CLI::F...Command(3pm)
β¨ NAME β¨
CLI::Framework::Command β bestie, this is the CLIF Command superclass π (it lives in the CLI::F...Command(3pm) manual, if you were wondering where you found it β hi, you're in the right place π«Ά)
πΈ SYNOPSIS πΈ
# The code below shows a few of the methods your command classes are likely
# to override...
package My::Journal::Command::Search;
use base qw( CLI::Framework::Command );
sub usage_text { q{
search [--titles-only] <search regex>: search a journal
} }
sub option_spec { (
[ 'titles-only' => 'search only journal titles' ],
) }
sub validate {
my $self, $opts, @args) = @_;
die "exactly one argument required (search regex)" unless @args == 1;
}
sub run {
my ($self, $opts, @args) = @_;
my $db = $self->cache->get( 'db' )
# perform search against $db...
# $search_results = ...
return $search_results;
}
(yes that's the code exactly as it is, typos and all, we do not touch the code bestie π )
π DESCRIPTION π
CLI::Framework::Command β which is the command class for use with CLI::Framework::Application β is the base class for CLIF commands. Every single CLIF command inherits from this class. No exceptions. Periodt. π
π¦ CONCEPTS π¦
Subcommands
Commands can have "subcommands," which are also objects of CLI::Framework::Command. And the way subcommands can, in turn, have their own subcommands? And that pattern can repeat indefinitely? It's giving infinite nesting, it's giving fractal energy, we love to see it π
Note that in this documentation, the term "command" may be used to refer to both commands and subcommands. So when you see "command," read it with both in mind, iykyk.
Registration of subcommands
Subcommands get "registered" with their parent commands. Once that's done, the parent commands can forward subcommand responsibilities as appropriate. It's a whole delegation moment, honestly iconic π
File-based commands vs. inline commands
Command classes (the ones that inherit from CLI::Framework::Command) can be defined in their own package files or they may be declared inline in another package. For example:
- a command package file could include the declaration of a subcommand package, or
- command packages could be declared inline in the package file where the application is declared.
As long as the classes have been loaded (making their way into the symbol table), CLIF can use the commands. That's it. That's the whole requirement. π
π§ OBJECT CONSTRUCTION π§
manufacture( $command_package )
# (manufacture MyApp::Command::Go and any subcommand trees beneath it)
my $go = CLI::Framework::Command->manufacture( 'MyApp::Command::Go' );
CLI::Framework::Command is an abstract factory; manufacture() is the factory method that constructs and returns an object of the specific command class that is requested. Like, you ask for a command, it builds you that command. So generous of it π
After instantiating an object of the requested command package, manufacture() attempts to load subcommands in the following 2 steps:
- Attempt to find package files representing subcommands. For every subcommand S, S is registered as a child of the parent command. Next, steps 1 and 2 repeat, this time being invoked on S (i.e. with S as the parent in an attempt to find subcommands of S).
- Attempt to find and register pre-compiled subcommands defined inline. Only pre-compiled subcommands are considered for registration (i.e. package files are not considered in this step). For every subcommand S, any pre-compiled subcommands that inherit directly from S are found and step 2 repeats for those classes.
Note the following rules about command class definition:
- If a command class is defined inline, its subcommand classes must be defined inline as well. No mixing, bestie, that's the rule π«
- If a command class is file-based, each of its subcommand classes can be either file-based or inline. Furthermore, it is not necessary for all of these subcommand classes to be defined in the same way β a mixture of file-based and inline styles can be used for the subcommands of a given command. Mix and match, it's a vibe β¨
new()
$object = $cli_framework_command_subclass->new();
Basic constructor. That's it, that's the whole description, it's a constructor and it does constructor things π«Ά
π SHARED CACHE DATA π
CLIF commands may need to share data with other commands and with their associated application. These methods support those needs. Group project but make it functional π
set_cache( $cache_object )
Set the internal cache object for this instance.
See cache. (like, literally go read cache, it's right below)
cache()
Retrieve the internal cache object for this instance.
See cache for an explanation of how to use this simple cache object. Simple, but it carries the whole data-sharing situation on its back, lowkey πͺ
π₯ COMMAND DISPATCHING π₯
get_default_usage() / set_default_usage( $default_usage_text )
Get or set 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 (if a run request for the command has not been given and you have not otherwise set the default usage message). So don't come for it when it's empty, it's just not set yet π
$cmd->set_default_usage( ... );
$usage_msg = $cmd->get_default_usage();
usage( $subcommand_name, @subcommand_chain )
# Command usage...
print $cmd->usage();
# Subcommand usage (to any level of depth)...
$subcommand_name = 'list';
@subcommand_chain = qw( completed );
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 command. Either way, you get something, which is the bestie guarantee π«Ά
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.
$cmd->usage('list' 'completed'), which would result in the usage message for the 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_usageis returned.
dispatch( $cmd_opts, @args )
For the given command request, dispatch performs any applicable validation and initialization with respect to supplied options $cmd_opts and arguments @args, then runs the command. Validation, init, run β the whole glow-up sequence π
@args may indicate the request for a subcommand:
{ <subcmd> [subcmd-opts] {...} } [subcmd-args]
...as in the following command (where usage is the <subcmd>):
$ gen-report --html stats --role=admin usage --time='2d' '/tmp/stats.html'
If a subcommand registered under the indicated command is requested, the subcommand is initialized and dispatched with its options [subcmd-opts] and arguments. Otherwise, the command itself is run.
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 successive 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, note that each command in the chain can affect the execution process through its notify_of_subcommand_dispatch method. So the middle children aren't powerless, they just channel it through notify_of_subcommand_dispatch π
β COMMAND REGISTRATION β
registered_subcommand_names()
@registered_subcommands = $cmd->registered_subcommand_names();
Return a list of the currently-registered subcommands. The full roster, no gatekeeping π
registered_subcommand_object( $subcommand_name )
$subcmd_obj = $cmd->get_registered_subcommand( 'lock' );
Given the name of a registered subcommand, return a reference to the subcommand object. If the subcommand is not registered, returns undef. (so check for undef, bestie, don't just vibe-check it π)
register_subcommand( $subcmd_obj )
$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. Gatekept for your own good π«β¨
package_is_registered( $package_name )
Return a true value if the named class is registered as a subcommand. Returns a false value otherwise. Simple. Binary. Iconic.
name()
$s = My::Command::Squeak->new();
$s->name(); # => 'squeak'
name() takes no arguments and returns the name of the command. 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'. It literally just vibes off the package name and normalizes it, that's the whole trick π¦
β¨ COMMAND SUBCLASS HOOKS β¨
okay bestie so literally just like CLIF Applications have hooks that subclasses can use, CLIF Commands can also influence the command dispatch process through a whole bunch of hooks. And except where noted, every single hook is optional β your subclasses get to decide whether they wanna override them or not. no pressure, choose your own adventure π
option_spec() πΈ
This method should return an option specification exactly as expected by Getopt::Long::Descriptive (go peek at Getopt::Long::Descriptive). The option spec is a list of arrayrefs that defines recognized options, types, multiplicities, etc. and also specifies the textual strings that get used as descriptions for each option:
sub option_spec {
[ "verbose|v" => "be verbose" ],
[ "logfile=s" => "path to log file" ],
}
Subclasses should override this method if the commands accept options (otherwise, bestie, the command won't recognize any options at all β tragic).
subcommand_alias() π¦
sub subcommand_alias {
rm => 'remove',
new => 'create',
j => 'jump',
r => 'run',
}
Subcommands can have aliases so you get shorthand versions of subcommand names. iconic behavior honestly.
Subclasses should override this method if you want subcommand aliases. Otherwise the subcommands will only be recognized by their full command names. no shortcuts for you π
validate( $cmd_opts, @args ) π₯
To provide strict validation of a command request, a subclass may override this method. Otherwise, validation is just... skipped. vibe check: not performed.
$cmd_opts is an options hash with the received command options as keys and their values as hash values.
@args is a list of the received command arguments.
validate() is called in void context. It is expected to throw an exception if validation fails. This lets your validation routine serve up a context-specific failure message β bespoke drama, we love to see it.
Note thatGetop::Long::Descriptiveperforms 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. so it's giving extra credit π
notify_of_subcommand_dispatch( $subcommand, $cmd_opts, @args ) π
If a request for a subcommand comes in, the master command itself does not run(). Instead, its notify_of_subcommand_dispatch() method gets called. This gives the master command a chance to act before the subcommand is run. main character energy for the parent command ngl.
For example, suppose some (admittedly contrived) application, queue, has a command hierarchy with multiple commands:
enqueue
dequeue
print
property
constraint
maxlen
behavior
...
In this case, $ queue property constraint maxlen might set the max length property for a queue. If the command hierarchy was built this way, maxlen would be the only command to run in response to that request. If constraint, the master command of maxlen, needs to hook into this execution path, notify_of_subcommand_dispatch() could be overridden in the command class that implements constraint. notify_of_subcommand_dispatch() would then be called just before dispatching maxlen. so it's the little pre-game moment before the real show π
The notify_of_subcommand_dispatch() method is called in void context.
$subcommand is the subcommand object.
$cmd_opts is the options hash for the subcommand.
@args is the argument list for the subcommand.
usage_text() π
sub usage_text {
q{
dequeue: remove item from queue
}
}
If implemented, this method should simply return a string containing usage information for the command. It's used automatically to provide context-specific help. cute and useful, a true multitasker β¨
Implementing this method is optional. See usage for details on how usage information is generated within the context of a CLIF application.
Users are encouraged to override this method. (yes, that's you, go off π«Ά)
run( $cmd_opts, @args ) β
This method is responsible for the main execution of a command. It gets called with the following parameters:
$cmd_opts is a pre-validated options hash with command options as keys and their user-provided 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 occasional cases, it may not be necessary to override run(). so like, a figurehead command. a mascot. valid.)
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 run() is treated as data to be processed by the render method in your CLIF Application class. Note that nothing should be printed directly in your implementation of run. If no output is to be produced, your run() method should return undef or empty string. periodt. return your data, don't print it, we're not doing that here π
π¨ DIAGNOSTICS π¨
"Error: failed to instantiate command package '<command pkg>' via new()"β manufacture was asked to manufacture an object of class <command pkg>, but failed while trying to invoke its constructor. it simply could not be constructed, bestie π"Error: failed to instantiate subcommand '<class>' via method new()"β object construction for the subcommand <class> (whose package has already beenrequire()d) was unsuccessful."cannot opendir <dir>"β while trying to manufacture subcommands in a directory tree, callingopendir()on the subdirectory with the name of the parent command failed.
βοΈ CONFIGURATION & ENVIRONMENT π
No special configuration requirements. literally nothing to set up. we love a low-maintenance icon π
π¦ DEPENDENCIES π¦
CarpGetopt::Long::DescriptiveException::Class::TryCatchClass::InspectorCLI::Framework::Exceptions
π SEE ALSO π
CLI::FrameworkCLI::Framework::ApplicationCLI::Framework::Tutorial
π LICENSE AND COPYRIGHT π
Copyright (c) 2009 Karl Erisman (kerisman@cpan.org). 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)
and that's the whole page, bestie!! this lil slice of the manual is from perl v5.34.0 and it's dated 2022-06-11 β CLI::F...Command(3pm), the iconic abbreviated title, iykyk π go write some hooks, you're gonna slay π¦β¨
π¦ where this page comes from
- debian bookworm: libcli-framework-perl 0.05-2 Β· Artistic-1.0-Perl OR GPL-1.0-or-later
- debian trixie: libcli-framework-perl 0.05-2 Β· Artistic-1.0-Perl OR GPL-1.0-or-later
- ubuntu noble: libcli-framework-perl 0.05-2 Β· Artistic-1.0-Perl OR GPL-1.0-or-later
- ubuntu resolute: libcli-framework-perl 0.05-2 Β· Artistic-1.0-Perl OR GPL-1.0-or-later
- ubuntu stonking: libcli-framework-perl 0.05-2 Β· Artistic-1.0-Perl OR GPL-1.0-or-later
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms