Skip Menu |

Preferred bug tracker

Please visit the preferred bug tracker to report your issue.

This queue is for tickets about the App-Cmd CPAN distribution.

Report information
The Basics
Id: 59656
Status: stalled
Priority: 0/
Queue: App-Cmd

People
Owner: Nobody in particular
Requestors: REHSACK [...] cpan.org
Cc:
AdminCc:

Bug Information
Severity: Normal
Broken in: 0.307
Fixed in: (no value)



Subject: Documentation out of sync
Hi Ricardo, I'm working on a tool to generate some reports. My questions was: "How can I create a command plugin what is able to execute a command based on a configuration file name?" Example: $ genreport daily My App::Cmd application should look into ~/.genreport/ - find daily.yaml and creates an alias command in App::Report::Command::GenReport. This command should be executed and it should be informed to use the daily configuration. I scanned the entire Pod, found that the referenced documents App::Cmd::Plugin and App::Cmd::Manual doesn't exists anymore but finally I figured out what I have to do by doing a static code analysis. Neither $actual_cmd is documented nor it's explicitly explained how a command plugin can support more than one command. Best regards, Jens
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
Subject: 0003-update-pod-to-refer-the-execute-method-instead-of-ru.patch
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
Subject: 0004-add-support-of-set_action.patch
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
Subject: 0002-rename-run-method-into-execute.patch
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
Subject: 0001-minor-pod-fixes.patch
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
had a typo in the last patch, here is the diff against it ...
Subject: 0001-Fixing-typo-in-calling-convention.patch
From f78d6318c746e5b5c6e5c6ada9fdc66d7da174fc Mon Sep 17 00:00:00 2001 From: Jens Rehsack <rehsack@googlemail.com> Date: Fri, 30 Jul 2010 21:31:28 +0200 Subject: [PATCH] Fixing typo in calling convention --- lib/App/Cmd.pm | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/App/Cmd.pm b/lib/App/Cmd.pm index b4e394c..eb23e79 100644 --- a/lib/App/Cmd.pm +++ b/lib/App/Cmd.pm @@ -327,9 +327,9 @@ sub prepare_command { sub _prepare_command { my ($self, $command, $opt, @args) = @_; if (my $plugin = $self->plugin_for($command)) { - my $cmd = $plugin->prepare($self, @args); + my ($cmd, $opt, @args) = $plugin->prepare($self, @args); $cmd->set_action($command); # when a command class can support multiple commands, we should tell the chosen - return $cmd; + return ($cmd, $opt, @args); } else { return $self->_bad_command($command, $opt, @args); } -- 1.7.0.5
Subject: add a "which command name was used" mechanism
I've merged in most of the documentation fixes. Thanks. I think it's reasonable for a $command object to know what command name was used to reach it. I can't accept the patch, yet, for a few reasons: 1. It should be $command->command_name_used or something like that. ->action makes it sound like we're introducing yet another major concept, when we're just asking (more or less) what $ARGV[1] was -- which command_name for the command was used. 2. I think it's a bad idea to use the command name for any real behavior change. That should be done with distinct command plugins. All this means is that I don't want the documentation to show how to do this. Please replace those docs with something that just says "you can find out what name was used by calling such and such method." 3. No tests were provided. If you can provide future work as a git remote, that would be great. If not, that's okay. Thanks very much for your contributions! -- rjbs
...by the way, a rebased version of your unmerged commits are available in my github repo for this project as the multi-action-commands branch. -- rjbs