NAME

MooX::Role::CliOptions - Wrapper to simplify using Moo with Getopt::Long

VERSION

Version 0.05

SYNOPSIS

This is a minimal script that composes MooX::Role::CliOptions.

  #!/usr/bin/perl
  package My::Moodulino;

  use Moo;
  with 'MooX::Role::CliOptions';

  # initialize script attributes/variables
  has option1 => (
      is      => 'ro',
      isa     => sub {
          die 'Illegal value for option1'
            unless $_[0] =~ /^foo|bar$/;
      },
      default => '',
  );

  ...

  # this makes the script a modulino
  do {
      my $app = __PACKAGE__->init(
          argv     => \@ARGV,
          add_opts => [ 'option1=s' ],
      );
      exit $app->run;
  } unless caller();

  sub run {
      my $self = shift;

      ...

      return 0;
  }

  1; # must be present to satisfy "require" when testing
  __END__

DESCRIPTION

This role was written to help standardize command line script behavior and, if written as a modulino, greatly improve testability. It should be noted that all example code snippets below are based on the modulino style but the normal, non-modulino style is also supported. See the example and test scripts in the distribution for further info if needed.

The default object created when composing this Role has the following structure (assuming a package name of My::Moodulino as above and no additional attributes are defined in the composing class.)

$VAR1 = bless( {
 'debug' => 1,
 'verbose' => 1,
 'argv' => []
}, 'My::Moodulino' );
 

EXPORTS

None. (Not applicable in a Role.)

ATTRIBUTES

Three read-only attributes are provided for the composing package, two of which are exposed as command line arguments and the third being created from the final @ARGV values after processing by Getopt::Long.

NOTE: Both debug and verbose can be eliminated from the Role by setting the environment variable MRC_NO_STDOPTS to a "true" value before composing MooX::Role::CliOptions into your script. This allows you to completely remove them or redefine them to suit your needs as desired. For example, you might want --debug to be "off" by default. If you decide to redefine them you must supply a suitable attribute in your script. This does NOT affect the --help or --man command line options or the argv attribute.

The following example demonstrates this:

#!perl!
 
# redefine --debug to be off by default and --verbose to indicate a level
# between 0 and 5
BEGIN {
   $ENV{MRC_NO_STDOPTS} = 1;
}
 
use Moo;
with 'MooX::Role::CliOptions';
 
# not required but strongly recommended by ths author
use MooX::StrictConstructor;

has debug => (
   is => 'ro',
   default => 0,
);
 
has verbose => (
   is => 'ro',
   isa => sub {
       die 'illegal value for --verbose'
         unless $_[0] >= 0 && $_[0] <= 5;
   },
   default => 0,
);
 
do {
   my $app = __PACKAGE__->init(
       argv => \@ARGV,
       add_opts => [
           'debug',
           'verbose=i',
       ],
   );
 
   exit $app->run;
} unless caller();
 
...
 

debug (Boolean read-only)

Exposed as the negatable --debug command line option.

Default: Boolean TRUE (1). Is turned off with --nodebug on the command line. (Paranoia is your friend.)

Commonly used to enable diagnostic reports and/or disable potentially dangerous operations such as database modifications.

Note: Implies the setting for verbose if --verbose or --noverbose is not explicitly set on the command line.

verbose (Boolean read-only)

Exposed as the negatable --verbose command line option.

Typically used to add extra information to the output. Often used in conjunction with --debug.

Default: Will be the same as debug if not explicitly set with either --verbose or --noverbose. This behavior was chosen since that is the most common usage pattern in the author's experience.

The most likely usage patterns would be

# in a crontab where no verbose output would be desired (verbose will
# default to OFF.)
/my_script --nodebug
 
# manually run from the cli where normal operation is needed and verbose
# output is desired
/my_script --nodebug --verbose

argv (read-only)

Returns an arrayref to the contents of @ARGV after processing by Getopt::Long. This is syntactic sugar for using @ARGV directly.

Default: An empty arrayref if no command line arguments other than options recognized by Getopt::Long are supplied.

OTHER COMMAND LINE OPTIONS

The following command line options are also accepted, but are not associated with an attribute since both will cause an immediate exit via Pod::Usage after displaying the appropriate message.

--help

Will use pod2usage to display the SYNOPSIS or USAGE POD section if available.

--man

Will use pod2usage to display the full POD if available.

METHODS

init

This is the workhorse that integrates Getopt::Long with the call to the composing package's new constructor. Its return value is the resulting object of the composing package type.

Parameters

argv (required)

Typically passed in as follows:

my $app = __PACKAGE__->init( argv => \@ARGV );
 

This will be passed to Getopt::Long for processing. Any remaining elements will be left in @ARGV. They can also be accessed via $app->argv.

add_opts (optional)

You can add your own command line options by using this. Simply place the Getopt::Long specification for any additional options that you want in an array ref as shown below and be sure to declare an attribute to hold the option data as processed by Getopt::Long. (See the example scripts to make things clear.)

# in your script
has custom1 => (
   is => 'ro',
   isa => sub { ... },
);
 
do {
   my $app = __PACKAGE__->init(
       argv => \@ARGV,
       add_opts => [
           'custom1=s',
       ],
   );
   exit ($app->run || 0);
} unless caller();
 

The above snippet would tell Getopt::Long to accept a command line option named custom1 that must be a string and place it in the custom1 attribute that was declared. You may use any kind of isa or coerce test that you deem are needed as well as a default.

SEE ALSO

examples/moodulino.pl for a functional modulino script.
examples/myscript.pl for a functional non-modulino script.

AUTHOR

Jim Bacon, <boftx at cpan.org>

BUGS

Please report any bugs or feature requests to bug-moox-role-clioptions at rt.cpan.org, or through the web interface at https://rt.cpan.org/NoAuth/ReportBug.html?Queue=MooX-Role-CliOptions. I will be notified, and then you'll automatically be notified of progress on your bug as I make changes.

SUPPORT

You can find documentation for this module with the perldoc command.

perldoc MooX::Role::CliOptions

You can also look for information at:

LICENSE AND COPYRIGHT

Copyright 2019 Jim Bacon.

This program is free software; you can redistribute it and/or modify it under the terms of the the Artistic License (2.0). You may obtain a copy of the full license at:

http://www.perlfoundation.org/artistic_license_2_0

Any use, modification, and distribution of the Standard or Modified Versions is governed by this Artistic License. By using, modifying or distributing the Package, you accept this license. Do not use, modify, or distribute the Package, if you do not accept this license.

If your Modified Version has been derived from a Modified Version made by someone other than you, you are nevertheless required to ensure that your Modified Version complies with the requirements of this license.

This license does not grant you the right to use any trademark, service mark, tradename, or logo of the Copyright Holder.

This license includes the non-exclusive, worldwide, free-of-charge patent license to make, have made, use, offer to sell, sell, import and otherwise transfer the Package with respect to any patent claims licensable by the Copyright Holder that are necessarily infringed by the Package. If you institute patent litigation (including a cross-claim or counterclaim) against any party alleging that the Package constitutes direct or contributory patent infringement, then this Artistic License to you shall terminate on the date that such litigation is filed.

Disclaimer of Warranty: THE PACKAGE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS "AS IS' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES. THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED TO THE EXTENT PERMITTED BY YOUR LOCAL LAW. UNLESS REQUIRED BY LAW, NO COPYRIGHT HOLDER OR CONTRIBUTOR WILL BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING IN ANY WAY OUT OF THE USE OF THE PACKAGE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.