MooX::Cmd(3pm)
π NAME π
MooX::Cmd β the way to make command-organized CLI apps in a Moo style, bestie. Like, actually easy. β¨
(It lives in the User Contributed Perl Documentation section, it's a 3pm page, and yes this is the whole glow-up. iykyk.)
π SYNOPSIS π
okay so here's the whole vibe in one block, no cap:
package MyApp;
use Moo;
use MooX::Cmd;
sub execute {
my ( $self, $args_ref, $chain_ref ) = @_;
my @extra_argv = @{$args_ref};
my @chain = @{$chain_ref} # in this case only ( $myapp )
# where $myapp == $self
}
1;
package MyApp::Cmd::Command;
# for "myapp command"
use Moo;
use MooX::Cmd;
# gets executed on "myapp command" but not on "myapp command command"
# there MyApp::Cmd::Command still gets instantiated and for the chain
sub execute {
my ( $self, $args_ref, $chain_ref ) = @_;
my @chain = @{$chain_ref} # in this case ( $myapp, $myapp_cmd_command )
# where $myapp_cmd_command == $self
}
1;
package MyApp::Cmd::Command::Cmd::Command;
# for "myapp command command"
use Moo;
use MooX::Cmd;
# gets executed on "myapp command command" and will not get instantiated
# on "myapp command" cause it doesnt appear in the chain there
sub execute {
my ( $self, $args_ref, $chain_ref ) = @_;
my @chain = @{$chain_ref} # in this case ( $myapp, $myapp_cmd_command,
# $myapp_cmd_command_cmd_command )
# where $myapp_cmd_command_cmd_command == $self
}
package MyZapp;
use Moo;
use MooX::Cmd execute_from_new => 0;
sub execute {
my ( $self ) = @_;
my @extra_argv = @{$self->command_args};
my @chain = @{$self->command_chain} # in this case only ( $myzapp )
# where $myzapp == $self
}
1;
package MyZapp::Cmd::Command;
# for "myapp command"
use Moo;
use MooX::Cmd execute_from_new => 0;
# gets executed on "myapp command" but not on "myapp command command"
# there MyApp::Cmd::Command still gets instantiated and for the chain
sub execute {
my ( $self ) = @_;
my @extra_argv = @{$self->command_args};
my @chain = @{$self->command_chain} # in this case ( $myzapp, $myzapp_cmd_command )
# where $myzapp_cmd_command == $self
}
1;
package main;
use MyApp;
MyZapp->new_with_cmd->execute();
MyApp->new_with_cmd;
1;
like. look at that. iconic. π
β¨ DESCRIPTION β¨
MooX::Cmd makes writing command line utilities so much easier β it handles commands and subcommands and subsubcommands and on and on, forever basically. π¦
These commands form a tree, and that tree is mirrored in the package structure. And the way it works? On invocation, every single command along the path through the tree β starting from the toplevel command all the way down to the most specific one β gets instanciated. yes, all of them, even the ones whose execute doesn't run. she contains multitudes. π
Every command needs an execute function, and it takes three parameters:
selfβ a reference to the specific MooX::Cmd object that is executing. that's you, babe.argsβ an ArrayRef of arguments passed toself. this only encompasses arguments of the most specific (read: right-most) command. so like, the innermost one. the main character. πchainβ an ArrayRef ofMooX::Cmds along the tree path, as specified on the command line.
β οΈ Note: only the execute function of the most specific command is executed. everyone else is just... there for the vibes (and for the chain). π«Ά
πΈ MooX::Cmd Attributes πΈ
Each command has some attributes set by MooX::Cmd during initialization:
command_chainβ same as thechainargument toexecute.command_nameβ TODOcommand_commandsβ TODOcommand_argsβ TODOcommand_baseβ TODO
(yes bestie, those are literally TODO. not me being lazy, that's just what the page says. π)
π Examples π
π A Single Toplevel Command π
#!/usr/bin/env perl
package MyApp;
use Moo;
use MooX::Cmd;
sub execute {
my ($self,$args,$chain) = @_;
printf("%s.execute(\$self,[%s],[%s])\n",
ref($self), # which command is executing?
join(", ", @$args ), # what where the arguments?
join(", ", map { ref } @$chain) # what's in the command chain?
);
}
package main;
MyApp->new_with_cmd();
Some sample invocations:
$ ./MyApp.pl
MyApp.execute($self,[],[MyApp])
$./MyApp.pl --opt1
MyApp.execute($self,[--opt1],[MyApp])
$ ./MyApp.pl --opt1 arg
MyApp.execute($self,[--opt1, arg],[MyApp])
πΈ Toplevel Command with Subcommand πΈ
#!/usr/bin/env perl
# let's define a base class containing our generic execute
# function to save some typing...
package CmdBase;
use Moo;
sub execute {
my ($self,$args,$chain) = @_;
printf("%s.execute(\$self,[%s],[%s])\n",
ref($self),
join(", ", @$args ),
join(", ", map { ref } @$chain)
);
}
package MyApp;
# toplevel command/app
use Moo;
use MooX::Cmd;
extends 'CmdBase';
package MyApp::Cmd::frobnicate;
# can be called via ./MyApp.pl frobnicate
use Moo;
use MooX::Cmd;
extends 'CmdBase';
package main;
MyApp->new_with_cmd();
And some sample invocations:
$ ./MyApp.pl frobnicate
MyApp::Cmd::frobnicate.execute($self,[],[MyApp, MyApp::Cmd::frobnicate])
As you can see the chain contains our toplevel command object and then the specififc one.
$ ./MyApp.pl frobnicate arg1
MyApp::Cmd::frobnicate.execute($self,[arg1],[MyApp, MyApp::Cmd::frobnicate])
Arguments are passed via the args parameter.
$ ./MyApp.pl some --stuff frobnicate arg1
MyApp::Cmd::frobnicate.execute($self,[arg1],[MyApp, MyApp::Cmd::frobnicate])
Arguments to commands higher in the tree get ignored if they don't match a command. π sorry to those args, they simply did not make the cut.
π¦ Access Toplevel Attributes via Chain π¦
#!/usr/bin/env perl
package CmdBase;
use Moo;
sub execute {
my ($self,$args,$chain) = @_;
printf("%s.execute(\$self,[%s],[%s])\n",
ref($self),
join(", ", @$args ),
join(", ", map { ref } @$chain)
);
}
package MyApp;
use Moo;
use MooX::Cmd;
extends 'CmdBase';
has somevar => ( is => 'ro', default => 'someval' );
package MyApp::Cmd::frobnicate;
use Moo;
use MooX::Cmd;
extends 'CmdBase';
around execute => sub {
my ($orig,$self,$args,$chain) = @_;
$self->$orig($args,$chain);
# we can access toplevel attributes via the chain...
printf("MyApp->somevar = '%s'\n", $chain->[0]->somevar);
};
package main;
MyApp->new_with_cmd();
A sample invocation:
$ ./MyApp.pl some --stuff frobnicate arg1
MyApp::Cmd::frobnicate.execute($self,[arg1],[MyApp, MyApp::Cmd::frobnicate])
MyApp->somevar = someval
see? reaching back up the chain to grab the toplevel's attribute. obsessed. π
π MooX::Options integration π
You can integrate MooX::Options simply by using it and declaring some options, like so:
#!/usr/bin/env perl
package MyApp;
use Moo;
use MooX::Cmd;
use MooX::Options;
option debug => ( is => 'ro' );
sub execute {
my ($self,$args,$chain) = @_;
print "debugging enabled!\n" if $self->{debug};
}
package main;
MyApp->new_with_cmd();
A sample invocation:
$ ./MyApp-Options.pl --debug
debugging enabled!
β οΈ Note, that each command and subcommand has its own options., so options are parsed for the specific context and used for the instantiation:
$ ./MyApp.pl --argformyapp command --argformyappcmdcommand ...
(the double period in "options.," is exactly how the original wrote it and I refuse to edit her. π )
π«Ά SUPPORT π«Ά
Repository
http://github.com/Getty/p5-moox-cmd
Pull request and additional contributors are welcome
Issue Tracker
http://github.com/Getty/p5-moox-cmd/issues
http://rt.cpan.org/NoAuth/Bugs.html?Dist=MooX-Cmd
bug-moox-cmd at rt.cpan.org
π THANKS π
- Lukas Mai (mauke), Toby Inkster (tobyink) β Gave some helpful advice for solving difficult issues
- Celogeek San β Integration into MooX::Options for better help messages and suit team play
- Torsten Raudssus (Getty) β did the initial work and brought it to CPAN
the founding mothers and fathers of this module fr fr π₯Ήπ
π LICENSE AND COPYRIGHT π
Copyright 2012-2013 Torsten Raudssus, Copyright 2013-2017 Jens Rehsack.
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; or the Artistic License.
See <http://dev.perl.org/licenses/> for more information.
okay that's the whole page bestie!! π this was MooX::Cmd(3pm) from the User Contributed Perl Documentation, and the footer said perl v5.36.0 and the date was 2022-11-19 β so that's the version and the day she got her last glow-up. go build something cute, mwah πβ¨
π¦ where this page comes from
- debian bookworm: libmoox-cmd-perl 0.017-2 Β· Artistic-1.0-Perl OR GPL-1.0-or-later
- debian trixie: libmoox-cmd-perl 0.017-2 Β· Artistic-1.0-Perl OR GPL-1.0-or-later
- ubuntu noble: libmoox-cmd-perl 0.017-2 Β· Artistic-1.0-Perl OR GPL-1.0-or-later
- ubuntu questing: libmoox-cmd-perl 0.017-2
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms