=head1 NAME

OptArgs - integrated argument and option processing

=head1 VERSION

0.0.1 Development release.

=head1 SYNOPSIS

    #!/usr/bin/env perl
    use OptArgs;

    opt quiet => (
        isa     => 'Bool',
        alias   => 'q',
        comment => 'output nothing while working',
    );

    arg item => (
        isa      => 'Str',
        required => 1,
        comment  => 'the item to paint',
    );

    my $ref = optargs;

    print "Painting $ref->{item}\n" unless $ref->{quiet};

=head1 DESCRIPTION

B<OptArgs> processes Perl script I<options> and I<arguments>.  This is
in contrast with modules in the Getopt::* namespace, which deal with
options only.  The following model is assumed by B<OptArgs> for
command-line applications:

=over

=item Command

The program name - i.e. the filename be executed by the shell.

=item Options

Options are parameters that affect the way a command runs. They are
generally not required to be present, but that is configurable. All
options have a long form prefixed by '--', and may have a single letter
alias prefixed by '-'.

=item Arguments

Arguments are positional parameters that that a command needs know in
order to do its work. Confusingly, arguments can be optional. The last
argument defined may be I<greedy>: it can consume everything else left
on the command line.

=item Sub-commands

From a users point of view sub-command arguments and options are
indistinguishable from arguments and options to the main Command.
Sub-command options and arguments are defined in the same place as
Command arguments and options.  However from a code perspective they
are implemented as separate, stand-alone programs to be called by a
dispatcher.

=back

=head2 Simple Scripts

To demonstrate lets put the code from the synopsis in a file called
C<paint> and observe the following interactions from the shell:

    $ ./paint
    usage: paint ITEM

      arguments:
        ITEM          the item to paint

      options:
        --quiet, -q   output nothing while working

The C<optargs()> function parses the commands arguments according to
the C<opt> and C<arg> declarations and returns a single HASH reference.
If the command is not called correctly then an exception is thrown with
an automatically generated usage message as shown above.

Because B<OptArgs> knows about arguments it can detect more errors than
an option-only processing module:

    $ ./paint house red
    error: unexpected option or argument: red

So let's add that missing argument definition:

    arg colour => (
        isa     => 'Str',
        default => 'blue',
        comment => 'the colour to use',
    );

And then check the usage again:

    $ ./paint
    usage: paint ITEM [COLOUR]

      arguments:
        ITEM          the item to paint
        COLOUR        the colour to use

      options:
        --quiet, -q   output nothing while working

It can be seen that the non-required argument C<colour> appears inside
square brackets indicating its optional nature.

Let's add another argument with a positive value for the C<greedy>
parameter:

    arg message => (
        isa     => 'Str',
        comment => 'the message to paint on the item',
        greedy  => 1,
    );

And check the new usage output:

    usage: paint ITEM [COLOUR] [MESSAGE...]

      arguments:
        ITEM          the item to paint
        COLOUR        the colour to use
        MESSAGE       the message to paint on the item

      options:
        --quiet, -q   output nothing while working

Three dots (...) are postfixed to usage message for greedy arguments.
By being greedy, the C<message> argument will swallow whatever is left
on the comand line:

    $ ./paint house blue Perl is great
    Painting in blue on house: "Perl is great".

Note that it doesn't make sense to define any more arguments once you
have a greedy argument.

The order in which options and arguments (and sub-commands - see below)
are defined is the order in which they appear in usage messsages, and
is also the order in which the command line is parsed for them.

=head2 Sub-Command Scripts

Sub-commands are useful when your script performs different actions
based on the value of a particular argument. To use sub-commands
you build your application with the following structure:

=over

=item Command Class

The Command Class defines the options and arguments for your I<entire>
application. The module is written the same way as a simple script but
additionally specifies a 'SubCmd' argument:

    package My::Cmd;
    use OptArgs;

    arg command => (
        isa     => 'SubCmd',
        comment => 'sub command to run',
    );

    opt help => (
        isa     => 'Bool',
        comment => 'print a help message and exit',
        ishelp  => 1,
    );

    opt dry_run => (
        isa     => 'Bool',
        comment => 'do nothing',
    );

The C<subcmd> function call is then used to define sub-command names
and descriptions, and separate each sub-commands arguments and options:

    subcmd( 'start', 'start a machine' );

    arg machine => (
        isa     => 'Str',
        comment => 'the machine to start',
    );

    opt quickly => (
        isa     => 'Bool',
        comment => 'start the machine quickly',
    );

    subcmd( 'stop', 'start the machine' );

    arg machine => (
        isa     => 'Str',
        comment => 'the machine to stop',
    );

    opt plug => (
        isa     => 'Bool',
        comment => 'stop the machine by pulling the plug',
    );

One nice thing about B<OptArgs> is that options are I<inherited>. You
only need to specify something like a C<dry-run> option once at the top
level, and all sub-commands will see it if it has been set.

Additionally, and this is the main reason why I wrote B<OptArgs>, you
do not have to load a whole bunch of slow-to-start modules ( I'm
looking at you, L<Moose>) just to get a help message.

=item Sub-Command Classes

These classes do the actual work. The entry point is a normal function,
typically called something like C<run>, which is passed a single
HASHref containing the option and argument values for the command.

    package My::Cmd::start;

    sub run {
        my $opts = shift;
        print "Starting $opts->{machine}\n";
    }

The function name can be whatever you like but it must be the same for
every sub command.

    package My::Cmd::stop;

    sub run {
        my $opts = shift;
        print "Stoping $opts->{machine}\n";
    }

=item Command Script

The command script is what the user runs, and does nothing more
than dispatch to a call to your the Dispatcher Class:

    #!/usr/bin/perl
    use OptArgs qw/dispatch/;
    dispatch(qw/ run Your::Cmd /);


One advantage to having a separate Command Class (and not defining
everything inside a Command script) is that it is easy to run tests
against your various Sub-Command Classes as follows:

    use Test::More;
    use Test::Output;
    use OptArgs qw/dispatch/;

    stdout_is(
        sub { dispatch( qw/ run My::Cmd start A / ) },
        "Starting A\n", 'start'
    );

    done_testing();

It is much easier to catch and measure exceptions when the code is
running inside your test script, instead of having to fork and parse
stderr strings.

=back

=head1 FUNCTIONS

The following functions are exported (by default except for
C<dispatch>) using L<Exporter::Tidy>.

=over

=item opt( $name, %parameters )

Define a Command Option. If C<$name> contains underscores then aliases
with the underscores replaced by dashes (-) will be created. The
following parameters are accepted:

=over

=item isa

Required. Is mapped to a L<Getopt::Long> type according to the
following table:

     optargs         Getopt::Long
    ------------------------------
     'Bool'          '!'
     'Counter'       '+'
     'Str'           '=s'
     'Int'           '=i'
     'Num'           '=f'
     'ArrayRef'      's@'
     'HashRef'       's%'

=item comment

Required. Used to generate the usage/help message.

=item default

The value set when the option is not used.

If this is a subroutine reference it will be called with a hashref
containg all option/argument values after parsing the source has
finished.  The value to be set must be returned, and any changes to the
hashref are ignored.

=item alias

A single character alias.

=item ishelp

When true flags this option as a help option, which when given on the
command line results in a usage message exception.  This flag is
basically a cleaner way of doing the following in each (sub) command:

    my $opts = optargs;
    if ( $opts->{help} ) {
        die usage('help requested');
    }

=back

=item arg( $name, %parameters )

Define a Command Argument with the following parameters:

=over

=item isa

Required. Is mapped to a L<Getopt::Long> type according to the
following table:

     optargs         Getopt::Long
    ------------------------------
     'Str'           '=s'
     'Int'           '=i'
     'Num'           '=f'
     'ArrayRef'      's@'
     'HashRef'       's%'
     'SubCmd'        '=s'

=item comment

Required. Used to generate the usage/help message.

=item required

Set to a true value when the caller must specify this argument.  Can
not be used if a 'default' is given.

=item default

The value set when the argument is not given. Can not be used if
'required' is set.

If this is a subroutine reference it will be called with a hashref
containg all option/argument values after parsing the source has
finished.  The value to be set must be returned, and any changes to the
hashref are ignored.

=item greedy

If true the argument swallows the rest of the command line. It doesn't
make sense to define any more arguments once you have used this as they
will never be seen.

=item fallback

If C<isa> is a C<SubCmd> this option (when set) will stop the
generation of the usage message when the argument is not found as a
sub-command. The current command will be called instead. This option
when set must be a HASH reference containing "name" and "comment"
key/value pairs, which are only used in usage messages.

=back

=item optargs( [ @argv ] ) -> HashRef

Parse @ARGV by default (or @argv when given) and returns a hashref
containing key/value pairs for options and arguments I<combined>.  An
error / usage exception is thrown if an invalid combination of options
and arguments is given.

Note that C<@ARGV> will be decoded into UTF-8 (if necessary) from
whatever L<I18N::Langinfo> says your current locale codeset is.

=item usage( [$message] ) -> Str

Returns a usage string prefixed with $message if given.

=item subcmd( @cmd, $description )

Create a sub-command. After this function is called further calls to
C<opt> and C<arg> define options and arguments respectively for the
sub-command.

=item dispatch( $function, $rootclass, [ @argv ] )

Parse C<@ARGV> (or C<@argv> if given) and dispatch to C<$function>
in the appropriate package name constructed from C<$rootclass>.

=back

=head1 SEE ALSO

L<Getopt::Long>, L<Exporter::Tidy>

=head1 SUPPORT & DEVELOPMENT


This distribution is managed via github:

    https://github.com/mlawren/p5-OptArgs/tree/devel

This distribution follows the semantic versioning model:

    http://semver.org/

Code is tidied up on Git commit using githook-perltidy:

    http://github.com/mlawren/githook-perltidy

=head1 AUTHOR

Mark Lawrence <nomad@null.net>

=head1 LICENSE

Copyright 2012 Mark Lawrence <nomad@null.net>

This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 3 of the License, or (at your
option) any later version.

