pericmd 012: Rinci metadata

The previous post has established what Rinci metadata is and what it is for. We’ll now go through examples of building a metadata from scratch and see its use in a CLI application.

A Rinci metadata is a normal hash structure. In Perl, we put it in package global variable %SPEC under the key of function name. Example:

our %SPEC;
$SPEC{hello} = {
    v => 1.1,
    summary => 'Say hello',
};

The only required property (that’s what we call the key in a metadata hash) is v (short for version).  This property is required because there has been a previous version of the metadata hash, the 1.0 version, which is rather incompatible with the current one, 1.1. If v is not specified, it is assumed to be 1.0, so we always need to specify it to mean 1.1.

Another property you see above is summary. In a CLI program, this will show up as the abstract (in POD or help message). Let’s write a full CLI program and try it out right now:

#!/usr/bin/env perl

use 5.010;
use strict;
use warnings;
use Perinci::CmdLine::Any;

our %SPEC;
$SPEC{hello} = {
    v => 1.1,
    summary => 'Say hello',
};
sub hello {
    [200, "OK", "Hello, world!"];
}

Perinci::CmdLine::Any->new(url=>'/main/hello')->run;

Save it as hello and then run it from the shell:

% ./hello
Hello, world! 

% ./hello --help
hello - Say hello

Usage:
  hello --help (or -h, -?)
  hello --version (or -v)
  hello [options]
Options:
  --config-path=s     Set path to configuration file
  --config-profile=s  Set configuration profile to use
  --format=s          Choose output format, e.g. json, text
  --help, -h, -?      Display this help message
  --json              Set output format to json
  --naked-res         When outputing as JSON, strip result envelope
  --no-config         Do not use any configuration file
  --version, -v       

If you want to see what the generated POD would look like, you’ll need to install Dist::Zilla and some plugins, and create a proper distribution structure. Let’s try that now too:

% cpanm -n Dist::Zilla Dist::Zilla::Plugin::PodWeaver \
    Dist::Zilla::Plugin::Rinci::AbstractFromMeta \
    Dist::Zilla::Plugin::PodnameFromFilename Pod::Weaver::Plugin::Rinci

Create a directory named App-hello, cd into it, and put the script under bin/ and add/change some bits:

#!perl

use 5.010;
use strict;
use warnings;
use Perinci::CmdLine::Any;

our %SPEC;
$SPEC{hello} = {
    v => 1.1,
    summary => 'Say hello',
};
sub hello {
    [200, "OK", "Hello, world!"];
}

Perinci::CmdLine::Any->new(url=>'/main/hello')->run;

# ABSTRACT:
# PODNAME:

Also create dist.ini:

name=App-hello
version=0.01

[Rinci::AbstractFromMeta]
[PodnameFromFilename]
[@Classic]
[PodWeaver]
config_plugin=-Rinci

Lastly, also create an empty module lib/App/hello.pm containing just:

package App::hello;
1;
# ABSTRACT: Say hello

(Note: there’s a repetition of abstract “Say hello”, this is because we put the metadata in the script itself and not the module. Normally for more reusability we’ll put the Rinci metadata and function body in the module.)

Now, build the distribution:

% dzil build

After the build, you should see a directory called App-hello-0.01 as well as a tarball file App-hello-0.01.tar.gz. This is the result of the build. If you see the contents of App-hello-0.01/bin/hello, at the end you will see:

# ABSTRACT: Say hello
# PODNAME: hello

__END__

=pod

=head1 NAME

hello - Say hello

=head1 SYNOPSIS

Usage:

 % hello [options]

=head1 OPTIONS

C<*> marks required options.

=over

=item B<--config-path>=I<s>

Set path to configuration file.

Can be specified multiple times.

=item B<--config-profile>=I<s>

Set configuration profile to use.

=item B<--format>=I<s>

Choose output format, e.g. json, text.

=item B<--help>, B<-h>, B<-?>

Display this help message.

=item B<--json>

Set output format to json.

=item B<--naked-res>

When outputing as JSON, strip result envelope.

By default, when outputing as JSON, the full enveloped result is returned, e.g.:

    [200,"OK",[1,2,3],{"func.extra"=>4}]

The reason is so you can get the status (1st element), status message (2nd
element) as well as result metadata/extra result (4th element) instead of just
the result (3rd element). However, sometimes you want just the result, e.g. when
you want to pipe the result for more post-processing. In this case you can use
`--naked-res` so you just get:

    [1,2,3]


=item B<--no-config>

Do not use any configuration file.

=item B<--version>, B<-v>

=back

=head1 ENVIRONMENT

HELLO_OPT

=head1 FILES

~/hello.conf

/etc/hello.conf

=cut
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