Tuesday, July 20, 2010

morning reading: Getopt::Long::Descriptive (GLD) and App::Cmd

"Getopt::Long::Descriptive - Getopt::Long, but simpler and more powerful"
given a descriptive getopt argument, returns a usage summary and an object containing set options.
I am a fan of this less is more approach of "simpler AND more powerful."
"App::Cmd - write command line apps with less suffering"
Simplify writing command line apps by breaking functionality into module(s) with a minimal runner script. Makes extending command line apps easy by adding additional sub-modules.
Uses Getopt::Long::Descriptive.

Have you ever asked "why do I have to document my command line options twice? once in the usage command and once in the Getopt statement?" I know I was asking just last week at the Thousand Oaks Perl Mongers meeting. If you don't ask, is it because you consider your Getopt command documentation? We discussed and compared various Getopt alternatives: Getopt::Long, Getopt::Euclid, Getop::Clade, etc.

One interesting solution is Getopt::Euclid. Euclid parses specially formatted pod commands to create the Getopt configuration. This is an awesome idea, but leaves me with two problems: 1) There is an extra step to create this parsing setup, and that means I can't test the exact code that my user will see. 2) it employs a source filter which freaks me out. Perhaps the source filter has been upgraded to use one of the PPI parsing modules instead, that would be less scary than the black magic happening in source filters.

GetOpt::Long::Descriptive (GLD) is built on Getopt::Long and takes a more verbose/descriptive input format. It outputs a usage command and an object containing options and values. Unlike Euclid, it doesn't read or create perldoc/POD.

I think adding a podweaver+Getopt::Long::Descriptive plugin would be interesting. Creating a nicely documented POD section during the dzil build step of my Dist::Zilla based modules would be a big win. I just browsed the code for Getopt::Long::Descriptive::Usage, and it looks like adding a weaver transform would be possible, if I could figure out how to extract the usage code from the module during the build step. This may be easier to visualize once I start investigating App::Cmd.

From the SYNOPSIS section:

use Getopt::Long::Descriptive;

my ($opt, $usage) = describe_options(
    'my-program %o ',
    [ 'server|s=s', "the server to connect to"                  ],
    [ 'port|p=i',   "the port to connect to", { default => 79 } ],
    [ 'verbose|v',  "print extra stuff"            ],
    [ 'help',       "print usage message and exit" ],
print($usage->text), exit if $opt->help;
Client->connect( $opt->server, $opt->port );
print "Connected!\n" if $opt->verbose;

...and running my-program --help will produce:

  my-program [-psv] [long options...] 
    -s --server     the server to connect to
    -p --port       the port to connect to
    -v --verbose    print extra stuff
    --help          print usage message and exit

I'm quite fond of how s|server became -s --server, showing both the long and short form of the arguments.

Go play with these modules and let me know if you start using them. Many thanks to their Authors for sharing their work on CPAN. You guys rock. I'm going to start using these modules and will report back when I have a better feel for them. This will likely become a future topic for the Los Angeles Perl Mongers (LAPM).


PPI documentation
Los Angeles Perl Mongers
Thousand Oaks Perl Mongers

No comments: