pericmd 015: args

Now we move on to the most important property in a Rinci function metadata: args, which describes the arguments of the function. Since this property is rather complex, I will need several posts to cover the important points.

The value of this property is a hash with argument names as the keys and argument specification as values. Argument name must only contain letters, numbers, and underscores, like a Latin-only identifier. This makes it easy to ensure uniqueness of arguments, but with the consequence of making it more cumbersome to specify argument ordering (it’s a design choice and I picked hash). Argument specification is in turn a hash.

Argument specification

Like function metadata, argument specification allows the usual properties: summary, description. Other important properties are: req, pos, greedy, default, schema, tags. And, since we are in a CLI application series after all, these properties are also very much relevant: cmdline_aliases, cmdline_src.

req: (short for “required”). This property has a boolean value. If you set it to true, you are saying that the argument is required.

pos: (short for “position”). This property has a positive integer value and specifies the order of arguments (zero-based numbering). Why this is required will be explained in the examples later. In short, we allow function to accept hash/named arguments as well as positional arguments (the usual my ($arg1, $arg2, $arg3) = @_; stuff), so in the latter case we will need to mark which arguments are in which order.

greedy: This property accepts a boolean value and is used for slurping positional arguments and will also be explained via an example later.

default: Unsurprisingly, this property sets default values. This property accepts references (nested data structures), but for more complex defaults your function will need to do it itself in the function body.

schema: A restriction on the possible values of the argument. Currently should be a Sah schema, so a string or an array. Sah deserves its own blog posts, but I’ll try to explained it as we go along.

tags: A list of strings, for tagging each argument. Useful in several occassions, will be demo-ed in examples.

cmdline_aliases: Can be used to specify shortcut or extra options.

cmdline_src: Can be used to specify that we accept argument value from external sources other than command-line options, such as file or STDIN.

Hello, with arguments

Let’s return to our hello script example and add some arguments:

$SPEC{hello} = {
    v => 1.1,
    summary => 'Say hello',
    args => {
        name => {
            summary => 'Name',
            schema  => 'str*',
            cmdline_aliases => {n=>{}},
            pos => 0,
        },
        salutation => {
            summary => 'Salutation',
            schema  => 'str*',
            cmdline_aliases => {s=>{}},
        },
    },
};
sub hello {
    my %args = @_;

    my $name = $args{name};
    my $salutation = $args{salutation};

    my $msg = "Hello";
    $msg .= "," if $name || $salutation;
    $msg .= " $salutation" if $salutation;
    $msg .= " $name" if $name;
    $msg .= "!";

    [200, "OK", $msg];
}

The above example introduces two arguments: name and salutation. Now here’s how Perinci::CmdLine parses command-line options into function arguments: each argument will get its own command-line options with the same name. In this case, –name and –salutation. Both accept strings. Now each argument also specify an alias, n and s respectively. As to why we need an empty hash for each alias (as opposed to just saying: cmdline_aliases => [‘s’]) is because some complex aliases scenario is allowed, which will be illustrated with an example later.

The function accepts arguments as hash. If you want your function to accept positional arguments, you can: by specifying a property:

$SPEC{hello} = {
    v => 1.1,
    summary => 'Say hello',
    args => {
        name => {
            summary => 'Name',
            schema  => 'str*',
            cmdline_aliases => {n=>{}},
            pos => 0,
        },
        salutation => {
            summary => 'Salutation',
            schema  => 'str*',
            cmdline_aliases => {s=>{}},
            pos => 1,
        },
    },
    args_as => 'array',
};
sub hello {
    my ($name, $salutation) = @_;

    my $msg = "Hello";
    $msg .= ", " if $name || $salutation;
    $msg .= " $salutation" if $salutation;
    $msg .= " $name" if $name;
    $msg .= "!";

    [200, "OK", $msg];
}

You have to set property args_as to “array” (instead of the default “hash”), and you have to make sure that all arguments have positions (lines 9 as well as 15). Then you can accept arguments the way a typical Perl sub do (line 21).

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s