package Perinci::CmdLine::Easy; use 5.010; use strict; use warnings; use Perinci::CmdLine; require Exporter; our @ISA = qw(Exporter); our @EXPORT_OK = qw(run_cmdline_app); our $VERSION = '0.50'; # VERSION our %SPEC; $SPEC{run_cmdline_app} = { v => 1.1, summary => "A simple interface to run a subroutine as command-line app", args => { sub => { req => 1, summary => "Coderef or subroutine name", }, summary => { schema => "str*", }, description => { schema => "str*", }, argv => { schema => ["array*" => {of=>"str*"}], default => [], summary => "List of arguments", description => <<'_', Each argument is NAME, NAME* (marking required argument), or NAME+ (marking greedy argument, where the rest of command-line arguments will be fed into this array). _ }, }, result_naked => 1, }; sub run_cmdline_app { my %args = @_; my $meta = { v => 1.1, summary => $args{summary}, description => $args{description}, result_naked => 1, args_as => "array", args => {}, }; my $i = 0; for my $arg (@{ $args{argv} // []}) { my $req = $arg =~ s/\*$//; my $greedy = $arg =~ s/\+$//; $meta->{args}{$arg} = { pos => $i, req => $req, greedy => $greedy, summary => "Argument #$i", schema => "str*", }; $i++; } my @caller = caller(1); no strict 'refs'; my $sub = $args{sub}; my $url; if (!$sub) { die "Please supply sub\n"; } elsif (ref($sub) eq 'CODE') { my $name = "$sub"; $name =~ s/[^A-Za-z0-9]+//g; $main::SPEC{$name} = $meta; *{ "main::$name" } = $sub; $url = "/main/$name"; } else { my ($pkg, $local) = $sub =~ /\A(.+::)?(.+)\z/; $pkg = $caller[0] . '::' unless $pkg; ${ $pkg . "SPEC" }{$local} = $meta; $url = $pkg; $url =~ s!::!/!g; $url = "/$url"; } Perinci::CmdLine->new(url => $url)->run; } 1; # ABSTRACT: A simple interface to run a subroutine as command-line app __END__ =pod =head1 NAME Perinci::CmdLine::Easy - A simple interface to run a subroutine as command-line app =head1 VERSION version 0.50 =head1 SYNOPSIS In your command-line script (e.g. named list-cpan-dists): use JSON qw(decode_json); use LWP::Simple; use Perinci::CmdLine::Easy qw(run_cmdline_app); run_cmdline_app( summary => "List CPAN distributions that belong to an author", sub => sub { my $cpanid = shift or die "Please supply CPAN ID\n"; my $res = get "http://api.metacpan.org/v0/release/_search?q=author:". uc($cpanid)."%20AND%20status:latest&fields=name&size=5000" or die "Can't query MetaCPAN"; $res = $json->decode($res); die "MetaCPAN timed out\n" if $res->{timed_out}; my @dists; for my $hit (@{ $res->{hits}{hits} }) { my $dist = $hit->{fields}{name}; $dist =~ s/-\d.+//; push @dists, $dist; } \@dists; }, argv => [qw/cpanid*/], ); To run this program: % list-cpan-dists --help ;# display help message % LANG=id_ID list-cpan-dists --help ;# display help message in Indonesian % list-cpan-dists SHARYANTO To do bash tab completion: % complete -C list-cpan-dists list-cpan-dists % list-cpan-dists <tab> ;# completes to --help, --version, --cpanid, etc % list-cpan-dists --c<tab> ;# completes to --cpanid =head1 DESCRIPTION Perinci::CmdLine::Easy provides an easier alternative to L<Perinci::CmdLine>. You do not need to know any L<Rinci> or L<Riap> concepts, or provide your own metadata. Just supply the subroutine, summary, list of arguments, and you're good to go. Of course, if you need more customization, there's Perinci::CmdLine. What you'll get: =over 4 =item * Command-line options parsing =item * Help message (supports translation) =item * Tab completion for bash =item * Formatting of output (supports complex data structure) =item * Logging =back =head1 SEE ALSO L<Perinci::CmdLine> =head1 AUTHOR Steven Haryanto <stevenharyanto@gmail.com> =head1 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. =cut