Getopt::App - Write and test your script with ease
#!/usr/bin/env perl package My::Script; use Getopt::App -signatures; # See "APPLICATION METHODS" sub getopt_post_process_argv ($app, $argv, $state) { ... } sub getopt_configure ($app) { ... } # run() must be the last statement in the script run( # Specify your Getopt::Long options and optionally a help text 'h|help # Output help', 'v+ # Verbose output', 'name=s # Specify a name', # Here is the main sub that will run the script sub ($app, @extra) { return print extract_usage() if $app->{h}; say $app->{name} // 'no name'; # access command line options return 42; # Reture value is used as exit code } );
The example script above can be run like any other script:
$ my-script --name superwoman; # prints "superwoman" $ echo $? # 42
use Test::More; use Cwd qw(abs_path); use Getopt::App -capture; # Sourcing the script returns a callback my $app = do(abs_path('./bin/myapp')); # The callback can be called with any @ARGV subtest name => sub { my $got = capture($app, [qw(--name superwoman)]); is $got->[0], "superwoman\n", 'stdout'; is $got->[1], '', 'stderr'; is $got->[2], 42, 'exit value'; }; done_testing;
Getopt::App is a module that helps you structure your scripts and integrates Getopt::Long with a very simple API. In addition it makes it very easy to test your script, since the script file can be sourced without actually being run.
Getopt::App also supports infinite nested subcommands and a method for bundling this module with your script to prevent depending on a module from CPAN.
This module is currently EXPERIMENTAL, but is unlikely to change much.
These methods are optional, but can be defined in your script to override the default behavior.
@configure = $app->getopt_configure;
This method can be defined if you want "Configure" in Getopt::Long to be set up differently. The default return value is:
qw(bundling no_auto_abbrev no_ignore_case pass_through require_order)
The default return value is currently EXPERIMENTAL.
$code = $app->getopt_subcommand($subcommand, [@ARGV]);
Takes the subcommand found in the "getopt_subcommands" list and the command line arguments and must return a CODE block. The default implementation is simply:
$code = do($subcommand->[1]);
$bool = $app->getopt_post_process_argv([@ARGV], {%state});
This method can be used to post process the options. %state contains a key "valid" which is true or false, depending on the return value from "GetOptionsFromArray" in Getopt::Long.
%state
This method can die and optionally set $! to avoid calling the function passed to "run".
die
$!
The default behavior is to check if the first item in $argv starts with a hyphen, and die with an error message if so:
$argv
Invalid argument or argument order: @$argv\n
$exit_value = $app->getopt_post_process_exit_value($exit_value);
A method to be called after the "run" function has been called. $exit_value holds the return value from "run" which could be any value, not just 0-255. This value can then be changed to change the exit value from the program.
$exit_value
sub getopt_post_process_exit_value ($app, $exit_value) { return int(1 + rand 10); }
$app->getopt_pre_process_argv($argv);
This method can be defined to pre-process $argv before it is passed on to "GetOptionsFromArray" in Getopt::Long. Example:
sub getopt_pre_process_argv ($app, $argv) { $app->{first_non_option} = shift @$argv if @$argv and $argv->[0] =~ m!^[a-z]!; }
This method can die and optionally set $! to avoid calling the actual "run" function.
$subcommands = $app->getopt_subcommands;
This method must be defined in the script to enable sub commands. The return value must be either undef to disable subcommands or an array-ref of array-refs like this:
undef
[["subname", "/abs/path/to/sub-command-script", "help text"], ...]
The first element in each array-ref "subname" will be matched against the first argument passed to the script, and when matched the "sub-command-script" will be sourced and run inside the same perl process. The sub command script must also use Getopt::App for this to work properly.
See https://github.com/jhthorsen/getopt-app/tree/main/example for a working example.
$exit_value = $app->getopt_unknown_subcommand($argv);
Will be called when "getopt_subcommands" is defined but $argv does not match an item in the list. Default behavior is to die with an error message:
Unknown subcommand: $argv->[0]\n
Returning undef instead of dieing or a number (0-255) will cause the "run" callback to be called.
use Getopt::App -capture; my $app = do '/path/to/bin/myapp'; my $array_ref = capture($app, [@ARGV]); # [$stdout, $stderr, $exit_value]
Used to run an $app and capture STDOUT, STDERR and the exit value in that order in $array_ref. This function will also capture die. $@ will be set and captured in the second $array_ref element, and $exit_value will be set to $!.
$app
$array_ref
$@
# Default to "SYNOPSIS" from current file my $str = extract_usage($section, $file); my $str = extract_usage($section); my $str = extract_usage();
Will extract a $section from POD $file and append command line option descriptions when called from inside of "run". Command line options can optionally have a description with "spaces-hash-spaces-description", like this:
$section
$file
run( 'o|option # Some description', 'v|verbose # Enable verbose output', sub { ... }, );
This function will not be exported if a function with the same name already exists in the script.
my $obj = new($class, %args); my $obj = new($class, \%args);
This function is exported into the caller package so we can construct a new object:
my $app = Application::Class->new(\%args);
# Run a code block on valid @ARGV run(@rules, sub ($app, @extra) { ... }); # For testing my $cb = run(@rules, sub ($app, @extra) { ... }); my $exit_value = $cb->([@ARGV]);
"run" can be used to call a callback when valid command line options is provided. On invalid arguments, warnings will be issued and the program exit with $? set to 1.
$?
$app inside the callback is a hash blessed to the caller package. The keys in the hash are the parsed command line options, while @extra is the extra unparsed command line options.
@extra
@rules are the same options as Getopt::Long can take. Example:
@rules
# app.pl -vv --name superwoman -o OptX cool beans run(qw(h|help v+ name=s o=s@), sub ($app, @extra) { die "No help here" if $app->{h}; warn $app->{v}; # 2 warn $app->{name}; # "superwoman" warn @{$app->{o}}; # "OptX" warn @extra; # "cool beans" return 0; # Used as exit code });
In the example above, @extra gets populated, since there is a non-flag value "cool" after a list of valid command line options.
Getopt::App->bundle($path_to_script); Getopt::App->bundle($path_to_script, $fh);
This method can be used to combine Getopt::App and $path_to_script into a a single script that does not need to have Getopt::App installed from CPAN. This is for example useful for sysadmin scripts that otherwize only depends on core Perl modules.
$path_to_script
The script will be printed to $fh, which defaults to STDOUT.
$fh
STDOUT
Example usage:
perl -MGetopt::App -e'Getopt::App->bundle(shift)' ./src/my-script.pl > ./bin/my-script;
use Getopt::App; use Getopt::App 'My::Script::Base', -signatures; use Getopt::App -capture;
Default
use Getopt::App;
Passing in no flags will export the default functions "extract_usage", "new" and "run". In addition it will save you from a lot of typing, since it will also import the following:
use strict; use warnings; use utf8; use feature ':5.16';
Signatures
use Getopt::App -signatures;
Same as "Default", but will also import "signatures" in experimental. This requires Perl 5.20+.
Class name
package My::Script::Foo; use Getopt::App 'My::Script';
Same as "Default" but will also make My::Script::Foo inherit from My::Script. Note that a package definition is required.
My::Script::Foo
Capture
use Getopt::App -capture;
This will only export "capture".
This library is free software. You can redistribute it and/or modify it under the same terms as Perl itself.
Jan Henning Thorsen - jhthorsen@cpan.org
jhthorsen@cpan.org
To install Getopt::App, copy and paste the appropriate command in to your terminal.
cpanm
cpanm Getopt::App
CPAN shell
perl -MCPAN -e shell install Getopt::App
For more information on module installation, please visit the detailed CPAN module installation guide.