App-Easer

 view release on metacpan or  search on metacpan

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

- 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 => {

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


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 => {

lib/App/Easer/V1.pm  view on Meta::CPAN

      next
        unless grep { $_ eq $name }
        ($command->{supports} //= [$child])->@*;
      return $child;
   } ## end for my $child (get_children...)
   return;
} ## end sub get_child

sub stock_ChildrenByPrefix ($self, $spec, @prefixes) {
   require File::Spec;
   my @expanded_inc = map {
      my ($v, $dirs) = File::Spec->splitpath($_, 'no-file');
      [$v, File::Spec->splitdir($dirs)];
   } @INC;
   my %seen;
   return map {
      my @parts = split m{::}mxs, $_ . 'x';
      substr(my $bprefix = pop @parts, -1, 1, '');
      map {
         my ($v, @dirs) = $_->@*;
         my $dirs = File::Spec->catdir(@dirs, @parts);

lib/App/Easer/V1.pm  view on Meta::CPAN

               substr(my $lastpart = $_, -3, 3, '');
               join '::', @parts, $lastpart;
            } grep {
               my $path = File::Spec->catpath($v, $dirs, $_);
               (-e $path && ! -d $path)
               && substr($_, 0, length($bprefix)) eq $bprefix
               && substr($_, -3, 3) eq '.pm'
            } readdir $dh;
         }
         else { () }
      } @expanded_inc;
   } @prefixes;
}

sub expand_children ($self, $spec, $child_spec) {
   return $child_spec unless ref($child_spec) eq 'ARRAY';
   my ($exe, @args) = $child_spec->@*;
   return $self->{factory}->($exe, 'children')->($self, $spec, @args);
}

sub get_children ($self, $spec, $expand = 1) {
   return if $spec->{leaf};
   return if exists($spec->{children}) && !$spec->{children};
   my @children = ($spec->{children} // [])->@*;

   # set auto-leaves as 1 by default, new in 0.007002
   $self->{application}{configuration}{'auto-leaves'} = 1
      unless exists $self->{application}{configuration}{'auto-leaves'};

   return
     if $self->{application}{configuration}{'auto-leaves'}
     && @children == 0;    # no auto-children for leaves under auto-leaves

   # skip expansion if $expand is false (default is expand)
   @children = map { expand_children($self, $spec, $_) } @children
      if $expand;

   my @auto =
     exists $self->{application}{configuration}{'auto-children'}
     ? (($self->{application}{configuration}{'auto-children'} // [])->@*)
     : (qw< help commands >);
   if (exists $spec->{'no-auto'}) {
      if (ref $spec->{'no-auto'}) {
         my %no = map { $_ => 1 } $spec->{'no-auto'}->@*;
         @auto = grep { !$no{$_} } @auto;
      }

lib/App/Easer/V1.pod  view on Meta::CPAN

   prefixes:
      - '::' : 'What::Ever::'
      - ':' :  'My::App::'

Otherwise, the I<unordered> nature of Perl hashes would risk that the
expansion associated to C<:> is tried first, spoiling the result and
making it unpredictable.

By default, the C<+> character prefix is associated to a mapping into
functions in C<App::Easer::V1> starting with C<stock_>. As an example, the
string C<+CmdLine> is expanded into C<App::Easer::V1::stock_CmdLine>, which
happens to be an existing function (used in parsing command-line
options). It is possible to suppress this expansion by setting a mapping
from C<+> to C<+> in the C<prefixes>, although this will deviate from
the normal working of C<App::Easer::V1>.

=head2 Configuration Parsing Customization

   configuration:
      name:      «string»
      collect:   «executable»

lib/App/Easer/V1.pod  view on Meta::CPAN

=head2 commandline_help

=head2 commit_configuration

=head2 default_getopt_config

=head2 env_namer

=head2 execute

=head2 expand_children

=head2 stock_factory

   # just the sub
   $subref = factory(sub {});

   # eval it - note the initial space in the string
   $subref = factory(' sub {}');

   # Expand the '+', by default with 'App::Easer::V1#stock_'

lib/App/Easer/V1.pod  view on Meta::CPAN


is the default name of a sub to look for in the selected package;

=item * C<$opts>

is a hash reference with additional options, e.g. a C<prefixes> sub-hash or
sub-array mapping string prefixes to expaned ones (see below).

=back

When C<$executable> is a string, it is first I<expanded> according to the
available prefixes in C<< $opts->{prefixes} >>. This contains mapping from
prefixes to expanded versions of those prefixes; it can be either a hash
reference with the mappings, or an array of those hash references (this
allows setting the order to use for doing the expanion, e.g. making sure
that C<:::> is attempted before C<:>, should both be possible).

By default, prefix C<+> is expanded with C<App::Easer::V1::>; e.g. the
input executor C<+CmdLine> becomes C<App::Easer::V1::CmdLine>. It is
possible to change this or disable it (disabling can be achieved by
providing a mapping from C<+> to C<+>, although this will probably make
loading of the package fail in a later stage).

After this expansion of the prefix, if any, the string in C<$executor> is
split into two parts, based on the character C<#>. What comes before is a
I<package> name, what comes after is a I<subroutine> name (defaulting to
C<$default_subname>).

lib/App/Easer/V2.pm  view on Meta::CPAN

      while (defined(my $parent = $retval->child)) {
         $retval = $parent;
      }
      $slot->{leaf} = $retval;
      weaken($slot->{leaf});
   }
   return $slot->{leaf};
}


# 2024-08-27 expand to allow hashref in addition to arrayref
# backwards-compatibility contract is that overriding this function allows
# returning the list of sources to use, which might be composed of a single
# hashref...
sub sources ($self, @new) {
   my $r;
   my $slot = $self->slot;
   if (@new) { # setter + getter
      $r = $slot->{sources} = $new[0];
   }
   else {   # getter only, set default if *nothing* has been set yet

lib/App/Easer/V2.pm  view on Meta::CPAN

} ## end sub find_child ($self)

# get the list of children. This only gives back a list of "hints" that
# can be turned into instances via inflate_children. In this case, it's
# module names
sub list_children ($self) {
   my @children = $self->children;

   # handle auto-loading of children from modules in @INC via prefixes
   require File::Spec;
   my @expanded_inc = map {
      my ($v, $dirs) = File::Spec->splitpath($_, 'no-file');
      [$v, File::Spec->splitdir($dirs)];
   } @INC;
   my %seen;
   my @autoloaded_children = map {
      my @parts = split m{::}mxs, $_ . 'x';
      substr(my $bprefix = pop @parts, -1, 1, '');
      map {
         my ($v, @dirs) = $_->@*;
         my $dirs = File::Spec->catdir(@dirs, @parts);

lib/App/Easer/V2.pm  view on Meta::CPAN

               substr(my $lastpart = $_, -3, 3, '');
               join '::', @parts, $lastpart;
              } grep {
               my $path = File::Spec->catpath($v, $dirs, $_);
               (-e $path && !-d $path)
                 && substr($_, 0,  length($bprefix)) eq $bprefix
                 && substr($_, -3, 3) eq '.pm'
              } sort { $a cmp $b } readdir $dh;
         } ## end if (opendir my $dh, File::Spec...)
         else { () }
      } @expanded_inc;
   } $self->children_prefixes;
   push @autoloaded_children, map {
      my $prefix = $_;
      my $prefix_length = length($prefix);
      grep { !$seen{$_}++ }
        grep {
         (substr($_, 0, length $prefix) eq $prefix)
            && (index($_, ':', $prefix_length) < 0);
        } keys %App::Easer::V2::registered;
   } $self->children_prefixes;

lib/App/Easer/V2.pod  view on Meta::CPAN

=head2 Option Values Collection (C<sources>)

The collection is performed thanks to I<sources>, which can be set with
the corresponding C<sources> key or method (depending on the style).
C<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.

Up to version C<2.007001> included, the C<sources> key could only point
to an I<array reference> holding a list of sources. After that release,
it has been expanded to I<also> accept a I<hash reference>, allowing for
a new and more sophisticated handling of option values collection. In
either case, anyway, processing arrives at a point where there is a
I<list of sources> to be processed as described below; using the I<array
ref> keeps backwards compatibility with the old behaviour. See
L</Sources as hash reference> for additional details on the new way.

Sources are I<considered> with respect to two different ordering
methods: their place in the array pointed by key C<sources> and their
I<priority>. The former sets the order in which data from each source is
collected, the latter sets the precedence while assembling conflicting



( run in 2.050 seconds using v1.01-cache-2.11-cpan-97f6503c9c8 )