The London Perl and Raku Workshop takes place on 26th Oct 2024. If your company depends on Perl, please consider sponsoring and/or attending.

NAME

CLI::Framework::Command - CLIF Command superclass

SYNOPSIS

    # Define commands and subcommands for use in a CLIF application...
    # (placing package files with this content in the command search path for
    # a CLIF app will make the commands available to the application)

    # Command:
    package My::Example::Command;
    use base qw( CLI::Framework::Command );
    sub usage_text { ... }
    sub notify { ... }
    1;

    # Sub-command:
    package My::Example::Subcommand;
    use base qw( My::Example::Command );
    sub usage_text { ... }
    sub run { ... }
    1;

    # Sub-sub-command:
    package My::Example:SubSubcommand;
    use base qw( My::Example::Subcommand );
    sub usage_text { ... }
    sub run { ... }
    1;

    ...

DESCRIPTION

CLI::Framework::Command (command class for use with CLI::Framework::Application) is the base class for CLIF commands. All CLIF commands should inherit from this class.

CONCEPTS

subcommands

Commands can have "subcommands," which are also objects of this class. Subcommands can, in turn, have their own subcommands, and this pattern repeats recursively.

NOTE that in this documentation, the term "command" may be used to refer to both commands and subcommands.

METHODS: OBJECT CONSTRUCTION

manufacture

    # (manufacture MyApp::Command::Go)
    my $go = CLI::Framework::Command->manufacture(
        command_search_path => "MyApp/Command", command => 'go'
    );

    # (manufacture MyApp::Command::Go::Fast)
    $go->manufacture( command => 'fast' );

CLI::Framework::Command is an abstract factory; this is the factory method that constructs and returns an object of the specific command that is requested. Called as a class method, the named command is constructed and returned. As an object method, the named subcommand is constructed and registered under the main command that manufacture() is being invoked on.

new

    $object = $cli_framework_command_subclass->new() or die "Cannot instantiate $class";

Basic constructor.

METHODS: SESSION DATA

CLIF commands may need to share data with other commands and with their associated application. These methods support those needs.

set_session

    $app->set_session( \%session_data );

Set the entire session from the given hash.

session

    # get a single item from the session...
    $value = $app->session( $key );

    # save a single item in the session...
    $app->session( $key => $value );

    # get the entire session...
    $s = $app->session();

Accessor/mutator for the session

METHODS: COMMAND DISPATCHING

set_default_usage

    $cmd->set_default_usage( $usage_message );

Set the default usage message for the command.

get_default_usage

    $usage_msg = $cmd->get_default_usage();

Get the default usage message for the command. This message is used by usage.

NOTE: get_default_usage() merely retrieves the usage data that has already been set. CLIF only sets the default usage message for a command when processing a run request for the command. Therefore, the default usage message for a command may be empty.

usage

    # Command usage...
    print $cmd->usage();

    # Subcommand usage...
    print $cmd->usage( $subcommand_name, @subcommand_chain );

Attempts to find and return a usage message for a command or subcommand.

If a subcommand is given, returns a usage message for that subcommand. If no subcommand is given or if the subcommand cannot produce a usage message, returns a general usage message for the application.

Logically, here is how the usage message is produced:

  • If registered subcommand(s) are given, attempt to get usage message from a subcommand (NOTE that a sequence of subcommands could be given, e.g. qw(task list completed), which would result in the usage message for final subcommand, completed). If no usage message is defined for the subcommand, the usage message for the command is used instead.

  • If the command has implemented usage_text, its return value is used as the usage message.

  • Finally, if no usage message has been found, the default usage message produced by get_default_usage is returned.

dispatch

    $command->dispatch( $cmd_opts, @args );

For the given command request, perform any applicable validation and initialization with respect to the supplied options $cmd_opts and arguments (@args).

@args may indicate the request for a subcommand:

    { <subcmd> [subcmd-opts] {...} } [subcmd-args]

If a subcommand registered under the indicated command is requested, initialize and dispatch the subcommand with its options [subcmd-opts] and arguments. Otherwise, run the command itself.

This means that a request for a subcommand will result in the run() method of only the deepest-nested subcommand (because dispatch() will keep forwarding to subcommands until the args no longer indicate that a subcommand is requested). Furthermore, the only command that can receive args is the final subcommand in the chain (but all commands in the chain can receive options). However, each command in the chain can affect the execution process through its notify method.

METHODS: COMMAND REGISTRATION

get_registered_command_names

This is an alias for registered_subcommand_names.

registered_subcommand_names

    @registered_subcommands = $cmd->registered_subcommand_names();

Return a list of the currently-registered subcommands.

get_registered_command

This is an alias for get_registered_subcommand.

get_registered_subcommand

    $subcmd_obj = $cmd->get_registered_subcommand('name');

Given the name of a registered subcommand, return a reference to the subcommand object. If the subcommand is not registered, returns undef.

register_command

This is an alias for register_subcommand.

register_subcommand

    $cmd->register_subcommand( $subcmd_obj );

Register $subcmd_obj as a subcommand under master command $cmd.

If $subcmd_obj is not a CLI::Framework::Command, returns undef. Otherwise, returns $subcmd_obj.

NOTE: Subcommand names must be unique. If register_subcommand() is called with a subcommand having the same name as an existing registered subcommand, the existing one will be replaced by the new one.

COMMAND SUBCLASS HOOKS

Just as CLIF Applications have hooks that subclasses can take advantage of, CLIF Commands are able to influence the command dispatch process via several hooks. Subclasses can (and must, in some cases, as noted) override the following methods:

name

Class method that takes no arguments and returns the name of the command. The default implementation of this method uses the normalized base name of the package as the command name, e.g. the command defined by the package My::Application::Command::Xyz would be named 'xyz'.

Subclasses may override this if a different naming scheme is desired.

option_spec

    sub option_spec {
        (
            [ "verbose|v"   => "be verbose"         ],
            [ "logfile=s"   => "path to log file"   ],
        )
    }

This method should return an option specification as expected by the Getopt::Long::Descriptive function describe_options . The option specification defines what options are allowed and recognized by the command.

Subclasses should override this method if commands accept options (otherwise, the command will not recognize any options).

subcommand_alias

    sub subcommand_alias {
        rm  => 'remove',
        new => 'create',
        j   => 'jump',
        r   => 'run',
    }

Subcommands can have aliases to support shorthand versions of subcommand names.

Subclasses should override this method if subcommand aliases are desired. Otherwise, the commands will only be recognized by their full names.

validate

To provide strict validation of a command request, a subclass may override this method. Otherwise, validation is skipped.

validate is called during command dispatch as follows:

    $cmd->validate( $cmd_opts, @args );

$cmd_opts is an options hash with received command options as keys and their values as hash values.

@args is a list of received command arguments.

validate is expected to throw an exception if validation fails. This allows your validation routine to provide a context-specific failure message.

NOTE that Getop::Long::Descriptive performs some validation of its own based on the option_spec. However, validate allows more flexibility in validating command options and also allows validation of arguments.

notify

If a request for a subcommand is received, the master command itself does not run(). Instead, its notify() method is called. This gives the master command a chance to act before the subcommand is run.

The <notify> method is called as follows:

    $cmd->notify( $subcommand, $cmd_opts, @args );

$subcommand is the subcommand object.

$cmd_opts is the options hash for the subcommand.

@args is the argument list for the subcommand.

usage_text

If implemented, this method should simply return a string containing usage information for the command. It is used automatically to provide context-specific help.

Implementing this method is optional. See usage for details on how usage information is generated within the context of a CLIF application.

run

This method is responsible for the main execution of the command. It is called as follows:

    $output = $cmd->run( $cmd_opts, @args )

$cmd_opts is a pre-validated options hash with command options as keys and their values as hash values.

@args is a list of the command arguments.

The default implementation of this method simply calls usage to show help information for the command. Therefore, subclasses will usually override run() (Occasionally, it is useful to have a command that does little or nothing on its own but has subcommands that define the real behavior. In such relatively uncommon cases, it may make sense not to override run()).

If an error occurs during the execution of a command via its run method, the run method code should throw an exception. The exception will be caught and handled appropriately by CLIF.

The return value of the run method is treated as data to be output by the render method in your CLIF Application class. Note that nothing should be printed directly. Also note that if no output is produced, the run method should return undef or empty string.

SUBCLASSING

Inheriting from CLI::Framework::Command to produce new commands is almost as easy as implementing the purely abstract methods in "COMMAND SUBCLASS HOOKS" and overriding the others as necessary for your new command class. However, there are a few additional details to be aware of...

METACOMMANDS

CLI::Framework::Command::Meta - Class defining application-aware commands.

This class is a subclass of CLI::Framework::Command. It defines "metacommands", commands that are application-aware (and thus, implicitly aware of all other commands registered within the application). Metacommands have methods that set and retrieve the application within which they are running. This class exists as a separate class because, with few exceptions, commands should be independent of the application they are associated with and should not affect that application. Metacommands represent the exception to that rule.

app

    $app = $command->app();

Return the application object associated with a command object.

set_app

    $command->set_app( $app );

Set the application object associated with a command object.

DIAGNOSTICS

Missing required param 'command'

manufacture requires a named parameter command, which specifies the name of the requested command.

Error: failed to require() subcommand from package file '<file path>'

manufacture failed when trying to require() a subcommand (a package located in a directory named after the master command).

Error: failed to instantiate subcommand '<class>' via method new()

Object construction for the subcommand <class> (whose package has already been require()d) was unsuccessful.

Must specify 'command_search_path' for command construction

manufacture requires the command_search_path parameter when called as a class method.

Error: failed to require() base command from package file '<file path>'

manufacture failed when trying to require() a "master command."

Error: Cannot instantiate class '<class>' via method new()

Object construction for the "master command" <class> was unsuccessful.

CONFIGURATION & ENVIRONMENT

When called as an object method on an existing Command object "X", manufacture looks for the named subcommand in the directory path X:

    # Where $x isa X...
    $x->manufacture( command => 'foo' );
    # ...CLIF will search for X/Foo.pm

So remember that subcommands should be given names that explicitly convey their class hierarchy (e.g. subcommand of Do::Something should be Do::Something::Now and not Some::Other::Now), and located as such on the filesystem.

DEPENDENCIES

Carp

Getopt::Long::Descriptive

Class::ISA

File::Spec

Class::Inspector

CLI::Framework::Exceptions

SEE ALSO

CLI::Framework::Application

CLI::Framework::Quickstart

CLI::Framework::Tutorial

LICENSE AND COPYRIGHT

Copyright (c) 2009 Karl Erisman (karl.erisman@icainformatics.com), ICA Informatics. All rights reserved.

This is free software; you can redistribute it and/or modify it under the same terms as Perl itself. See perlartistic.

AUTHOR

Karl Erisman (kerisman@cpan.org)