NAME
Sub::Spec::CmdLine - Access Perl subs via command line
VERSION
version 0.37
SYNOPSIS
In your module:
package YourModule;
our %SPEC;
$SPEC{foo} = {
summary => 'Foo!',
args => {
arg => ...,
arg2 => ...
},
...
};
sub foo {
...
}
...
1;
In your script:
#!/usr/bin/perl
use Sub::Spec::CmdLine qw(run);
run(module=>'YourModule', sub=>'foo');
In the command-line:
% script.pl --help
% script.pl --arg value --arg2 '[an, array, in, yaml, syntax]' ...
For running multiple subs, in your script:
use Sub::Spec::CmdLine qw(run);
run(subcommands => {
foo => { module=>'YourModule', sub=>'foo'},
bar => { module=>'YourModule', sub=>'bar'},
...
});
In the command-line:
% script.pl --help
% script.pl --list
% script.pl foo --help
% script.pl foo --arg value --arg2 ...
% script.pl bar --blah ...
DESCRIPTION
NOTICE: This module and the Sub::Spec standard is deprecated as of Jan 2012. Rinci is the new specification to replace Sub::Spec, it is about 95% compatible with Sub::Spec, but corrects a few issues and is more generic. Perinci::*
is the Perl implementation for Rinci and many of its modules can handle existing Sub::Spec sub specs. See Perinci::CmdLine which supersedes this module.
This module utilize sub specs (as defined by Sub::Spec) to let your subs be accessible from the command-line.
This can be used to create a command-line application easily. What you'll get:
Command-line parsing (currently using Getopt::Long, with some tweaks)
Help message (utilizing information from sub specs)
Tab completion for bash
This module uses Log::Any logging framework. Use something like Log::Any::App, etc to see more logging statements for debugging.
Note: If you use this module, make sure that your sub does not return status code above 555, because OS exit code is set to $code-300.
FUNCTIONS
None of the functions are exported by default, but they are exportable.
format_result($sub_res[, \%opts]) => TEXT
Format result from sub into various formats
Options:
format => FORMAT (optional, default 'text')
Format can be 'text' (pretty text or nonpretty text), 'pretty' (pretty text, generated by Data::Format::Pretty::Console under interactive=1), 'nopretty' (also generated by Data::Format::Pretty::Console under interactive=0), 'yaml', 'json', 'php' (generated by PHP::Serialization's serialize()).
default_success_message => STR (optional, default none)
If output format is text ('text', 'pretty', 'nopretty') and result code is 200 and there is no data returned, this default_success_message is used. Example: 'Success'.
run(%args)
Run subroutine(s) from the command line, which essentially comprises these steps:
Parse command-line options in @ARGV (using Sub::Spec::GetArgs::Argv)
Also, display help using Sub::Spec::To::Text::Usage::spec_to_usage() if given '--help' or '-h' or '-?'.
See Sub::Spec::GetArgs::Argv for details on parsing.
Call sub
Format the return value from sub (using format_result())
Exit with appropriate exit code
0 if 200, or CODE-300.
Arguments (* denotes required arguments):
summary => STR
Used when displaying help message or version.
module => STR
Currently this must be supplied if you want --version to work, even if you use subcommands. --version gets $VERSION from the main module. Not required if you specify 'spec'.
sub => STR
Required if you only want to execute one subroutine. Alternatively you can provide multiple subroutines from which the user can choose (see 'subcommands').
spec => HASH | CODEREF
Instead of trying to look for the spec using module and sub, use the supplied spec.
help => STRING | CODEREF
Instead of generating help using spec_to_usage() from the spec, use the supplied help message (or help code, which is expected to return help text).
subcommands => {NAME => {ARGUMENT=>...}, ...} | CODEREF
module and sub should be specified if you only have one sub to run. If you have several subs to run, assign each of them to a subcommand, e.g.:
summary => 'Maintain a directory containing git repos', module => 'Git::Bunch', subcommands => { check => { }, backup => { }, # module defaults to main module argument, sync => { }, # sub defaults to the same name as subcommand name },
Available argument for each subcommand: 'module' (defaults to main module argument), 'sub' (defaults to subcommand name), 'summary', 'help', 'category' (for arrangement when listing commands), 'run', 'complete_arg', 'complete_args'.
Subcommand argument can be a code reference, in which case it will be called with
%args
containing: 'name' (subcommand name), 'args' (arguments to run()). The code is expected to return structure for argument with specified name, or, when name is not specified, a hashref containing all subcommand arguments.run => CODEREF
Instead of running command by invoking subroutine specified by module and sub, run this code instead. Code is expected to return a response structure ([CODE, MESSAGE, DATA]).
exit => BOOL (default 1)
If set to 0, instead of exiting with exit(), return the exit code instead.
load => BOOL (default 1)
If set to 0, do not try to load (require()) the module.
allow_unknown_args => BOOL (default 0)
If set to 1, unknown command-line argument will not result in fatal error.
complete_arg => {ARGNAME => CODEREF, ...}
Under bash completion, when completing argument value, you can supply a code to provide its completion. Code will be called with %args containing: word, words, arg, args.
complete_args => CODEREF
Under bash completion, when completing argument value, you can supply a code to provide its completion. Code will be called with %args containing: word, words, arg, args.
custom_completer => CODEREF
To be passed to Sub::Spec::BashComplete's bash_complete_spec_arg(). This can be used e.g. to change bash completion code (e.g. calling bash_complete_spec_arg() recursively) based on context.
dash_to_underscore => BOOL (optional, default 0)
If set to 1, subcommand like a-b-c will be converted to a_b_c. This is for convenience when typing in command line.
undo => BOOL (optional, default 0)
If set to 1, --undo and --undo-dir will be added to command-line options. --undo is used to perform undo: -undo and -undo_data will be passed to subroutine, an error will be thrown if subroutine does not have 'undo' features. --undo-dir is used to set location of undo data (default ~/.undo; undo directory will be created if not exists; each subroutine will have its own subdir here).
run() can also perform completion for bash (if Sub::Spec::BashComplete is available). To get bash completion for your perlprog, just type this in bash:
% complete -C /path/to/perlprog perlprog
You can add that line in bash startup file (~/.bashrc, /etc/bash.bashrc, etc).
FAQ
How does Sub::Spec::CmdLine compare with other CLI-app frameworks?
Differences: Sub::Spec::CmdLine is part of a more general subroutine metadata framework. Aside from a command-line app, your sub spec is also usable for other stuffs, like creating REST API's, remote subroutines, or documentation. Sub::Spec::CmdLine is not OO and does not offer plugins (as of now).
Pros: App::Cmd and App::Rad currently does not offer bash completion feature. Sub::Spec::CmdLine offers passing arguments as YAML.
Cons: inadequate documentation/tutorial, no configuration file support yet (coming soon).
Why is nonscalar arguments parsed as YAML instead of JSON/etc?
I think YAML is nicer in command-line because quotes are optional in a few places:
$ cmd --array '[a, b, c]' --hash '{foo: bar}'
versus:
$ cmd --array '["a", "b", "c"]' --hash '{"foo": "bar"}'
Though YAML requires spaces in some places where JSON does not. A flag to parse as JSON can be added upon request.
SEE ALSO
AUTHOR
Steven Haryanto <stevenharyanto@gmail.com>
COPYRIGHT AND LICENSE
This software is copyright (c) 2012 by Steven Haryanto.
This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself.