App-Easer

 view release on metacpan or  search on metacpan

docs/docs/30-commands-hierarchy.md  view on Meta::CPAN

        },
        foo => {
            'no-auto' => '*',
            ...
        },
        bar => {
            'no-auto' => ['help'],
            ...
        }
    },
};
```

In this example:

- the only automatically added child command is `help` (via option
  `auto-children`);
- the `MAIN` command gets the `commands` sub-command too, although
  explicitly and not implicitly;
- the `foo` command gets nothing, because `no-auto` filters out *every*
  implicitly generated sub-command;
- the `bar` command gets nothing as well, because its `no-auto` filters
  out the `help` command, which is also the only one that is set.

## Specification from module

By default, all specifications for (sub-)commands are supposed to be
contained in the input hash/JSON specification for the whole
application. It is possible, though, to put the specification of one or
more sub-commands inside a different module, to keep the specification
and the implementation close to each other, setting the configuration
`specfetch` to `+SpecFromHashOrModule`:

```perl
my $app = {
    configuration => { specfetch => '+SpecFromHashOrModule' },
    commands => {
        MAIN => {
            children => [qw< MyApp::Foo MyApp::Bar#specification baz  >],
            ...
        },
        baz => { ... },
    }
};
```

In the example above:

- commands `MAIN` and `baz` are defined directly in the hash, like it
  happens by default;
- the definition for sub-command `MyApp::Foo` can be found in module
  `MyApp::Foo`, calling its function `spec` that is supposed to return a
  hash reference with the specification of the command. The name `spec`
  is a default, conventional value;
- the definition for sub-command `MyApp::Bar#specification` can be found
  in module `MyApp::Bar`, calling its function `specification`. In this
  case we have an explicit indication of which function should be called
  to get the hash reference with the sub-command specification.

When `specfetch` is set to `+SpecFromHashOrModule`, the child name is
expanded as described above only if the specific string is missing as a
key inside the `commands` sub hash. In other terms, in the following
example no external module will be loaded to figure out the
specification for child `Some::Foo#whatever`, because the specification
is already available in `commands`:

```perl
my $app = {
    configuration => { specfetch => '+SpecFromHashOrModule' },
    commands => {
        MAIN => {
            children => [qw< Some::Foo#whatever  >],
            ...
        },
        'Some::Foo#whatever' => { ... },
    }
};
```

It might be even adviseable to use this name structure, actually: it
allows starting with a compact application definition, while allowing
for an easy split at a later time if this is the main goal.

## Dispatch: vague relationships

[App::Easer][] supports providing an *executable* associated to key
`dispatch`, in order to completely override the child search mechanism:

```perl
my $app = {
    commands => {
        MAIN => {
            children => [qw< foo bar baz >],
            dispatch => \&random_child,
            ...
        },
        foo => { ... },
        bar => { ... },
        baz => { ... },
    },
};

# ...

sub random_child ($app, $spec, $args) {
    my @children = $spec->{chidren}->@*;
    return $children[rand @children];
}
```

The example above is a bit crude but shows that the
`dispatch`-associated function is supposed to return the name of a
command. The example uses `children` to choose from, but it can actually
be any valid command:

```perl
my $app = {
    commands => {
        MAIN => {
            children => [qw< bar baz >],
            dispatch => sub { return 'foo' }, # not a child, but OK!



( run in 1.467 second using v1.01-cache-2.11-cpan-97f6503c9c8 )