App-Easer

 view release on metacpan or  search on metacpan

docs/docs/40-command-options.md  view on Meta::CPAN

application level, as well as the single-command level. The latter will
take precedence over the former:

```perl
my $app = {
    configuration => {
        sources => '+DefaultSources', # unnecessary, it's the default!
    },
    commands => { # enable a configuration file for the MAIN entry point
        MAIN => {
            sources => [qw< +Default +CmdLine +Environment +Parent
                +JsonFileFromConfig
            >],
            'config-option' => 'config', # unnecessary, default!
            options => [
                {
                    getopt => 'config|c=s',
                    environment => 'GAH_CONFIG_FILE',
                    default => "$HOME/.gah.json",
                    help => 'path to the configuration file',
                }
            ],
            children => [qw< foo bar >]
            ...
        },
        foo => {
            sources => [qw< +Parent >],
            'allow-residual-options' => 1,
        },
        bar => {...},
    },
};
```

In the example above:

- the default is set to... the default, just explicitly so that it's
  clear what's going on. Hence, configurations will be taken from the
  "usual" sources;
- the `MAIN` command overrides the list of sources to also allow for a
  configuration file, which is collected from the `config` option (again
  this is stated explicitly for sake of clarity in this tutorial);
- the `foo` child takes options from the parent command `MAIN` only, and
  allows the rest of the command line to contain options-looking
  arguments. This is useful if `foo` is just a wrapper around an
  external command, and the rest of the command line has to be taken
  verbatim to be passed down the line. Setting `allow-residual-options`
  to a true value in this case is not strictly needed, because we're not
  using the `+CmdLine` option so we're not checking the command line at
  all; anyway, it's good to document this.
- last, the `bar` child uses the defaults set in the main application
  configuration.

## Option values validation

[Getopt::Long][] enables a first coarse validation, by providing input
types for integers, strings and booleans. Sometimes, though, this might
not be sufficient, e.g. if some options are mutually exclusive and
incompatible.

To address this, it is possible to set key `validate` for performing
validation upon the collected options. This can happen at the top
`configuration` level or inside each command's specification.

In the first case, `validate` must point to an *executable* (i.e.
something that can be resolved by [App::Easer][] into a sub) with the
following signature:

```perl
sub validator ($global, $spec, $args) { die 'sorry!' if error(); }
```

The passed parameters are:

- `$global` the global application object;
- `$spec` the specification for the command under analysis;
- `$args` any command-line arguments residual up to this point.

The *latest* configuration to be checked is available in
`$global->{configs}[-1]` (not exactly an easy place...):

```perl
sub validator ($global, $spec, $args) {
   require Params::Validate;
   Params::Validate::validate(
      $self->{configs}[-1]->%*,  # configuration to validate
      {...}                      # hash for Params::Validate
   );
}
```

The interface above is not officially documented and is subject to
change, e.g. to make it easier to do the validation without having to
fiddle with the internals of `$global`.

When the `validate` key is set in a command's specification, it can
either be an *executable* like described above, or a hash reference. In
this latter case, [Params::Validate][] is used to validate the
configuration against that hash reference. This particular approach can
be considered stable and not subject to changes in the future.


## Configuration file from another option

It's possible to expand the options values gathering with loading them
from a JSON file, whose path is provided among the available options.
This allows e.g. to add a command-line option `-c|--config` to point to
a file with further values.

The indication to also look for a configuration file is usually best
placed at the end of the list:

```perl
my $app = {
    configuration => {
        sources => [qw< +Default +CmdLine +Environment +Parent
            +JsonFileFromConfig
        >],
        ...
    },
    ...
};
```

By default, source `+JsonFileFromConfig` will look into the built
configuration (i.e. coming from all previus sources) for an option
called exactly `config`, and use that as a path to the configuration
file to load.

> This is the exact reason why [The Default source](#the-default-source)
> works differently. It allows setting a default value for this option,
> so that it's considered at the right time if it's not provided on the
> command line, in the environment or from a parent's configuration.

It is possible to set a different configuration key to be used to gather
the path, though, through the command's configuration key
`config-option`. Example:

```perl
my $app = {
    configuration => {
        sources => [qw< +Default +CmdLine +Environment +Parent
            +JsonFileFromConfig
        >],
        ...
    },
    commands => {
        MAIN => {
            'config-option' => 'cnfile',
            options => [
                {
                    getopt => 'cnfile|C=s',
                    environment => 'MAH_CONFIGURATION_FILE',
                    default => "$HOME/.mah-app.json",
                    help => 'path to a JSON configuration file',
                },
                ...
            ],



( run in 0.640 second using v1.01-cache-2.11-cpan-39bf76dae61 )