NAME
App::Easer::V2 - Simplify writing (hierarchical) CLI applications
VERSION
This document describes App::Easer::V2 version {{[ version ]}}.
SYNOPSIS
#!/usr/bin/env perl
use v5.24;
use experimental 'signatures';
use App::Easer V2 => 'run';
my $app = {
aliases => ['foo'],
help => 'this is the main app',
description => 'Yes, this really is the main app',
options => [
{
name => 'foo',
help => 'option foo!',
getopt => 'foo|f=s',
environment => 'FOO',
default => 'bar',
},
],
execute => sub ($instance) {
my $foo = $instance->config('foo');
say "Hello, $foo!";
return 0;
},
default_child => '-self', # run execute by default
children => [
{
aliases => ['bar'],
help => 'this is a sub-command',
description => 'Yes, this is a sub-command',
execute => sub { 'Peace!' },
},
],
};
exit run($app, $0, @ARGV);
Call examples:
$ ./example.pl
Hello, bar!
$ ./example.pl --foo World
Hello, World!
$ ./example.pl commands
sub-commands for ./example.pl
bar: this is a sub-command
help: print a help command
commands: list sub-commands
$ ./example.pl help
this is the main app
Description:
Yes, this really is the main app
Can be called as: foo
Options:
foo: option foo!
command-line: mandatory string option
--foo <value>
-f <value>
environment: FOO
default: bar
Sub-commands:
bar: this is a sub-command
help: print a help command
commands: list sub-commands
$ ./example.pl help help
print a help command
Description:
Print help for (sub)command
Can be called as: help
This command has no option
No sub-commands
$ ./example.pl help commands
list sub-commands
Description:
Print list of supported sub-commands
Can be called as: commands
This command has no option
No sub-commands
$ ./example.pl inexistent
cannot find sub-command 'inexistent'
$ ./example.pl help inexistent
cannot find sub-command 'inexistent'
DESCRIPTION
NOTE: THIS DOCUMENT HAS TO BE REVIEWED TO MAKE IT EXPLICIT THAT IT REFERS TO VERSION 2 OF THE API.
App::Easer::V2 provides the scaffolding for implementing hierarchical command-line applications in a very fast way. This is Version 2 of the provided API, which does everything described below.
It makes it extremely simple to generate an application based on specific interfacing options, while still leaving ample capabilities for customising the shape of the application. As such, it aims at making simple things easy and complex things possible, in pure Perl spirit.
There are multiple ways to define an application. The two extremes are:
a hash reference with all the needed elements inside (see "SYNOPSIS" for an example)
a sub-class of
App::Easer::V2::Command
with methods overriding the needed elements where the programmer sees fit.
App::Easer::V2 allows also to leverage both aspects at the same time for the same command, e.g. setting some parts through a hash reference and other parts with overriding methods.
Top-Level Functions
The following functions are exported by App::Easer::V2
:
appeaser_api
my $api_version = appeaser_api();
Return string
V2
.d
d($whatever);
Sends
$whatever
throughdd
and then towarn
.dd
my $dumped = dd($whatever);
Sends
$whatever
through Data::Dumper and returns it.run
my $exit_code = run($cmd_hashref, $0, @ARGV);
Run a command with the provided parameters (first the name of the command, using
$0
, then the command-line arguments).
In addition to importing the functions above, the following keys are also supported when use
ing the module:
-command
The package from where
App::Easer::V2
isuse
d is a command and inherits fromApp::Easer::V2::Command
, as well as registering as a command. This is the combined effect of-inherit
and-register
below.-inherit
The package from where
App::Easer::V2
isuse
d inherits fromApp::Easer::V2::Command
. Usually-command
is the right one though.-register
Register this package as a valid (sub)command.
-spec
Provide a specification hash reference to set many attributes of the specific command. This hash reference is saved into the package's variable
app_easer_spec
.
The options above allow easily define a new class for a command like this:
use App::Easer::V2 -command => -spec => { ... };
Anatomy of a run
Running an application can be done in several ways, depending on how the application is represented:
# application defined as a hashref or arrayref
use App::Easer V2 => 'run';
exit run($app, $0, @ARGS);
# application defined in a class
use MyApp;
exit MyApp->new->run($0, @ARGS);
When an application is run, the following high level algorithm is applied:
Options are gathered from different sources, like e.g. the command-line, environment variables, parent commands (in lower levels of the command hierarchy), files, or defaults.
A commit hook is called, if present, allowing an intermediate command to perform some actions before a sub-command is run. This hook has been anticipated before validation in V2.
A validation hook is called, if present, allowing check of the provided configuration, e.g. to spot incompatible options.
A sub-command is searched if possible and, if present, the process restarts from the first bullet above with this sub-command.
When the final sub-command is reached, the execute hook is run.
Application High Level View
The following list provides all keys/method names that are recognized in the definition of an application with App::Easer::V2
. Items markes as Executable
can be provided as sub references or with overriding the corresponding method in the derived class.
aliases
-
Array of strings.
The array contains alias names for the command. The first alias is also considered the
name
in case aname
is missing. allow_residual_options
-
Boolean, defaults to false.
Signal that the parsing of the command line must not fail if residual, unrecognized options are found. This allows e.g. building wrappers around external commands without the need to re-implement all of their options.
auto_environment
-
Boolean, defaults to false.
Signal that all options without an
environment
key should get one set to value 1, triggering auto-generation of the environment variable name. children
-
Array of items.
Provides a list of children for the command. Children can be provided as hash references (whose structure is the same as anytyhing supported by
hashy_class
), array references (whose first item is the name of a class and the rest is provided to itsnew
method), a string (which leads to a class name that can be instantiated without parameters), or a blessed object.Anything that does not eventually produce a
App::Easer::V2::Command
should be considered a liability. children_prefixes
-
Array of strings. Defaults to
[$pkg . '::Cmd']
.Each string in the array is used as a prefix to look for sub-commands in
@INC
.Assuming the main command is implemented in class
MyApp
, the default value looks for classes namedMyApp::Cmd*
, e.g.MyApp::CmdFoo
andMyApp::CmdBar
and ignores classed namedMyApp::Common
orMyApp::Utils
. commit
-
Executable with signature:
sub commit_function ($app) { ... }
where
$app
is the blessed object for the application.Perform the commit hook for the application, which is called immediately after the collection of options for the command and before looking further down for sub-commands or calling the
execute
method. Every weird action like fiddling with the command-line arguments etc. should be done here. default_child
-
String. Defaults to
help
.The name of a sub-command to invoke if no non-option values are set on the command line for a non-leaf command.
If set to
-self
, lack of an explicit child name on the command line means that theexecute
of the command itself should be run.See also
fallback_to
. description
-
String.
A verbose form of
help
, usually providing details about how the command works. This is used when generating the whole help for the command. environment_prefix
-
String.
A prefix that is applied to an options's name to derive an environment variable name. Used when
auto_environment
is true and noenvironment
key is present in the option's specification, or when theenvironment
key points to value1
. execute
-
Executable.
getopt_config
-
Array of strings. See below for defaults.
A list of strings to use to configure
Getopt::Long
for the specific command.By default it is set to
gnu_getopt
. If a command is not a leaf,require_order
andpass_through
are added too, although the latter only temporarily to allow for chaining (unrecognized options might still trigger an exception). Ifallow_residual_options
is true,pass_through
is added. help
-
A concise form of help, ideally a single line to explain what the (sub-)command does. It is used when generating the whole help for the command, as well as the list of sub-commands of the help for the parent command.
options
-
Array of items.
See "OPTIONS".
fallback_to
-
String.
The name of a sub-command to invoke if the first non-option command-line argument is not recognized as a children command for non-leaf commands.
If set to
-self
, lack of a valid child name on the command line means that theexecute
of the command itself should be run.If set to
-default
, thedefault_child
is used.If set to a non-negative integer n, the n-th child is used from the list of children.
If set to a string, the corresponding child is used.
Otherwise, an exception is raised.
See also
default_child
. force_auto_children
-
Boolean. Defaults to false.
Force the generation of the so-called auto-children even for leaf commands (i.e. commands without sub-commands either in
children
or from the class hierarchy).Auto-children are the
help
,commands
, andtree
sub-commands.This can come handy when
default_child
/fallback_to
are set to-self
and the three wordshelp
,commands
, andtree
are not possible valid values as arguments for the leaf command itself (e.g. when it does not use non-option command line arguments). hashy_class
-
String. Defaults to
App::Easer::V2::Command
.The class name to use for inflating applications defined as hash references into objects.
Anything different from the default is a liability.
help_channel
-
String. Defaults to
-STDOUT:encoding(UTF-8)
.Set the output channel for automatic commands
help
,commands
, andtree
.It can be set to:
a sub reference, which will be called with the following signature:
sub channel ($cmd_object, @stuff_to_print);
a filehandle, used to print out stuff
a reference to a scalar, where the output will be placed
a string of the form
filename[:binmode]
, wherefilename
can NOT contain the character:
. The file will be opened and if thebinmode
part is provided,binmode()
will be called on the resulting filehandle with the provided value.If the
filename
part is-
or-stdout
(case insensitive), thenSTDOUT
will be used. Iffilename
is-stderr
(case insensitive), thenSTDERR
will be used.
name
-
String.
Name of the command. If absent, the first item in the
alias
array is used. params_validate
-
Hash reference or
undef
.If passed as a hash reference, two keys are supported:
sources
-
Array of items.
See "OPTIONS".
The following YAML representation gives an overview of the elements that define an application managed by App::Easer::V2
, highlighting the necessary or strongly suggested ones at the beginning:
aliases: «array of strings»
execute: «executable»
help: «string»
options: «array of hashes»
allow_residual_options: «boolean»
auto_environment: «boolean»
children: «array of hashes»
children_prefixes: «array of strings»
commit: «executable»
default_child: «string»
description: «string»
environment_prefix: «string»
fallback_to: «string»
force_auto_children: «boolean»
hashy_class: «string»
help_channel: «string»
name: «string»
params_validate: «hash»
sources: «array of items»
validate: «executable»
As anticipated, it's entirely up to the user to decide what style is best, i.e. define applications through metadata only, through object-oriented derivation, or through a mix of the two. The following examples are aimed at producing the same application:
# metadata (mostly)
my $app_as_metadata = {
aliases => [qw< this that >],
help => 'this is the application, but also that',
options => [ { getopt => 'foo|f=s', default => 'bar' } ],
execute => sub ($app) {
say 'foo is ', $app->config('foo');
return 0;
},
};
# class only
package ThisThatApp;
use App::Easer::V2 '-command';
sub aliases ($self) { return [qw< this that >] }
sub help ($self) { return 'this is the application, but also that' }
sub options ($self) { [ { getopt => 'foo|f=s', default => 'bar' } ] }
sub execute ($self) {
say 'foo is ', $self->config('foo');
return 0;
}
# mixed style
package ThisThatMixedApp;
use App::Easer::V2 -command => -spec => {
aliases => [qw< this that >],
help => 'this is the application, but also that',
options => [ { getopt => 'foo|f=s', default => 'bar' } ],
};
sub execute ($self) {
say 'foo is ', $self->config('foo');
return 0;
}
The last style allows keeping data mostly as data, while leaving the freedom to implement the logic as proper methods, which can be beneficial for e.g. sharing common logic among several commands.
App::Easer::V2::Command METHODS
When a command is created, it is (usually) an instance of class App::Easer::V2::Command
or a descendant. As such, it has the methods explained in the following list, which at the moment appear as public ones although some might be hidden in the future (stable ones are expressely marked so).
auto_children
-
my @classes = $self->auto_children; my @objects = $self->auto_children(1);
Return a list of the automatic children (
help
,commands
, andtree
) as inflatable children, i.e. as fully qualified class names. If an optional true value is passed, children are inflated into objects. auto_commands
-
my $instance = $self->auto_commands;
Returns an instance representing the
commands
sub-command. auto_help
-
my $instance = $self->auto_help;
Returns an instance representing the
help
sub-command. auto_tree
-
my $instance = $self->auto_tree;
Returns an instance representing the
tree
sub-command. aliases
-
my @aliases = $self->aliases; my @modified = $self->aliases(\@new_aliases);
Gets/sets the aliases. If not set,
name
is used. allow_residual_options
-
my $boolean = $self->allow_residual_options; $self->allow_residual_options(0); # disable $self->allow_residual_options(1); # enable
auto_environment
-
my $boolean = $self->auto_environment; $self->auto_environment(0); # disable $self->auto_environment(1); # enable
call_name
-
my $string = $self->call_name; $self->call_name('override, for no reason apparently...');
Returns a string with the name used to call the sub command (useful to figure out which of the
aliases
was used).The method can also be used to set this name, if needed. This is not guaranteed to be future-proof.
children
-
my @direct_children = $self->children; $self->children(\@new_direct_children);
Get/set the list of direct children. Other children might be collected automatically from the class hierarchy.
Use of this method is discouraged and not future-proof.
children_prefixes
-
my $aref = $self->children_prefixes; $self->children_prefixes(\@new_prefixes);
collect
-
$self->collect;
Collect options values from the configured sources, see "OPTIONS".
Not assumed to be used directly. Overloading is a liability.
commit
-
$self->commit;
Commit the collected options.
Not assumed to be used directly.
It can be overloaded to provide a custom behaviour, which can e.g. modify
residual_args
orconfig_hash
to drive following steps of looking for a sub-command. config
-
my $value = $self->config($key); # returns a scalar anyway my @values = $self->config(@keys);
Retrieve collected option values.
config_hash
-
my $merged_hash = $self->config_hash; my $detailed = $self->config_hash(1);
Get the collected option values as a hash.
In the basic case, a merged hash is returned, with values taken from sources according to their priorities.
In the advanced case where a true value is passed as optional argument, a hash with two keys
merged
andsequence
is returned. The explanation of the data format is beyond the scope of this manual page. default_child
-
my $dc = $self->default_child; $self->default_child($new_name);
description
-
my $text = $self->description; $self->description($updated_description);
environment_prefix
-
my $prefix = $self->environment_prefix; $self->environment_prefix($new_prefix);
environment_variable_name
-
my $name = $self->environment_variable_name($opt_hash);
Get the environment variable name set for the specific option described by
$opt_hash
. If it contains anenvironment
key and it has a name, that is returned, otherwise if it is1
then an environment variable is generated fromenvoronment_prefix
andname
. execute
-
$self->execute;
Code that executes the main logic of the command.
If a sub reference was provided with
execute
in the application definition, that is called receiving the object as its only parameter. Otherwise, the intended use is to override this method in a derived class for a command.It is not meant to be called directly.
execution_reason
-
my $reason = $self->execution_reason;
A string representing the reason why the specific
execute
method/callback was selected, can be one of:-default
The command was selected as the default child set for a command.
-fallback
The command was selected as a result of the
fallback
method.-leaf
The command is a leaf and has no sub-commands.
fallback
-
my $name = $self->fallback;
Select a fallback child, or the invoking command itself (returning
-self
) as the command that should be investigated next or executed.This method is called when there are unrecognized non-option command-line arguments that lead to no child of a non-leaf command. The selection is performed using
fallback_to
. fallback_to
-
my $name = $self->fallback_to; $self->fallback_to($new_fallback);
Get/set the fallback string for figuring out the fallback in case of need. Used by
fallback
. find_child
-
my ($child_instance, @child_args) = $self->find_child;
Look for a child to hand execution over. Returns an child instance or undef (which means that the
$self
is in charge of executing something). This implements the most sensible default, deviations will have to be coded explicitly.This method is called by
run
and is not expected to be called elsewhere. It use is discouraged and not future-proof.Returns a list with the selected children and the arguments to feed to its
run
method:-
(undef, '-leaf')
if no child exists. In this case, the caller command's
execute
method should be used. -
($instance, @args)
if a child is found in
$args[0]
. -
($instance, '-default')
if the default child is returned.
-
(undef, '-fallback')
in case $self is the fallback and should be used for calling the
execute
method. -
($instance, '-fallback', @args)
in case the fallback is returned, with the residual unparsed arguments.
-
find_matching_child
-
my $instance = $self->find_matching_child($name);
Find and instantiate a child matching
$name
, either directly or as an alias. force_auto_children
-
my $boolean = $self->force_auto_children; $self->force_auto_children(0); # disable $self->force_auto_children(1); # enable
full_help_text
-
my $text = $self->full_help_text;
Get the full auto-generated help text for the command, e.g. to print it.
getopt_config
-
my $aref = $self->getopt_config; $self->getopt_config(\@custom_getopt_long_configuration);
hashy_class
-
my $class = $self->hashy_class; $self->hashy_class($new_class);
Setting this to anything different from
App::Easer::V2::Command
is a liability, although it might make sense to set to a derived class to provide a common set of methods useful for the specific application. help
-
my $text = $self->help; $self->help($new_help_line);
help_channel
-
my $ch = $self->help_channel; $self->help_channel($new_channel);
inflate_children
-
my @instances = $self->inflate_children(@hints);
Turn a list of
@hints
into corresponding instances.A blessed hint is always returned unmodified, assuming it's already a valid instance. No check on the class is performed.
A hash reference is inflated using
hashy_class
.An array reference assumes that the first element in the array is a valid
hashy_class
and the rest of the items are passed to itsnew
method.Anything else is considered a string containing a class to instantiate.
Actual instantiation is done using method
instantiate
.Direct use of this method is a liability.
inherit_options
-
my @options = $self->inherit_options(@options_names);
Look for matching names in a parent's options. This does technically not put these options inside the command, but it is used internally to achieve this goal.
This method is not meant to be called directly and is subject to become a private method, so its usage is discouraged and not future-proof.
instantiate
-
my $instance = $self_or_package->instantiate($class, @args);
This method loads class
$class
viaload_module
and returns:$class->new(@args);
This is a class method.
list_children
-
my @children = $self->list_children;
Return the full list of children for a command, including ones gathered in the class tree and auto-generated ones (these are added only if there are other children or if
force_auto_children
is set to a true value). load_module
-
my $module_name_copy = $self->load_module($module_name);
Load
$module_name
withrequire
and return the name itself. The module name can only be provided using::
as separators. No specific bug from the past of Perl is addressed. merge_hashes
-
my $merged = $self->merge_hashes(@inputs);
Takes a list of input hash references and generates a merged version of all of them. Hashes in
@inputs
are supposed to be provided in priority order, where those coming first take precedence over those coming next. name
-
my $name = $self->name; $self->name($new_name);
Get/set name of command. If not present, the first item of
aliases
is used. If this is not set too, or empty, string** no name **
is used. name_for_option
-
my $opt_name = $self->name_for_option($opt_spec_hashref);
Get the option's name, either from its
name
key, or deriving it fromgetopt
, or fromenvironment
. Returns~~~
if none of them works. new
-
my $instance = $class->new(@spec); my $other = $class->new(\%spec);
Instantiate a new object, using the provided values.
In derived classes, additional specifications are also taken from the package variable
$class . '::app_easer_spec'
, if set. options
-
my @options_aoh = $self->options; $self->options(\@new_options);
See "Application High Level View" and "OPTIONS". The returned list if passed through
resolve_options
anyway, e.g. to inherit options. params_validate
-
my $href_or_undef = $self->params_validate; $self->params_validate($new_pv_conf);
parent
-
my $parent_command = $self->parent;
Get the parent command.
ref_to_sub
-
my $sub = $self->ref_to_sub($locator);
Turn a locator for a sub into a proper reference to a sub. The
$locator
can be:a sub reference, that is returned unmodified;
an array reference with two items inside, i.e. a class/module name followed by a method/function name
a string pointing to the function, either fully qualified as in
My::Class::function
or as a plain name that will be looked for in the class of$self
.
residual_args
-
my @residual_args = $self->residual_args; $self->residual_args(@new_args);
Access the list of residual (i.e. unparsed) arguments from the command line.
resolve_options
-
my @options = $self->resolve_options($single_specification);
Expand a
$single_specification
into one or more options. Basic optiosn specifications are hash references, but they might be strings like+parent
(for inheriting all that is transmitted from a parent command) or regular expressions to bulk import options based on their names. run
-
$self->run($command_name, @arguments);
Run a command. The first parameter is the command name, it should probably be set to
$0
when calling the topmost command.Running means parsing all options and potentially looking for sub-commands, until one is found.
Returns whatever the
execute
method of the selected sub-command returns. run_help
-
$self->run_help;
Run the
auto_help
command, which should print out the help for the command itself. This is not usually needed, but comes handy to implement printing the help not via a sub-command but honoring a command-line option, like this:sub execute ($self) { return $self->run_help if $self->config('help'); ... }
set_config
-
$self->set_config(foo => 'bar');
Set a new value for a configuration, overriding what has been found out from the several input sources.
slot
-
my $hashref = $self->slot; $self->slot($new_data);
App::Easer::V2
uses a blessed hash reference to manage all data related to an object representing a command. To minimize overlapping with a user's object data, all data forApp::Easer::V2
is kept in a sub-hash pointed by theslot
key, like this:bless { $class_name => { ... all actual App::Easer::V2 stuff here ... } }, $hashy_class;
This method gives access to this slot and can be overridden to keep this data elsewhere, e.g. in an array element or in an inside-out object, without the need to re-implement all accessors.
slurp
-
my $contents = $self->slurp($filename); my $contents_2 = $self->slurp($filename, '<:raw');
Get the whole contents from a file, optionally specifying the mode for openining the file. By default, UTF-8 encoding is assumed and enforced.
Use of this method is discouraged and not future-proof.
sources
-
my @sources = $self->sources; $self->sources(\@new_sources_list);
See "Application High Level View" and "OPTIONS".
validate
OPTIONS
The main capability provided by App::Easer
is the flexibility to handle options, collecting them from several sources and merging them together according to priorities.
Supported options are set in an array of hashes (or strings) pointed by the options
key. Each hash in the array sets the details regarding a single option. When provided as string, the option is inherited from a parent, allowing the sub-command to expose the same option as the parent. This gives freedom to put options and values either in the parent or in the descendant command, providing flexibility.
This is a YAML overview of how to set one option as a hash:
name: «string»
help: «string»
transmit: «boolean»
transmit_exact: «boolean»
getopt: «string»
environment: «string» or 1
default: any value
A few keys inside the hash regard the option itself, like:
name
name of the option. This is not mandatory if
getopt
is present, which gets the name automatically from the first alias of the option itself;help
some help about the option.
transmit
boolean to set whether an option can be easily "inherited" by a sub-command (without the need to put all attributes of the option once again).
transmit_exact
boolean to set whether the option must be spelled exactly to be inherited (no inheritance via a regular expression).
Option Values Collection
The collection is performed thanks to sources, which can be set with the corresponding sources
key or method (depending on the style). App::Easer
comes with several sources for getting configurations from a variety of places, but still leaves the door open to add more customized ones.
Sources are considered with respect to two different ordering methods: their place in the array pointed by key sources
and their priority. The former sets the order in which data from each source is collected, the latter sets the precedence while assembling conflicting data from several different sources (lower priorities means higher precedence).
Each source can be set either as a $locator
(see ahead) or as an array reference with the following structure:
[ $locator, @args ]
The $locator
can be a reference to a sub, which is used as the source itself, or a string that allows getting the source sub to handle the specific source. Strings starting with the +
character are reserved for sources provided by App::Easer::V2
natively.
If $locator
is a plain string, it is possible to set the priority directly inside it with =NN
(e.g. +Default=100
). It's not necessary to set the priority; if missing, it will be assumed to be 10 more than the previous one in the array (with the first item starting at 10). This also means that, by default, the ordering of sources also doubles down as the ordering of precedence.
The @args
part can provide additional arguments to the specific source; its applicability is dependent on the source itself. As the only exception, if the first item of @args
is a hash reference, it will be removed from the array and used to gather additional meta-options used directly by App::Easer
. At the moment, this is an alternative way to set the priority of the specific source using the key priority
. This means that the following examples are equivalent:
# priority in source name, like anywhere else
[ '+FromTrail=90', qw< defaults foo baz > ],
# priority in meta-options first-arguments hash reference
[ '+FromTrail', {priority => 90}, qw< defaults foo baz > ],
It's not necessary to set the sources
explicitly, as by default the following configuration is assumed:
+CmdLine +Environment +Parent=70 +Default=100
where the respective priorities are, in order, 10, 20, 70, and 100.
Sources provided out of the box by App::Easer::V2
are:
+CmdLine
This source gathers options from the command line arguments. It is set using the
getopt
key, according to the rules explained inGetOpt::Long
. The first alias of an option is also set as the option's name in case keyname
is missing.+Environment
This source gets values from environment variables. It is set using the
environment
key, which can be set to either the name of the environment variable (this is case sensitive) or automatically from higher-level configurationenvironment_prefix
and the option's name in case it is set to value1
exactly.+Parent
This source gets values from a parent command (it only applies to sub-commands).
+Default
Get a default value from the
default
sub-key of the option.+JsonFileFromConfig
Get keys/values from a JSON file, whose path is pointed by a key in the collected options. By default this key is
config
. To set a different key, pass this source as an array reference with the source name and the key, like this:[ JsonFileFromConfig => 'jcnf' ]
+JsonFiles
Get keys/values from a few JSON files (it's OK if they do not exist). To set the files to try, pass this source as an array reference:
[ JsonFiles => @paths ]
+FromTrail
Get keys/values from a sub-hash of the already collected options (e.g. after loading them from a configuration file). The trail to the position of the sub-hash is provided like this:
[ FromTrail => qw< topcmd subcmd additional_values > ]
It is possible to set a default value for the option used by JsonFileFromConfig
, as long as the +Default
source is placed before JsonFileFromConfig
. In this case, it's usually necessary to assign a lower priority value to JsonFileFromConfig
to make sure values read from there take precedence over the defaults:
sources => [qw<
+CmdLine=10 +Environment=20 +Parent=30 +Default=100
+JsonFileFromConfig=40
>];
This is the main reason why the priority has been detached from order of appearance.
Accessing Collected Option Values
Assuming the application object is $self
, there are a few methods to get the configurations:
config
my $value = $self->config('foo'); my @values = $self->config(@multiple_keys);
get whatever value was computed after collecting values from all sources and taking the one with the best (i.e. lowest) priority.
config_hash
my $merged_hash = $self->config_hash; my $complete_hash = $self->config_hash(1);
The first form (or any where the only parameter is considered false by Perl) gets the merged form, i.e. where each key has one value associated, based on the priorities set for the sources.
The second form returns a more complicated data structure where the
sequence
key points to an array reference containing all details about data gathering. Explanation of this data structure is beyond the scope of this manual page.The second form cam be used in case the provided mechanism of prioritization is not sufficient.
residual_args
my @args = $self->residual_args;
Get all arguments from the command line that were not parsed (and hence left for a sub-command or just unparsed).
MIXED STUFF
Managing help as a command-line option
To get help
about a command, App::Easer::V2 provides a help
sub-command out of the box most of the times. The exception is for leaf commands, which do not have sub-commands.
This is not a big deal with hierarchical applications, because it's possible to invoke the help
sub-command of the parent command and pass the name of the sub-command we need help with:
# print help about `topcmd`
$ topcmd help
# print help about `subcmd` under `topcmd`
$ topcmd help subcmd
On the other hand, for non-hierarchical applications, the only available command is also a leaf and this hinders getting a meaningful, auto-generated help text off the shelf.
In this case, it's possible to include an option for getting help, like this:
my $app = {
options => [
{
getopt => 'help|h!',
help => 'print help on the command',
},
...
Then, inside the execute
sub, it's possible to run the help
sub-command explicitly:
sub execute ($self) {
return $self->run_help if $self->config('help');
# ... normal code for "execute"
# ...
}
BUGS AND LIMITATIONS
Minimum perl version 5.24.
Report bugs through GitHub (patches welcome) at https://github.com/polettix/App-Easer.
AUTHOR
Flavio Poletti <flavio@polettix.it>
COPYRIGHT AND LICENSE
Copyright 2021 by Flavio Poletti <flavio@polettix.it>
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.