.\" Automatically generated by Pod::Man 4.09 (Pod::Simple 3.35) .\" .\" Standard preamble: .\" ======================================================================== .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp .. .de Vb \" Begin verbatim text .ft CW .nf .ne \\$1 .. .de Ve \" End verbatim text .ft R .fi .. .\" Set up some character translations and predefined strings. \*(-- will .\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left .\" double quote, and \*(R" will give a right double quote. \*(C+ will .\" give a nicer C++. Capital omega is used to do unbreakable dashes and .\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff, .\" nothing in troff, for use with C<>. .tr \(*W- .ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' .ie n \{\ . ds -- \(*W- . ds PI pi . if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch . if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch . ds L" "" . ds R" "" . ds C` "" . ds C' "" 'br\} .el\{\ . ds -- \|\(em\| . ds PI \(*p . ds L" `` . ds R" '' . ds C` . ds C' 'br\} .\" .\" Escape single quotes in literal strings from groff's Unicode transform. .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" .\" If the F register is >0, we'll generate index entries on stderr for .\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index .\" entries marked with X<> in POD. Of course, you'll have to process the .\" output yourself in some meaningful fashion. .\" .\" Avoid warning from groff about undefined register 'F'. .de IX .. .if !\nF .nr F 0 .if \nF>0 \{\ . de IX . tm Index:\\$1\t\\n%\t"\\$2" .. . if !\nF==2 \{\ . nr % 0 . nr F 2 . \} .\} .\" ======================================================================== .\" .IX Title "Perinci::CmdLine::Manual::Examples 3pm" .TH Perinci::CmdLine::Manual::Examples 3pm "2018-04-01" "perl v5.26.1" "User Contributed Perl Documentation" .\" For nroff, turn off justification. Always turn off hyphenation; it makes .\" way too many mistakes in technical documents. .if n .ad l .nh .SH "NAME" Perinci::CmdLine::Manual::Examples \- Collection of examples .SH "VERSION" .IX Header "VERSION" This document describes version 1.811.0 of Perinci::CmdLine::Manual::Examples (from Perl distribution Perinci-CmdLine), released on 2018\-03\-17. .SH "DESCRIPTION" .IX Header "DESCRIPTION" In the examples, Perinci::CmdLine::Any is used to show examples that are applicable to either Perinci::CmdLine::Classic or Perinci::CmdLine::Lite. For examples that are more appropriate or only applicable to specific implementation, the specific module will be used. .PP Perinci::CmdLine::Classic is hereby referred to as \f(CW\*(C`PC::Classic\*(C'\fR, while Perinci::CmdLine as \f(CW\*(C`PC::Lite\*(C'\fR. .SH "BASICS" .IX Header "BASICS" .SS "Simplest application" .IX Subsection "Simplest application" Since Perinci::CmdLine is function\- and metadata-based, you need to create at least one function and add some metadata for it. And you'll need to return the result as an enveloped response. The simplest is something like: .PP .Vb 4 \& #!perl \& use strict; \& use warnings; \& use Perinci::CmdLine::Any; \& \& our %SPEC; \& $SPEC{hello} = { \& v => 1.1, \& summary => \*(AqSay hello\*(Aq, \& }; \& sub hello { \& [200, "OK", "Hello, world!"]; \& } \& \& Perinci::CmdLine::Any\->new(url => \*(Aq/main/hello\*(Aq)\->run; .Ve .PP The \f(CW\*(C`url\*(C'\fR attribute specifies the location of the function in \s-1URL\s0 format (see Riap for more details on the syntax of \s-1URL\s0). It is basically a fully-qualified function name, with \f(CW\*(C`::\*(C'\fR replaced with \f(CW\*(C`/\*(C'\fR. With this URL-based syntax, it is possible to use a remote and/or non-Perl function for the \s-1CLI\s0 application. .PP The hash in \f(CW$SPEC{hello}\fR is called a Rinci metadata. The keys are called properties. There are two properties: \f(CW\*(C`v\*(C'\fR (which is always required with the value of 1.1 to specify version) and \f(CW\*(C`summary\*(C'\fR (which is actually optional, to describe the function). .PP In this example, the function and its metadata is put inside the same script. You can of course put them in a separate Perl module, and use them with e.g. \f(CW\*(C`url => \*(Aq/Your/Module/func\*(Aq\*(C'\fR. It is also worth mentioning that if you use the Perinci::CmdLine framework, your functions can also be used directly by other Perl modules/code since they are just regular Perl functions. .PP The function returns a 3\-element array containing HTTP-like status code, a status message, and the actual result. .PP If you save the above script as \f(CW\*(C`hello\*(C'\fR run it on the command-line: .PP .Vb 2 \& % ./hello \& Hello, world! .Ve .PP Yup, not very interesting. You get help message for free: .PP .Vb 2 \& % ./hello \-\-help \& % ./hello \-h .Ve .PP As well as some common options like \f(CW\*(C`\-\-format\*(C'\fR to return the result in a different format: .PP .Vb 2 \& % ./hello \-\-json \& [200,"OK","Hello, world!"] \& \& % ./hello \-\-format perl; # only in PC::Classic, not available in PC::Lite \& [200, "OK", "Hello, world!"] .Ve .SH "FUNCTION ARGUMENTS AND COMMAND-LINE OPTIONS" .IX Header "FUNCTION ARGUMENTS AND COMMAND-LINE OPTIONS" .SS "Basics" .IX Subsection "Basics" Function arguments map to command-line options. Example: .PP .Vb 4 \& #!perl \& use strict; \& use warnings; \& use Perinci::CmdLine::Any; \& \& our %SPEC; \& $SPEC{hello} = { \& v => 1.1, \& summary => \*(AqSay hello\*(Aq, \& args => { \& name => { \& summary => \*(AqName to say hello to\*(Aq, \& }, \& }, \& }; \& sub hello { \& my %args = @_; \& [200, "OK", "Hello, $args{name}!"]; \& } \& \& Perinci::CmdLine::Any\->new(url => \*(Aq/main/hello\*(Aq)\->run; .Ve .PP When you run this: .PP .Vb 2 \& % ./hello \-\-name Jimmy \& Hello, Jimmy! .Ve .PP If you run \f(CW\*(C`./hello \-\-help\*(C'\fR, the option is now mentioned as well in the help message. .PP Unknown arguments will result in an error: .PP .Vb 2 \& % ./hello \-\-gender m \& ERROR 400: Unknown option \*(Aq\-\-gender\*(Aq .Ve .PP To specify that an argument is required, add \f(CW\*(C`req\*(C'\fR property to the argument specification with a true value: .PP .Vb 6 \& args => { \& name => { \& summary => \*(AqName to say hello to\*(Aq, \& req => 1, \& }, \& }, .Ve .PP So when you run the app: .PP .Vb 2 \& % ./hello \& ERROR 400: Missing required argument \*(Aqname\*(Aq .Ve .PP To specify that an argument can also be specified via positional command-line \&\fIargument\fR instead of just command-line \fIoption\fR, add \f(CW\*(C`pos\*(C'\fR property to the argument specification: .PP .Vb 7 \& args => { \& name => { \& summary => \*(AqName to say hello to\*(Aq, \& req => 1, \& pos => 0, \& }, \& }, .Ve .PP So when you run the app you can specify: .PP .Vb 2 \& % ./hello \-\-name Jimmy \& Hello, Jimmy! .Ve .PP as well as: .PP .Vb 2 \& % ./hello Jimmy \& Hello, Jimmy! .Ve .PP Extra arguments will also result in an error: .PP .Vb 2 \& % ./hello Jimmy Gideon \& ERROR 400: Extra argument \*(AqGideon\*(Aq .Ve .SS "Argument schema (and more on text output formats)" .IX Subsection "Argument schema (and more on text output formats)" Following up from the previous example, here's another example with more arguments. Also note that I use PC::Classic since PC::Lite doesn't do schema validation. .PP .Vb 5 \& #!perl \& use 5.010; \& use strict; \& use warnings; \& use Perinci::CmdLine; \& \& our %SPEC; \& $SPEC{hello} = { \& v => 1.1, \& summary => \*(AqSay hello\*(Aq, \& args => { \& name => { \& summary => \*(AqName(s) to say hello to\*(Aq, \& schema => [array => {of => \*(Aqstr\*(Aq, min_len=>1}], \& req => 1, \& pos => 0, \& greedy => 1, \& }, \& gender => { \& summary => \*(AqThe gender of the name(s)\*(Aq, \& schema => [str => {in => [\*(Aqm\*(Aq,\*(Aqf\*(Aq]}], \& }, \& }, \& }; \& sub hello { \& my %args = @_; \& my $g = $args{gender}; \& my @res; \& for my $name (@{ $args{name} // [] }) { \& push @res, join("", \& "Hello, ", \& (!$g ? "" : $g eq \*(Aqm\*(Aq ? "Mr. " : "Mrs. "), \& $name, \*(Aq!\*(Aq, \& ); \& } \& [200, "OK", \e@res]; \& } \& Perinci::CmdLine\->new(url => \*(Aq/main/hello\*(Aq)\->run; .Ve .PP If you run this program: .PP .Vb 5 \& % ./hello Jimmy Sion Habil \& % ./hello \-\-name Jimmy \-\-name Sion \-\-name Habil \& Hello, Jimmy! \& Hello, Sion! \& Hello, Habil! \& \& % ./hello \-\-name\-json \*(Aq["Jimmy","Sion","Habil"]\*(Aq \-\-gender m \& Hello, Mr. Jimmy! \& Hello, Mr. Sion! \& Hello, Mr. Habil! .Ve .PP Some things you might notice. First, there is a \f(CW\*(C`schema\*(C'\fR property for each argument. \f(CW\*(C`name\*(C'\fR is specified as having a type of array of strings. To set this argument from the \s-1CLI,\s0 you can either specify multiple times (e.g. \f(CW\*(C`\-\-name NAME1 \-\-name NAME2 ...\*(C'\fR) or specify using \s-1JSON\s0 (i.e. \f(CW\*(C`\-\-name\-json JSONSTR\*(C'\fR). .PP Second, the \f(CW\*(C`name\*(C'\fR argument specifies the \f(CW\*(C`greedy\*(C'\fR property. This is used in conjunction with the \f(CW\*(C`pos\*(C'\fR property. It declares that the argument will gobble up command-line arguments from \f(CW\*(C`pos\*(C'\fR to the end. So you can also specify the values of the \f(CW\*(C`name\*(C'\fR argument with \f(CW\*(C`ARG1 ARG2 ...\*(C'\fR. .PP Third, if you specify value that does not validate, an error will be produced. .PP .Vb 2 \& % ./hello \-\-name\-json \*(Aq[]\*(Aq \& ERROR 400: Invalid value for argument \*(Aqname\*(Aq: Length must be at least 1 \& \& % ./hello \-\-name Jimmy \-\-name Sion \-\-name Habil \-\-gender x \& ERROR 400: Invalid value for argument \*(Aqgender\*(Aq: Must be one of ["m","f"] .Ve .PP See Data::Sah for more about the schema syntax. .PP Fourth, you return the result as a data structure (an array) instead of directly printing the result using \f(CW\*(C`print()\*(C'\fR or \f(CW\*(C`say()\*(C'\fR. This is done to make your function more reusable outside the context of \s-1CLI.\s0 PC::Classic will format your data structure nicely using Data::Format::Pretty. Your array will be printed as a multicolumn \s-1ANSI\s0 table by default, on interactive mode. If you pipe the output of your program, you will by default get a simpler text output. This can be chosen explicitly using the \f(CW\*(C`\-\-format\*(C'\fR common option. .PP .Vb 3 \& % ./hello Jimmy Sion Habil \-\-format text; # will output pretty or simple depending on whether interactive \& % ./hello Jimmy Sion Habil \-\-format text\-simple; # will still output simple table even when interactive \& % ./hello Jimmy Sion Habil \-\-format text\-pretty; # will still output pretty table even when piped .Ve .SS "Short option aliases" .IX Subsection "Short option aliases" To add short options, you can use the \f(CW\*(C`cmdline_aliases\*(C'\fR property in the argument specification: .PP .Vb 8 \& name => { \& ... \& cmdline_aliases => { n => {} }, \& }, \& gender => { \& ... \& cmdline_aliases => { g => {} }, \& }, .Ve .PP Now instead of: .PP .Vb 1 \& % ./hello \-\-name Jimmy \-\-name Sion \-\-name Habil \-\-gender m .Ve .PP you can also use: .PP .Vb 1 \& % ./hello \-n Jimmy \-n Sion \-n Habil \-g m .Ve .SS "More on command-line option aliases" .IX Subsection "More on command-line option aliases" You are not limited to one alias, or one letter: .PP .Vb 4 \& gender => { \& ... \& cmdline_aliases => { g => {}, sex => {} }, \& }, .Ve .PP Now all these are equivalent: .PP .Vb 3 \& % ./hello ... \-\-gender m \& % ./hello ... \-g m \& % ./hello ... \-\-sex m .Ve .PP Suppose you want to create an alias \f(CW\*(C`\-m\*(C'\fR to mean \f(CW\*(C`\-\-gender m\*(C'\fR and \f(CW\*(C`\-f\*(C'\fR to mean \f(CW\*(C`\-\-gender f\*(C'\fR instead: .PP .Vb 7 \& gender => { \& ... \& cmdline_aliases => { \& m => { schema=>\*(Aqbool\*(Aq, code => sub {my $args=shift; $args\->{gender} = \*(Aqm\*(Aq } }, \& f => { schema=>\*(Aqbool\*(Aq, code => sub {my $args=shift; $args\->{gender} = \*(Aqf\*(Aq } }, \& }, \& }, .Ve .PP Now you can say: .PP .Vb 3 \& % ./hello Jimmy Sion \-m \& Hello, Mr. Jimmy! \& Hello, Mr. Sion! \& \& % ./hello Nunung Misye \-f \& Hello, Mrs. Nunung! \& Hello, Mrs. Misye! .Ve .SS "My function has some cmdline_aliases or cmdline_src defined but I want to change it!" .IX Subsection "My function has some cmdline_aliases or cmdline_src defined but I want to change it!" For example, your \f(CW\*(C`f1\*(C'\fR function metadata might look like this: .PP .Vb 10 \& package Package::F1; \& our %SPEC; \& $SPEC{f1} = { \& v => 1.1, \& args => { \& foo => { \& cmdline_aliases => { f=> {} }, \& }, \& bar => { ... }, \& fee => { ... }, \& }, \& }; \& sub f1 { ... } \& 1; .Ve .PP And your command-line script \f(CW\*(C`f1\*(C'\fR: .PP .Vb 3 \& #!perl \& use Perinci::CmdLine; \& Perinci::CmdLine\->new(url => \*(Aq/Package/F1/f1\*(Aq)\->run; .Ve .PP Now you want to create a command-line script interface for this function, but with \f(CW\*(C`\-f\*(C'\fR as an alias for \f(CW\*(C`\-\-fee\*(C'\fR instead of \f(CW\*(C`\-\-foo\*(C'\fR. This is best done by modifying the metadata and creating a wrapper function to do this, e.g. your command-line script \f(CW\*(C`f1\*(C'\fR becomes: .PP .Vb 10 \& package main; \& use Perinci::CmdLine; \& use Package::F1; \& use Data::Clone; \& our %SPEC; \& $SPEC{f1} = clone $Package::F1::SPEC{f1}; \& delete $SPEC{f1}{args}{foo}{cmdline_aliases}; \& $SPEC{f1}{args}{fee}{cmdline_aliases} = {f=>{}}; \& *f1 = \e&Package::F1::f1; \& Perinci::CmdLine\->new(url => \*(Aq/main/f1\*(Aq)\->run; .Ve .PP This also demonstrates the convenience of having the metadata as a data structure: you can manipulate it however you want. There is also a convenient helper function available in Perinci::Sub::Util when you want to create a modified subroutine based on another: .PP .Vb 3 \& package main; \& use Perinci::CmdLine; \& use Perinci::Sub::Util qw(gen_modified_sub); \& \& gen_modified_sub( \& output_name => \*(Aqf1\*(Aq, \& base_name => \*(AqPackage::F1::f1\*(Aq, \& modify_args => { \& foo => sub { my $as = shift; delete $as\->{cmdline_aliases} }, \& fee => sub { my $as = shift; $as\->{cmdline_aliases} = {f=>{} }, \& }, \& ); \& Perinci::CmdLine\->new(url => \*(Aq/main/f1\*(Aq)\->run; .Ve .SS "Overriding common option" .IX Subsection "Overriding common option" Example: My function has argument named 'format', but it is blocked by common option '\-\-format'! .PP To add/remove/rename common options, see the documentation on \f(CW\*(C`common_opts\*(C'\fR attribute. In this case, you want: .PP .Vb 2 \& delete $cmd\->common_opts\->{format}; \& #delete $cmd\->common_opts\->{format_options}; # you might also want this .Ve .PP or perhaps rename it: .PP .Vb 2 \& $cmd\->common_opts\->{output_format} = $cmd\->common_opts\->{format}; \& delete $cmd\->common_opts\->{format}; .Ve .SH "INPUT" .IX Header "INPUT" .SS "Accepting input from \s-1STDIN\s0 (or files)" .IX Subsection "Accepting input from STDIN (or files)" If you specify 'cmdline_src' to 'stdin' to a 'str' argument, the argument's value will be retrieved from standard input if not specified. Example: .PP .Vb 10 \& use Perinci::CmdLine; \& $SPEC{cmd} = { \& v => 1.1, \& args => { \& arg => { \& schema => \*(Aqstr*\*(Aq, \& cmdline_src => \*(Aqstdin\*(Aq, \& }, \& }, \& }; \& sub cmd { \& my %args = @_; \& [200, "OK", "arg is \*(Aq$args{arg}\*(Aq"]; \& } \& Perinci::CmdLine\->new(url=>\*(Aq/main/cmd\*(Aq)\->run; .Ve .PP When run from command line: .PP .Vb 4 \& % cat file.txt \& This is content of file.txt \& % cat file.txt | cmd \& arg is \*(AqThis is content of file.txt\*(Aq .Ve .PP If your function argument is an array, array of lines will be provided to your function. .PP Note that this will glob the whole content of input into memory. If you want streaming, see the next section. .SS "Accept streaming input" .IX Subsection "Accept streaming input" To accept streaming input, you specify one or more of your arguments as \f(CW\*(C`stream=>1\*(C'\fR. Also, these arguments need to specify their source either from file, \s-1STDIN,\s0 or STDIN/files, by setting \f(CW\*(C`cmdline_src => file|stdin|stdin_or_files\*(C'\fR, because otherwise, just receiving value from command-line option like \f(CW\*(C`\-\-arg val\*(C'\fR is not very interesting :\-). You will receive your function argument as a coderef which you can call repeatedly until input is exhausted (at the point of which the coderef will return undef). .PP .Vb 10 \& $SPEC{perl_wc} = { \& v => 1.1, \& args => { \& input => { \& schema => \*(Aqstr*\*(Aq, \& stream => 1, \& cmdline_src => \*(Aqstdin_or_files\*(Aq, \& }, \& }, \& }; \& sub perl_wc { \& my %args = @_; \& my $input = $args{input}; \& \& my $chars = 0; \& my $words = 0; \& my $lines = 0; \& while (my $line = $input\->()) { \& $lines++; \& $chars += length($line); \& chomp $line; \& my @w = split /[ \et]+/o, $line; $words += @w; \& } \& \& [200, "OK", {chars=>$chars, words=>$words, lines=>$lines}]; \& } .Ve .PP When run: .PP .Vb 8 \& % ls \-l | perl_wc \& +\-\-\-\-\-\-\-+\-\-\-\-\-\-\-+ \& | key | value | \& +\-\-\-\-\-\-\-+\-\-\-\-\-\-\-+ \& | chars | 1995 | \& | lines | 42 | \& | words | 61 | \& +\-\-\-\-\-\-\-+\-\-\-\-\-\-\-+ .Ve .PP Note: by default you will get string/text input line-by-line, and for binary (\f(CW\*(C`buf\*(C'\fR) per\-64k. This will be configurable in the future. .PP If argument type is not simple (e.g. an array or hash), then \s-1JSON\s0 stream input will be assumed. This means, each line of input will be parsed as \s-1JSON.\s0 .SH "OUTPUT" .IX Header "OUTPUT" .SS "Default output format" .IX Subsection "Default output format" \&\s-1TODO\s0 .SS "Removing borders" .IX Subsection "Removing borders" By default, the text format produces bordered tables in interactive mode, e.g. if you have this program: .PP .Vb 6 \& $SPEC{foo} = {v=>1.1}; \& sub foo { \& [200, "OK", [[1,2], [3,4], [5,6]]]; \& } \& use Perinci::CmdLine::Any; \& Perinci::CmdLine::Any\->new(url => \*(Aq/main/foo\*(Aq)\->run; .Ve .PP and you run it, you will have: .PP .Vb 6 \& % foo \& +\-\-\-+\-\-\-+ \& | 1 | 2 | \& | 3 | 4 | \& | 5 | 6 | \& +\-\-\-+\-\-\-+ .Ve .PP and if you use \f(CW\*(C`\-\-format text\-simple\*(C'\fR, only then it will become a tab-separated format: .PP .Vb 4 \& % foo \-\-format text\-simple \& 1 2 \& 3 4 \& 5 6 .Ve .PP But if you don't like this formatting and want to default to simpler formatting by default, you can add \f(CW\*(C`cmdline.default_format\*(C'\fR attribute to your function metadata: .PP .Vb 1 \& $SPEC{foo} = {v=>1.1, \*(Aqcmdline.default_format\*(Aq => \*(Aqtext\-simple\*(Aq}; .Ve .PP Using this attribute, you can also default to \s-1JSON,\s0 and so on if you want. .PP You can also do this on a per-result basis, by adding \f(CW\*(C`cmdline.default_format\*(C'\fR attribute in your result metadata, e.g.: .PP .Vb 3 \& sub foo { \& [200, "OK", [[1,2], [3,4], [5,6]], {\*(Aqcmdline.default_format\*(Aq=>\*(Aqtext\-simple\*(Aq}]; \& } .Ve .SS "Streaming output" .IX Subsection "Streaming output" To produce streaming output, set \f(CW\*(C`stream=>1\*(C'\fR in \f(CW\*(C`result\*(C'\fR spec in function metadata. Then in your function, return a subroutine reference that will allow caller to read data from. .PP .Vb 10 \& $SPEC{nat} = { \& v => 1.1, \& summary => \*(AqGenerate an infinite sequence of natural numbers\*(Aq, \& args => {}, \& result => { \& stream => 1, \& schema => \*(Aqstr*\*(Aq, \& }, \& }; \& sub nat { \& my $n = 1; \& [200, "OK", sub { $n++ }]; \& } .Ve .PP If result type is not simple (e.g. an array or hash), then each record will be encoded into \s-1JSON,\s0 to produce \s-1JSON\s0 stream. .PP If you want to return a file content as a stream (instead of slurping the whole content into memory): .PP .Vb 12 \& $SPEC{catfile} = { \& v => 1.1, \& summary => "Display file contents", \& args => { file => { schema => \*(Aqfilename*\*(Aq, req=>1, pos=>0 } }, \& result => { stream => 1, schema => \*(Aqstr*\*(Aq }, \& }; \& sub catfile { \& my %args = @_; \& my $file = $args{file}; \& open my $fh, "<", $file or return [500, "Can\*(Aqt open file \*(Aq$file\*(Aq: $!"]; \& [200, "OK", sub { scalar(<$fh>) }]; \& } .Ve .SS "Adding support for new format" .IX Subsection "Adding support for new format" \&\s-1TODO\s0 .SS "Pager" .IX Subsection "Pager" \&\s-1TODO\s0 .SH "CONFIGURATION" .IX Header "CONFIGURATION" .SS "Basics" .IX Subsection "Basics" In the function-centric world of Perinci::CmdLine, configuration is just another way to supply values to function arguments (before being potentially overridden by command-line arguments). Configuration files are written in \s-1IOD\s0 format, which is basically \*(L"\s-1INI\s0 with extra features\*(R". By default, configuration files are searched in \f(CW\*(C`/etc\*(C'\fR and then your home directory, with the name of \&\fIprogram_name\fR + \f(CW\*(C`.conf\*(C'\fR. So if you have: .PP .Vb 3 \& # ~/prog.conf \& foo=1 \& bar=2 .Ve .PP and: .PP .Vb 10 \& # prog \& #!perl \& use Perinci::CmdLine::Any; \& $SPEC{prog} = { \& v => 1.1, \& args => { \& foo => {}, \& bar => {}, \& }, \& }; \& sub prog { \& my %args = @_; \& [200, "OK", "foo is $args{foo}, while bar is $args{bar}"]; \& } \& Perinci::CmdLine::Any\->new(url=>\*(Aq/main/prog\*(Aq)\->run; .Ve .PP When you run: .PP .Vb 1 \& % prog .Ve .PP you'll get: .PP .Vb 1 \& foo is 1, while bar is 2 .Ve .PP Multiple configuration files will be merged, so if you have: .PP .Vb 3 \& # /etc/prog.conf \& foo=1 \& bar=2 \& \& # ~/prog.conf \& foo=10 .Ve .PP you'll get: .PP .Vb 1 \& foo is 10, while bar is 2 .Ve .SS "Configuration profiles" .IX Subsection "Configuration profiles" Configuration file can store more than one set of arguments, through specially named sections, called profiles: .PP .Vb 3 \& # ~/prog.conf \& foo=1 \& bar=2 \& \& [profile=p1] \& foo=21 \& bar=22 \& \& [profile=p2] \& foo=31 \& bar=32 .Ve .PP Running the program: .PP .Vb 6 \& % prog \& foo is 1, while bar is 2 \& % prog \-\-config\-profile p1 \& foo is 21, while bar is 22 \& % prog \-\-config\-profile p2 \& foo is 31, while bar is 32 .Ve .SS "Configuration with subcommands" .IX Subsection "Configuration with subcommands" \&\s-1TODO\s0 .SS "Ignoring configuration files" .IX Subsection "Ignoring configuration files" If you don't want to use any configuration files, you can use: .PP .Vb 1 \& % prog \-\-noconfig ... .Ve .SS "\s-1DEBUGGING\s0" .IX Subsection "DEBUGGING" \&\s-1TODO\s0 .SS "\s-1REMOTE FUNCTION\s0" .IX Subsection "REMOTE FUNCTION" .SH "SHELL COMPLETION" .IX Header "SHELL COMPLETION" .SS "Custom completion" .IX Subsection "Custom completion" By default, Perinci::Sub::Complete's \f(CW\*(C`complete_arg_val()\*(C'\fR can employ some heuristics to complete argument values, e.g. from the \f(CW\*(C`in\*(C'\fR clause or \f(CW\*(C`max\*(C'\fR and \&\f(CW\*(C`min\*(C'\fR: .PP .Vb 9 \& $SPEC{set_ticket_status} = { \& v => 1.1, \& args => { \& ticket_id => { ... }, \& status => { \& schema => [\*(Aqstr*\*(Aq, in => [qw/new open stalled resolved rejected/], \& }, \& }, \& } .Ve .PP But if you want to supply custom completion, the Rinci::function specification allows specifying a \f(CW\*(C`completion\*(C'\fR property for your argument, for example: .PP .Vb 10 \& use Complete::Util qw(complete_array_elem); \& $SPEC{del_user} = { \& v => 1.1, \& args => { \& username => { \& schema => \*(Aqstr*\*(Aq, \& req => 1, \& pos => 0, \& completion => sub { \& my %args = @_; \& \& # get list of users from database or whatever \& my @users = ...; \& complete_array_elem(array=>\e@users, word=>$args{word}); \& }, \& }, \& ... \& }, \& }; .Ve .PP You can use completion in your command-line program: .PP .Vb 2 \& % del\-user \-\-username \& % del\-user ; # since the \*(Aqusername\*(Aq argument has pos=0 .Ve .SS "My custom completion does not work, how do I debug it?" .IX Subsection "My custom completion does not work, how do I debug it?" Completion works by the shell invoking our (the same) program with \f(CW\*(C`COMP_LINE\*(C'\fR and \f(CW\*(C`COMP_POINT\*(C'\fR environment variables. You can do something like this to see debugging information: .PP .Vb 1 \& % COMP_LINE=\*(Aqmyprog \-\-arg x\*(Aq COMP_POINT=13 PERL5OPT=\-MLog::ger::App TRACE=1 myprog \-\-arg x .Ve .PP You can also use the testcomp utility (included in the App::CompleteUtils distribution) to help debug your custom completion: .PP .Vb 1 \& % testcomp myprog \-\-arg x^ .Ve .PP Place the \f(CW\*(C`^\*(C'\fR caret character to simulate the position of the cursor when tab-completion is attempted. .SH "I18N" .IX Header "I18N" .SH "OTHERS" .IX Header "OTHERS" .SS "Modifying common options" .IX Subsection "Modifying common options" .SS "Customizing help message" .IX Subsection "Customizing help message" .SS "Dealing with binary data" .IX Subsection "Dealing with binary data" .SS "(Client) (Server) Dealing with binary data" .IX Subsection "(Client) (Server) Dealing with binary data" The choice as \s-1JSON\s0 as the network transport protocol for Riap (because it is the lowest common denominator across languages like JavaScript, \s-1PHP,\s0 Python, Ruby, Perl) makes dealing with binary data requires an extra step or two. The Perinci::CmdLine framework are equipped with some features to make this simpler and more convenient. .PP First, to make a function that accepts binary data (in its arguments), you need to specify the argument type as \f(CW\*(C`buf\*(C'\fR. To return binary data as result, you need to specify \f(CW\*(C`result\*(C'\fR's schema type as \f(CW\*(C`buf\*(C'\fR. Example: .PP .Vb 10 \& package MyLib; \& our %SPEC; \& $SPEC{gzip} = { \& v => 1.1, \& summary => \*(AqGzip some data\*(Aq, \& args => { \& data => { \& summary => \*(AqData to compress\*(Aq, \& schema => \*(Aqbuf*\*(Aq, \& req => 1, \& }, \& }, \& }; \& sub gzip { \& require IO::Compress::Gzip; \& \& my %args = @_; \& my $compressed; \& IO::Compress::Gzip::gzip($args{data} => $compressed) \& or return [500, "Compression failed"]; \& [200, "OK", $compressed]; \& } .Ve .PP If you use this function in Perinci::CmdLine, you will get the command-line option \f(CW\*(C`\-\-data\-base64\*(C'\fR in addition to the usual \f(CW\*(C`\-\-data\*(C'\fR. With \&\f(CW\*(C`\-\-data\-base64\*(C'\fR, you can specify binary data including \s-1NUL\s0 bytes from the command-line. .PP If you specify the argument as accepting data from stdin or files like this: .PP .Vb 8 \& args => { \& data => { \& summary => \*(AqData to compress\*(Aq, \& schema => \*(Aqbuf*\*(Aq, \& req => 1, \& cmdline_src => \*(Aqstdin_or_files\*(Aq, \& }, \& }, .Ve .PP you can pass binary data, e.g.: .PP .Vb 1 \& % yourprog < /some/bindata .Ve .PP Perinci::CmdLine will take care of encoding this data to network server when you specify \f(CW\*(C`riap_version\*(C'\fR attribute to 1.2. So this process is transparent to you. .PP When outputting binary result, in the \f(CW\*(C`text\*(C'\fR output formats, Perinci::CmdLine will also print the binary result from server as-is without any newline added. So you can pipe binary data to files/processes unmodified. .SH "SUBCOMMANDS" .IX Header "SUBCOMMANDS" .SS "Default subcommand" .IX Subsection "Default subcommand" A default subcommand can be defined. This subcommand is selected without user specifying it the first command-line argument. A real-world example of this is from File::Trash::Undoable. The \fBtrash-u\fR command is by default selecting the \f(CW\*(C`trash\*(C'\fR subcommand: .PP .Vb 1 \& % trash\-u file1 file2 .Ve .PP is equivalent to: .PP .Vb 1 \& % trash\-u \-\-cmd trash file1 file2 .Ve .PP To select another subcommand other than \f(CW\*(C`trash\*(C'\fR, an explicit option is needed: .PP .Vb 2 \& % trash\-u \-\-list\-contents ; # select the list_contents subcommand \& % trash\-u \-\-cmd empty ; # select the empty subcommand .Ve .PP This is done via something like: .PP .Vb 8 \& Perinci::CmdLine\->new( \& subcommands => { \& trash => { url=>... }, \& empty => { url=>... }, \& list_contents => { url=>... }, \& }, \& default_subcommand => \*(Aqtrash\*(Aq, \& )\->run; .Ve .SS "Default subcommand (override via first command-line argument)" .IX Subsection "Default subcommand (override via first command-line argument)" There is also a choice to specify a default subcommand which is overrideable via first command-line argument. A real-world example of this is from App::GitUtils. If the \fBgu\fR command is specified without any argument: .PP .Vb 1 \& % gu .Ve .PP then it is equivalent to: .PP .Vb 1 \& % gu info .Ve .PP but user can specify other subcommands: .PP .Vb 1 \& % gu post\-commit .Ve .PP This is accomplished by setting: .PP .Vb 10 \& Perinci::CmdLine::Any\->new( \& subcommands => { \& info => {...}, \& run_hooks => {...}, \& post_commit => {...}, \& ... \& }, \& default_subcommand => \*(Aqinfo\*(Aq, \& get_subcommand_from_arg => 2, \& )\->run; .Ve .SS "Dynamic list of subcommands" .IX Subsection "Dynamic list of subcommands" \&\s-1TODO\s0 .SH "HOMEPAGE" .IX Header "HOMEPAGE" Please visit the project's homepage at . .SH "SOURCE" .IX Header "SOURCE" Source repository is at . .SH "BUGS" .IX Header "BUGS" Please report any bugs or feature requests on the bugtracker website .PP When submitting a bug or request, please include a test-file or a patch to an existing test-file that illustrates the bug or desired feature. .SH "SEE ALSO" .IX Header "SEE ALSO" Perinci::CmdLine::Manual .PP Perinci::Examples .SH "AUTHOR" .IX Header "AUTHOR" perlancar .SH "COPYRIGHT AND LICENSE" .IX Header "COPYRIGHT AND LICENSE" This software is copyright (c) 2018, 2017, 2016, 2015 by perlancar@cpan.org. .PP This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself.