Hi rjbs,
here is the promised patch - quicker than expected, because $active_cmd
contained different data than expected - but when everything is named
$command, $cmd, ... - it's hard to keep apart ...
Sno
From fb696a3e1a1b81d151b754a5951212420c46b1aa Mon Sep 17 00:00:00 2001
From: Jens Rehsack <rehsack@googlemail.com>
Date: Wed, 28 Jul 2010 08:43:50 +0200
Subject: [PATCH 3/4] update pod to refer the execute method instead of run method
---
lib/App/Cmd/Tutorial.pod | 4 ++--
1 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/lib/App/Cmd/Tutorial.pod b/lib/App/Cmd/Tutorial.pod
index c4571ce..cda674c 100644
--- a/lib/App/Cmd/Tutorial.pod
+++ b/lib/App/Cmd/Tutorial.pod
@@ -58,8 +58,8 @@ Now it works:
$ yourcmd initialize
Everything has been initialized. (Not really.)
-The arguments to the run method are the parsed options from the command line
-(that is, the switches) and the remaining arguments. With a properly
+The arguments to the execute method are the parsed options from the command
+line (that is, the switches) and the remaining arguments. With a properly
configured command class, the following invocation:
$ yourcmd reset -zB --new-seed xyzxy foo.db bar.db
--
1.7.0.5
From 83ae59259656afd50f220218b6f48980a8d8015f Mon Sep 17 00:00:00 2001
From: Jens Rehsack <rehsack@googlemail.com>
Date: Wed, 28 Jul 2010 09:08:47 +0200
Subject: [PATCH 4/4] - add support of set_action
- try to document command_names better in tutorial
---
lib/App/Cmd.pm | 4 ++-
lib/App/Cmd/Command.pm | 15 ++++++++++++
lib/App/Cmd/Tutorial.pod | 55 ++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 73 insertions(+), 1 deletions(-)
diff --git a/lib/App/Cmd.pm b/lib/App/Cmd.pm
index d932253..b4e394c 100644
--- a/lib/App/Cmd.pm
+++ b/lib/App/Cmd.pm
@@ -327,7 +327,9 @@ sub prepare_command {
sub _prepare_command {
my ($self, $command, $opt, @args) = @_;
if (my $plugin = $self->plugin_for($command)) {
- return $plugin->prepare($self, @args);
+ my $cmd = $plugin->prepare($self, @args);
+ $cmd->set_action($command); # when a command class can support multiple commands, we should tell the chosen
+ return $cmd;
} else {
return $self->_bad_command($command, $opt, @args);
}
diff --git a/lib/App/Cmd/Command.pm b/lib/App/Cmd/Command.pm
index 3eb03d1..a7fd347 100644
--- a/lib/App/Cmd/Command.pm
+++ b/lib/App/Cmd/Command.pm
@@ -69,6 +69,21 @@ sub new {
bless $arg => $class;
}
+=head2 set_action
+
+ $command_plugin->set_action($user_command);
+
+This method is called to set the user given action on command line. The user
+action is not interesting until multiple commands with different actions
+are supported by a plugin.
+
+=cut
+
+sub set_action {
+ my ($self, $command) = @_;
+ $self->{action} = $command;
+}
+
=head2 execute
=for Pod::Coverage run
diff --git a/lib/App/Cmd/Tutorial.pod b/lib/App/Cmd/Tutorial.pod
index cda674c..c1c33e6 100644
--- a/lib/App/Cmd/Tutorial.pod
+++ b/lib/App/Cmd/Tutorial.pod
@@ -100,6 +100,30 @@ routine. To improve our command class, we might add the following code:
$self->usage_error("too few arguments") unless @$args;
}
+In the case a command plugin is able to execute several actions, the
+command_names method must be overwritten to inform App::Cmd:
+
+ sub command_names {
+ return qw(initialize reset display);
+ }
+
+But now execute is called for each of the three actions - and the command
+doesn't know the user desired action. Take a look into the attribute
+C<action> (set by App::Cmd::Command::set_action).
+
+ my %dispatch = (
+ initialize => 'initialized',
+ reset => 'reseted',
+ display => 'displayed',
+ );
+
+ sub execute {
+ my ($self, $opt, $args) = @_;
+ my $action = $self->{action};
+
+ print "Everything has been $dispatch{$action}. (Not really.)\n";
+ }
+
=head1 TIPS
=over 4
@@ -113,6 +137,37 @@ all of them.
=item *
+For command which act as a bridge between a module with several actions on
+the same objects, it might be useful to have one command class which dispatches
+the actions properly to reduce initialization time.
+
+ package YourApp::Command::initialize;
+ sub execute { $_[0]->{embed}->initialze() };
+
+ package YourApp::Command::reset;
+ sub execute { $_[0]->{embed}->reset() };
+
+ package YourApp::Command::display;
+ sub execute { $_[0]->{embed}->display() };
+
+ package YourApp::Command::backup;
+ sub execute { $_[0]->{embed}->backup() };
+
+ package YourApp::Command::restore;
+ sub execute { $_[0]->{embed}->restore() };
+
+This will force App::Cmd to load 5 plugins, loop 5 times to get the supported
+command, etc. Instead,
+
+ package YourApp::Command::settings;
+ sub command_names { return qw(initialize reset display backup restore); }
+ sub execute { my $action = $self->{action}; $_[0]->{embed}->$action(); }
+
+could speed up command loading dramatically, depending on the amount of
+supported actions.
+
+=item *
+
To add a C<--help> option to all your commands create a base class like:
package MyApp::Command;
--
1.7.0.5
From 84dc8d0c573ea261000509ce7b3ff8b33aa1300b Mon Sep 17 00:00:00 2001
From: Jens Rehsack <rehsack@googlemail.com>
Date: Wed, 28 Jul 2010 08:39:11 +0200
Subject: [PATCH 2/4] rename run() method into execute()
---
lib/App/Cmd/Command/help.pm | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/lib/App/Cmd/Command/help.pm b/lib/App/Cmd/Command/help.pm
index f7920fe..6618e41 100644
--- a/lib/App/Cmd/Command/help.pm
+++ b/lib/App/Cmd/Command/help.pm
@@ -33,7 +33,7 @@ abstracts, or display the usage screen for a subcommand with its
description.\n"
}
-sub run {
+sub execute {
my ($self, $opts, $args) = @_;
if (!@$args) {
--
1.7.0.5
From 19ec283fe3f5bd5a8f03a528d3b8eb0769f25adc Mon Sep 17 00:00:00 2001
From: Jens Rehsack <rehsack@googlemail.com>
Date: Wed, 28 Jul 2010 08:23:15 +0200
Subject: [PATCH 1/4] - minor pod fixes
- remove App::Cmd::Plugin reference, this class doesn't really exists
and is not documented at all
- refer to App::Cmd::Tutorial instead of App::Cmd::Manual
---
lib/App/Cmd.pm | 4 ++--
lib/App/Cmd/Setup.pm | 12 ++++++++++--
lib/App/Cmd/Tutorial.pod | 3 ++-
3 files changed, 14 insertions(+), 5 deletions(-)
diff --git a/lib/App/Cmd.pm b/lib/App/Cmd.pm
index 99cfa35..d932253 100644
--- a/lib/App/Cmd.pm
+++ b/lib/App/Cmd.pm
@@ -90,7 +90,7 @@ in F<YourApp/Command/blort.pm>:
$self->usage_error("No args allowed") if @$args;
}
- sub run {
+ sub execute {
my ($self, $opt, $args) = @_;
my $result = $opt->{blortex} ? blortex() : blort();
@@ -111,7 +111,7 @@ and, finally, at the command line:
App::Cmd is intended to make it easy to write complex command-line applications
without having to think about most of the annoying things usually involved.
-For information on how to start using App::Cmd, see App::Cmd::Tutorial.
+For information on how to start using App::Cmd, see L<App::Cmd::Tutorial>.
=head1 METHODS
diff --git a/lib/App/Cmd/Setup.pm b/lib/App/Cmd/Setup.pm
index 586489a..2f77258 100644
--- a/lib/App/Cmd/Setup.pm
+++ b/lib/App/Cmd/Setup.pm
@@ -12,7 +12,7 @@ App::Cmd::Setup - helper for setting up App::Cmd classes
App::Cmd::Setup is a helper library, used to set up base classes that will be
used as part of an App::Cmd program. For the most part you should refer to
-L<the manual|App::Cmd::Manual> for how you should use this library.
+L<the tutorial|App::Cmd::Tutorial> for how you should use this library.
This class is useful in three scenarios:
@@ -30,6 +30,8 @@ Instead of writing:
package MyApp;
use App::Cmd::Setup -app;
+=begin future
+
The benefits of doing this are mostly minor, and relate to sanity-checking your
class. The significant benefit is that this form allows you to specify
plugins, as in:
@@ -37,7 +39,9 @@ plugins, as in:
package MyApp;
use App::Cmd::Setup -app => { plugins => [ 'Prompt' ] };
-Plugins are described in L<App::Cmd::Manual> and L<App::Cmd::Plugin>.
+Plugins are described in L<App::Cmd::Tutorial> and L<App::Cmd::Plugin>.
+
+=end future
=item when writing abstract base classes for commands
@@ -57,6 +61,8 @@ Do not confuse this with the way you will write specific commands:
Again, this form mostly performs some validation and setup behind the scenes
for you. You can use C<L<base>> if you prefer.
+=begin future
+
=item when writing App::Cmd plugins
L<App::Cmd::Plugin> is a mechanism that allows an App::Cmd class to inject code
@@ -71,6 +77,8 @@ L<App::Cmd::Plugin>.
=back
+=end future
+
=cut
use App::Cmd ();
diff --git a/lib/App/Cmd/Tutorial.pod b/lib/App/Cmd/Tutorial.pod
index c3edf0c..c4571ce 100644
--- a/lib/App/Cmd/Tutorial.pod
+++ b/lib/App/Cmd/Tutorial.pod
@@ -80,7 +80,8 @@ C<usage_desc> provides the usage format string; C<opt_spec> provides the option
specification list; C<validate_args> is run after Getopt::Long::Descriptive,
and is meant to validate the C<$args>, which GLD ignores.
-The first two methods provide configuration passed to GLD's C<describe_options> routine. To improve our command class, we might add the following code:
+The first two methods provide configuration passed to GLD's C<describe_options>
+routine. To improve our command class, we might add the following code:
sub usage_desc { "yourcmd %o [dbfile ...]" }
--
1.7.0.5