The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.

NAME

App::Chained - Wrapper to sub applications in the Git fashion - No modification to your scripts, modules.

SYNOPSIS

A complete example can be found in test_wrapper.p test_application test_module.pm test_templatel in the distribution.

 package App::Chained::Test ;
 use parent 'App::Chained' ;
 our $VERSION = '0.03' ;
 
 =head1 THIS WRAPPER DOCUMENTATION
 
 This will be automatically extracted as we set the B<help> fields to B<\&App::Chained::get_help_from_pod> 
 
 =cut

 sub run
 {
 my ($invocant, @setup_data) = @_ ;
 
 my $chained_app = 
        App::Chained->new
                (
                help => \&App::Chained::get_help_from_pod, 
                version =>  $VERSION,
                apropos => undef,
                faq => undef,
                getopt_data => [] ;
                
                sub_apps =>
                        {
                        test_application =>
                                {
                                description => 'executable',
                                run =>
                                        sub
                                        {
                                        my ($self, $command, $arguments) =  @_ ;
                                        system './test_application ' . join(' ', @{$arguments}) ;
                                        },
                                ...
                                },
                        },
                        
                @setup_data,
                ) ;
 
 bless $chained_app, $class ;
 
 $chained_app->parse_command_line() ;
 $chained_app->SUPER::run() ;
 }
 
 #--------------------------------------------------------------------------------- 
 
 package main ;
 
 App::Chained::Test->run(command_line_arguments => \@ARGV) ;

DESCRIPTION

This module implements an application front end to other applications. As the git command is a front end to many git-* sub commands

DOCUMENTATION

This module tries to provide the git like front end with the minimum work from you. Your sub commands can be implemented in perl scripts, modules or even applications written in other languages. You will not have to derive your sub commands from a class I define nor will you have to define specific soubrourines/methods in your sub commands. In a word I tried to keep this module as non-intruisive as possible.

Putting a front end to height sub applications took a total of 15 minutes plus another 15 minutes when I decided to have a more advanced command completion. More on completion later.

What you gain

The Wrapper will handle the following options

  • --help

  • --apropos

  • --faq

  • --version

  • --generate_bash_completion

Defining sub commands/applications

 sub_apps =>
  {
  check => # the name of the sub command, it can be an alias
        {
        description => 'does a check', # description
        run => 
          sub
          {
          # a subroutine reference called to run the sub command
          # This is a simple wrapper. You don't have to change your modules or scripts
          # or inherite from any class
                        
          my ($self, $command, $arguments) =  @_ ;
          system 'your_executable ' . join(' ', @{$arguments}) ;
          },
                        
        help => sub {system "your_executable --help"}, # a sub to be run when help required
        apropos => [qw(verify check error test)], # a list of words to match a user apropos query
        
        options => sub{ ...}, # See generate_bash_completion below
        },
  ...
  }
                        

EXAMPLE

App::Requirement::Arch (from version 0.02) defines a front end application ra to quite a few sub commands. Check the source of the ra script for a real life example with sub command completion script.

THIS CLASS USES EXIT!

Some of the default handling will result in this module using exit to return from the application wrapper. I may remove the exit in future versions as I rather dislike the usage of exit in module.

SUBROUTINES/METHODS

new(NAMED_ARGUMENT_LIST)

Create a App::Chained object, refer to the synopsis for a complete example.

Arguments

  • INTERACTION - Lets you redefine how App::Chained displays information to thhe user

  • command_line_arguments - Array reference-

  • help - A sub reference -

    you can also \&App::Chained::get_help_from_pod if you want your help to be extracted from the pod present in your app. The pod will be displayed by perldoc if present in your system or converted by App::Chained.

  • version - A scalar or a Sub reference -

  • apropos - A sub reference -

    if it is not defined, The apropos fields in the sub commands entries are searched for a match

  • faq - A sub reference - called when the user

  • getopt_data - Ans array reference containing

    • A string - a Getopt specification

    • A scalar/array/hash/sub reference according to Getop

    • A string - short description

    • A string - long description

            ['an_option|o=s' => \my $option, 'description', 'long description'],
  • sub_apps - A Hash reference - contains a sub command/application definition

            {
            check =>
                    {
                    description => 'does a check',
                    run =>
                            sub
                            {
                            my ($self, $command, $arguments) =  @_ ;
                            system 'ra_check.pl ' . join(' ', @{$arguments}) ;
                            },
                            
                    help => sub {system "ra_check.pl --help"},
                    apropos => [qw(verify check error test)],
                    options => sub{ ...},
                    },
            },

Returns - An App::Chained object

Exceptions - Dies if an invalid argument is passed

[P]Setup

Helper sub called by new.

[P]CheckOptionNames

Verifies the named options passed to the members of this class. Calls {INTERACTION}{DIE} in case of error.

[P]parse_command_line()

Parses the option passed in the throught the named argument command_line_arguments. It will also handle some of the options directly, eg: --help, --apropos, ...

Arguments - None

Returns - Nothing

$self-{parsed_command}> is set to the command to run.

$self-{command_options}> is set to the options that are to be passed to the command

Exceptions -Dies if an invalid command is passed in the options, warns if the options seem incorrect

[P]get_options_definitions()

Generated an option definition suitable for Getopt::Long. Adding default options is necessary. The added option will be added in $self-{getopt_data}>.

Arguments - None

Returns - a list of tuples

  • first element is a Getopt::Long option defintion

  • second element is a reference to a scalar (or other type) which will store the option value

    Exceptions - None

[P]display_help()

Will use $self-{help}>, that you set during construction, or will inform you if you haven't set the help field.

Arguments - None

Returns - Nothing

Exceptions - None

[P]display_usage()

Will use $self-{usage}>, that you set during construction, or will inform you if you haven't set the help field.

Arguments - None

Returns - Nothing

Exceptions - None

[P]display_command_list()

Will display the list of the sub commands.

Arguments - None

Returns - Nothing

Exceptions - None

[P]get_command_list()

Arguments - None

Returns - A string - the list of sub commands

Exceptions - None

[P]run_help_command(NAMED_ARGUMENT_LIST)

Handle the help command. It will display help for the sub command or for the application if none is given.

 $> my_app help sub_command

Arguments - None

Returns - Nothing

Exceptions Dies if a wrong sub command name is used or if the sub command doesn't define a help sub

[P]run()

Runs the sub command parsed on the command line.

Arguments - None

Returns - Nothing

Exceptions Dies if the sub command run field is improperly set.

[P]generate_bash_completion()

The generated completion is in two parts:

A perl script used to generate the completion (output on stdout) and a shell script that you must source (output on stderr).

 $> my_app -bash 1> my_app_perl_completion.pl 2> my_app_regiter_completion

Direction about how to use the completion scritp is contained in the generated script.

The completion will work for the top application till a command is input on the command line after that the completion is for the command.

command specific options

Your sub commands can define an options field. The field should be set to a subroutine reference that returns a string of options the sub command accepts. The format should be -option_name. One option perl line.

Here is an example of how I added completion to a set sub commands (8 of them). The sub commands do not have a completion script and rely on the wrapper for completion.

I first set the options field:

        {
        description => ...
        run => ...
        ...
        
        options => sub {return `$name --dump_options`},
        }

I am using the sub command itself to generate the options. This way I don't have to maintain the list by hand (which is possible).

Modifying the sub command itself was trivial and very quick. I modified the following code (example in one of thesub commands)

  die 'Error parsing options!'unless 
    GetOptions
      (
      'master_template_file=s' => \$master_template_file,
      'h|help' => \&display_help, 
      ) ;
      

to be

  die 'Error parsing options!'unless 
    GetOptions
        (
        'master_template_file=s' => \$master_template_file,
        'h|help' => \&display_help, 
        
        'dump_options' => 
          sub 
          {
          print join "\n", map {"-$_"} 
              qw(
                master_template_file
                help
                ) ;
          exit(0) ;
          },
        ) ;

Modfying the height or so scripts took only a few minutes.

Noiw I have command completion for all the sub command. Here is an example:

  nadim@naquadim Arch (master)$ ra show -[tab]
  -format                    -include_loaded_from   -master_categories_file                    
  -help                      -include_not_found     -master_template_file
  -include_categories        -include_statistics    -remove_empty_requirement_field_in_categories
  -include_description_data  -include_type          -requirement_fields_filter_file

The show sub command is two order of magnitude easier to use with completion.

Arguments - None

Returns - Nothing - exits with status code 1 after emitting the completion script on stdout

Exceptions - None - Exits the program.

Arguments received from bash:

  • $index - index of the command line argument to complete (starting at '1')

  • $command - a string containing the command name

  • \@argument_list - list of the arguments typed on the command line

You return possible completion you want separated by \n. Return nothing if you want the default bash completion to be run which is possible because of the <-o defaul> passed to the complete command.

Note! You may have to re-run the complete command after you modify your perl script.

[P]display_version()

Displays the version you set through $self-{version}>.

Arguments - None

Returns - Nothing

Exceptions None. Will warn if you forgot to set a version

See xxx.

[P]display_apropos()

Will display matches to the apropos query using $self-{apropos}>, that you set during construction, or will search in the apropos field of the sub commands.

Arguments - None - takes the search string from the --apropos option.

Returns - Nothing

Exceptions - None

[P]display_faq()

Will display an answer to a a faq question using $self-{faq}>, that you set during construction, or will inform you if you haven't set the faq field.

Arguments - None - takes the FAQ query from the --faq option.

Returns - Nothing

Exceptions - None

BUGS AND LIMITATIONS

None so far.

AUTHOR

        Nadim ibn hamouda el Khemir
        CPAN ID: NKH
        mailto: nadim@cpan.org

COPYRIGHT AND LICENSE

Copyright Nadim Khemir 2010.

This program is free software; you can redistribute it and/or modify it under the terms of either:

  • the GNU General Public License as published by the Free Software Foundation; either version 1, or (at your option) any later version, or

  • the Artistic License version 2.0.

SUPPORT

You can find documentation for this module with the perldoc command.

    perldoc App::Chained

You can also look for information at:

SEE ALSO

1 POD Error

The following errors were encountered while parsing the POD:

Around line 581:

You forgot a '=back' before '=head2'