rjbs / app-cmd Goto Github PK
View Code? Open in Web Editor NEWperl framework for testable, extensible command line apps
perl framework for testable, extensible command line apps
e.g., dancer2
uses App::Cmd
Using Module::Pluggable was, as it usually is, at least partly a mistake.
If you write a command that gets tested on the CPAN, and someone else writes a plugin, and the plugin break things, all your tests break, because the plugin is loaded by default by Pluggable.
It should be possible to give a set of core plugins that are used in testing, at least.
I'm playing (and not succeeding terribly well) at getting subcommands to work. My expectation is that subcommands live in a namespace which is private to their parent commands. However, that doesn't appear to be so. Here's some test code:
#!/usr/bin/env perl
MyApp->run;
package MyApp;
use App::Cmd::Setup -app;
package MyApp::Command::first;
use base 'App::Cmd::Subdispatch';
sub execute { print __PACKAGE__, "\n" }
package MyApp::Command::first::init;
use base 'App::Cmd::Command';
sub execute { print __PACKAGE__, "\n" }
package MyApp::Command::second;
use base 'App::Cmd::Subdispatch';
sub execute { print __PACKAGE__, "\n" }
package MyApp::Command::second::init;
use base 'App::Cmd::Command';
sub execute { print __PACKAGE__, "\n" };
Executing that code leads to the following error message:
two plugins for command init: MyApp::Command::second::init and MyApp::Command::first::init
If I remove the definition of second::init
, I get the following
Available commands:
commands: list the application's commands
help: display a command's help screen
first: (unknown)
init: (unknown)
second: (unknown)
And I can execute first::init
as if it were a top-level command:
$ ./tpan init
MyApp::Command::first::init
Which isn't what I'd expect. Am I going about this the wrong way?
Thanks.
Hi,
In Debian we are currently applying the following patch to App-Cmd.
We thought you might be interested in it too.
Description: Fix spelling error in manpage
Origin: vendor
Author: Salvatore Bonaccorso <[email protected]>
Last-Update: 2015-09-04
The patch is tracked in our Git repository at
https://anonscm.debian.org/cgit/pkg-perl/packages/libapp-cmd-perl.git/plain/debian/patches/spelling-error-in-manpage.patch
Thanks for considering,
Salvatore Bonaccorso,
Debian Perl Group
Not knowing which version of a program is actually executed can cost a lot of time for searching, so every command line app should support a --version option by default, similar to --help. I added the following to my subclass of App::Cmd:
sub run {
my ($self) = @_;
$self = $self->new unless ref $self;
my @argv = $self->prepare_args();
if (grep { $_ eq '--version' } @argv) { # or only check first of @argv
printf "%s (%s) version %s (%s)\n",
$self->arg0, ref($self),
$self->VERSION, $self->full_arg0;
} else {
App::Cmd::run(@_);
}
}
sub global_opt_spec {
...
["version" => "show client version", { shortcircuit => 1 } ];
}
I suppose you prefer to have this implemented as plugin, similar to "help" and "commands". I prefer not to pollute the list of commands, so only added the version command with name "--version", not as "version" in my pull request.
A cpantesters report is coming your way...
My guess is that the changes in 1.66 were relevant, but I didn't try to bisect.
analysis.cpantesters.org might have more data.
PERL_DL_NONLAZY=1 "/Users/ether/perl5/perlbrew/perls/8.7/bin/perl" "-MExtUtils::Command::MM" "-MTest::Harness" "-e" "undef *Test::Harness::Switches; test_harness(0, 'blib/lib', 'blib/arch')" t/*.t
# Testing App::Cmd 0.328
t/00-load.t ............ ok
t/abbrev.t ............. ok
t/callback.t ........... ok
t/setup-broken.t ....... ok
t/setup-ignored.t ...... ok
t/setup-inner.t ........ ok
# Failed test 'description from Pod'
# at t/basic.t line 102.
# got: 'basic.t exit
#
# This package exists to exiting with exit();
#
#
# '
# expected: 'basic.t exit
#
# This package exists to exiting with exit();
#
#
# '
# Looks like you failed 1 test of 17.
t/basic.t ..............
Dubious, test returned 1 (wstat 256, 0x100)
Failed 1/17 subtests
t/setup-nocmd.t ........ ok
#
# Versions for all modules listed in MYMETA.json (including optional ones):
#
# === Configure Requires ===
#
# Module Want Have
# ------------------- ---- ----
# ExtUtils::MakeMaker any 7.10
#
# === Build Requires ===
#
# Module Want Have
# ------------------- ---- ----
# ExtUtils::MakeMaker any 7.10
#
# === Test Requires ===
#
# Module Want Have
# ------------------- ---- --------
# Data::Dumper any 2.121_04
# ExtUtils::MakeMaker any 7.10
# File::Spec any 3.47
# IPC::Cmd any 0.92
# Test::Fatal any 0.014
# Test::More 0.96 1.001014
# base any 2.07
# lib any 0.5565
#
# === Test Recommends ===
#
# Module Want Have
# ---------- -------- --------
# CPAN::Meta 2.120900 2.150005
#
# === Runtime Requires ===
#
# Module Want Have
# ------------------------- ----- -----
# Capture::Tiny 0.13 0.30
# Carp any 1.04
# Class::Load 0.06 0.23
# Data::OptList any 0.109
# File::Basename any 2.73
# Getopt::Long 2.39 2.47
# Getopt::Long::Descriptive 0.084 0.099
# IO::TieCombine any 1.004
# Module::Pluggable::Object any 5.2
# Pod::Usage any 1.3
# String::RewritePrefix any 0.007
# Sub::Exporter any 0.987
# Sub::Exporter::Util any 0.987
# Sub::Install any 0.928
# Text::Abbrev any 1.01
# constant any 1.05
# parent any 0.234
# strict any 1.03
# warnings any 1.03
#
t/00-report-prereqs.t .. ok
t/capture-ext.t ........ ok
t/setup.t .............. ok
t/simple-args.t ........ ok
t/simple-require.t ..... ok
t/simple-use.t ......... ok
t/simple-help.t ........ ok
t/subdispatch.t ........ ok
t/tester-exit.t ........ ok
t/version.t ............ ok
Test Summary Report
-------------------
t/setup-broken.t (Wstat: 0 Tests: 6 Failed: 0)
TODO passed: 4
t/basic.t (Wstat: 256 Tests: 17 Failed: 1)
Failed test: 17
Non-zero exit status: 1
Files=18, Tests=81, 1 wallclock secs ( 0.09 usr 0.06 sys + 2.49 cusr 0.33 csys = 2.97 CPU)
Result: FAIL
Failed 1/18 test programs. 1/81 subtests failed.
make: *** [test_dynamic] Error 255
-> FAIL Installing App::Cmd failed. See /Users/ether/.cpanm/work/1443464126.1744/build.log for details. Retry with --force to force install it.
Hi
During packaging the newest version for Debian, and running QA checks on the resulting package two possible spelling errors where mentioned:
--- a/lib/App/Cmd/Tutorial.pod
+++ b/lib/App/Cmd/Tutorial.pod
@@ -103,7 +103,7 @@
=item help
-allows to query for details on command's specifics.
+allows one to query for details on command's specifics.
$yourcmd help initialize
yourcmd initialize [-z] [long options...]
@@ -291,7 +291,7 @@
<whatever you want here>
-This will register this packages namespace with YourApp to be excluded from its
+This will register this package's namespace with YourApp to be excluded from its
plugin validation magic. It otherwise makes no changes to C<::NotACommand>'s
namespace, does nothing magical with C<@ISA>, and doesn't bolt any hidden
functions on.
Disclaimer: As I'm not a native english speaker I'm not completly sure the second correction from "packages" to "package's" is correct. Was it meant this way?
Regards,
Salvatore
Say I would like handle some of the CLI options directly in my application, and pass the rest to another external command. In this case I would like the behavior of Getopt::Long::Descriptive: @argv retains only those options not parsed.
The Global Options section recommend writing:
package MyApp::Command;
use App::Cmd::Setup -command;
sub opt_spec {
my ( $class, $app ) = @_;
return (
[ 'help' => "this usage screen" ],
$class->options($app),
)
}
but $class->options
refers to App::Cmd::Command::options
or MyApp::Command::options
, neither of which have been mentioned elsewhere (and the former does not exist). Using this example code leads to a run-time error Can't locate object method "options" via package Foo...
.
Also, the TIPS section, under the description for reading config values from an optional user-provided config file, includes:
Or better yet, put this logic in a superclass and process the return value from an "inner" method:
package YourApp::Command;
sub opt_spec {
my ( $class, $app ) = @_;
return (
[ 'help' => "this usage screen" ],
$class->options($app),
)
}
which has nothing to do with reading values from config files, and looks like a rogue copy of the code snippet mentioned previously.
Would you be open to a patch to App::Cmd::Command::commands
that enables setting an option so that the version
subcmd is displayed?
I see that there are unit tests for broken commands, which suggests it's intentional that using a broken command module should be fatal. But is this the best behaviour?
I would propose wrapping the load_class($plugin)
call on 195 with a try{}
block, and instead warning with the exception message. This would at least not cause an entire application to fail if a broken plugin is installed.
For example, Dist::Zilla::App::Command::podpreview currently won't load (https://rt.cpan.org/Ticket/Display.html?id=110342) because Perl6::Export::Attrs is broken in blead. This results in a broken dzil
application if the podpreview command is installed.
example test failure: http://www.cpantesters.org/cpan/report/e1a1ab84-f7d1-11e5-978c-a77dfcd2507e
https://rt.cpan.org/Ticket/Display.html?id=54947
I've been using App::Cmd as a framework for defining individual batch
jobs. This has worked out fairly well so far, but as the number of
jobs/commands has increased into the 70+ range, the overhead of doing a
C on each command has become noticeable.
Because these jobs do a wide range of tasks, each call to the main app
ends up loading 600-ish pm files.
Would you consider adding a lazy_load
option which, when true, would
only require
the given command during the _prepare_command
phase?
Using this option would necessarily enforce a 1-command-per-pm limit.
An added benefit to this in a shared environment, is that other users'
broken commands only affect you if you attempt a command listing or help.
I've attached a proof of concept patch. If you are interested in adding
this option I could create a more formal patch with tests.
Thanks,
The "CPAN modules using App::Cmd" link in App::Cmd::Tutorial does not seem to work, neither in search.cpan.org nor in metacpan.org. I did not look deeper into this issue; maybe it' s just the newline in the L<> which is confusing the pod parser?
Regards, Slaven
This is really confusing and makes plugin development harder. If instead of this:
sub new {
my ($class, $arg) = @_;
my $arg0 = $0;
my $base = File::Basename::basename $arg0;
my $self = {
command => $class->_command($arg),
arg0 => $base,
full_arg0 => $arg0,
show_version => $arg->{show_version_cmd} || 0,
};
bless $self => $class;
}
We used this:
sub new {
my ($class, $arg) = @_;
my $arg0 = $0;
my $base = File::Basename::basename $arg0;
my $self = bless({}, $class);
$self->{command} = $self->_command($arg);
$self->{arg0} = $base;
$self->{full_arg0} = $arg0;
$self->{show_version} = $arg->{show_version_cmd} || 0;
return $self;
}
Then customized override methods (like plugin_search_path) would have access to the $self
instance. I use a different model (registration based rather than detected) fro my plugins and I would rather only parse my config once. So i want to store the config instance in $self
.
Also, it is quite confusing to be using $self
variable throughout when it is actually $class
...
Are you accepting pull requests? I would create one if you would like...
I am trying to add usage text to the main app, and when I do it does not display the usage information when doing help
.
Example code.
package Foo;
use App::Cmd::Setup -app;
sub usage_desc { return 'hi';};
Would it be possible to implement a simple text-based user interface?
For example:
my %arg = ( tui => 1, );
my $cmd = Grizzly->new( \%arg );
$cmd->run;
When ran:
program>
Something similar to the Term::TUI but integrated into the module.
Commands like help and quit would be enabled by default. The version command could remain disabled by default.
I hope I phrased the question properly.
App::Cmd should support creation of a autocomplete file to put into /etc/bash_completion.d
. Once you have autocompletion for a command you'll wonder why you wasted you time before, typing the same long command names over and over again.
Some applications also read from STDIN. I have not found how to easily test this with App::Cmd::Tester. Any of the following should be fine:
test_app( YourApp => [ qw(command --opt value) ], input => $input )
test_app( YourApp => [ qw(command --opt value) ], { input => $input } )
test_app( YourApp => [ qw(command --opt value), $input )
I suppose adding a local *STDIN
at the right place will make it work.
Hi,
In Debian we are currently applying the following patch to App-Cmd.
We thought you might be interested in it too.
Description: Fix spelling error in manpage
Origin: vendor
Author: Salvatore Bonaccorso <[email protected]>
Last-Update: 2016-07-18
The patch is tracked in our Git repository at
https://anonscm.debian.org/cgit/pkg-perl/packages/libapp-cmd-perl.git/plain/debian/patches/fix-spelling-error-in-manpage.patch
Thanks for considering,
Salvatore Bonaccorso,
Debian Perl Group
The behavior of the "--version" option does not appear to be mentioned anywhere in the documentation.
Getopt::Long has a default behavior for the --version option that seems useful, but I inadvertently created a "version" option myself and was confused when it got used in my tests (the behavior of the --version option does not work very well under App::Cmd::Tester).
Would it also be a good idea to add a "no_auto_version" option to go with the "no_auto_help" option?
In the pod for App::Cmd::Setup it references 'Manual' and 'Plugin'.
For more information on writing plugins, see App::Cmd::Manual and App::Cmd::Plugin.
Manual doesn't appear to exist and the pod for Plugin appears to lack information.
Hello Ricardo,
Any chance to implement subcommands from the box ?
https://stackoverflow.com/questions/53889078/how-to-implement-subcommand-using-appcmd-module
If you call one-command App::Cmd applications without any option or argument then command's execute()
method will receive argument list as [undef]
array ref instead of []
.
I was just installing my toolchain on a new 5.8.6 perlbrew and I had trouble installing App::Cmd -- but the third attempt to install it succeeded. I use HARNESS_OPTIONS=j9 in my environment.
(cpantesters reports should be coming your way tonight.)
If a command class uses Moose (or Mouse) the "Usage" output will be lost. Even with "no Moose".
$ perl -Ilib bin/test foo
Error: This will never work
Usage: at /Users/schwern/perl5/perlbrew/perls/perl-5.18.1-thread/lib/site_perl/5.18.1/App/Cmd/Command.pm line 90.
See https://gist.github.com/schwern/10081851 for test code.
The code in this section does not look correct to me,
https://metacpan.org/pod/distribution/App-Cmd/lib/App/Cmd/Tutorial.pod#Ignoring-Multiple-modules-from-the-App-level.
Where does $command_class come from?
Moose::Util::add_method_modifier( __PACKAGE__, 'around', [
should_ignore => sub {
my $orig = shift;
my $self = shift;
return 1 if not $command_class->isa( 'App::Cmd::Command' );
return $self->$orig( @_ );
}]);
btw, I am not a heavy Moose user, but I see add_method_modifier() is not documented in Moose::Util. I wonder if it's fine for wide usage or not...
https://rt.cpan.org/Ticket/Display.html?id=52876
I gave rjbs my impressions from my first encounter with App::Cmd. Its
in his chat log. He said to bug it. Here it is.
Michael Schwern: Got a moment to hear App::Cmd feedback?
rjbs: sure thing
Michael Schwern: So I sat down to write something like "gitpan clone
" and "gitpan fork " and remembered hdp and Eric arguing
over App::Cmd.
Michael Schwern: So I looked.
Michael Schwern: From the docs the basics looked straightforward, though
overkill for a small app so I did everything in one file with "package"
statements.
Michael Schwern: And I quickly hit my first stumbling block
rjbs: yeah, did that work?
Michael Schwern: opt_spec isn't documented
Michael Schwern: global_opt_spec is barely documented
rjbs: the global one I didn't write; I know it's poorly documente d:(
rjbs: I don't even exactly understand why it's there.
Michael Schwern: I wanted to add some flags to apply to all commands
rjbs: http://search.cpan.org/dist/App-Cmd/lib/App/Cmd/Command.pm#opt_spec
Michael Schwern: Ahh, the "its in the OTHER man page" problem
rjbs: yeah; you're writing a method for a App::Cmd::Command subclass
rjbs: did you read the tutorial, btw?
Michael Schwern: Which is not obvious
Michael Schwern: Yeah, the tutorial contradicted the synopsis
rjbs: looks like Tutorial could use a few L<>'s added
rjbs: o?
Michael Schwern: The tutorial says "use App::Cmd::Setup -app"
Michael Schwern: err
Michael Schwern: Ahh, the tutorial says "use App::Cmd::Setup -app" but
in the tip to add a --help option it says "use App::Cmd::Setup -command"
without explaination.
Michael Schwern: While I'm at it, why am I writing validate_args()?
rjbs: in that example?
Michael Schwern: In any example
rjbs: you don't need to
rjbs: if you don't provide it, validation is "okay"
Michael Schwern: then pull it
rjbs: what?
Michael Schwern: Wait, it doesn't do any validation?
rjbs: ...
rjbs: Okay, let me tell you waht happens
rjbs: and you tell me how to fix hte docs.
rjbs: You write an opt_spec which is just passed verbatim to
Getopt::Long::Descriptive.
rjbs: it turns @argv into $opt and $args
rjbs: $opt will tell you what all the switches were, like:
if ($opt->verbose) { ... }
rjbs: $args is an arrayref of all the stuff left over
rjbs: so: myapp cmd --verbose --protocol tcp myfile
might leave $args = [ 'myfile' ]
rjbs: so the validate args there is saying: before you go any further,
if the user said --help, give a help message.
Michael Schwern: So this is in addition to Getopt::Long::Descriptive's
checks
rjbs: yes
rjbs: GLD validates switches.
Michael Schwern: Ahh, that's not obvious
rjbs: validate_args validates what's left over.
rjbs: Ok.
rjbs: So, I will insert some more documentation above the paragraph
beginning "The first two methods"
Michael Schwern: I think part of the problem is the App::Cmd page
presents itself as "here, its easy!" and then there's a bunch of
documentations for lots of methods not mentioned before and little no
documentation for the methods already mentioned.
Michael Schwern: (man, my fingers are not working)
rjbs: nor mine; they're cold
Michael Schwern: What is the criterion for the methods documented in
App::Cmd?
rjbs: They're methods on the App::Cmd subclass.
rjbs: or the base class, depending on how you look at it.
rjbs: If you write a program "svn" and it has subcommands "commit" and
"update"
Michael Schwern: Part of the confusion is the "use YourApp -command"
cuteness.
rjbs: then App::Cmd is the base class of the thing implementing "svn"
rjbs: App::Cmd::Command is the base class of the thing implementing
"commit' and "update"
Michael Schwern: Yeah, that's non-obvious
rjbs: the -command thing makes sense, I promise -- but clearly it needs
clearer explanation
Michael Schwern: It obscures what I'm actually subclassing so I don't
know where to look next for documentation.
Michael Schwern: That App::Cmd::Setup is documented adds to the confusion
rjbs: You don't need to do things that way.
rjbs: ugh, I know, that DESPERATELY needs docs
Michael Schwern: s/documented/undocumented/
rjbs: Everything Just Works if you just use base.
Michael Schwern: Then just use base.
rjbs: no
Michael Schwern: Then just use parent
rjbs: (a) "Everything" was an overstatement; the plugin subsystem wont' work
rjbs: (b) it's actually very very convenient to not just use base, once
you know how App::Cmd::Setup works
rjbs: the plugin subsystem needs to track registered subcommands, etc
rjbs: so it needs to use something that will register with the superclass
Michael Schwern: You write plugins infrequently enough that I think two
lines is ok
Michael Schwern: You're optimizing the wrong bit
rjbs: It would be two lines in every command, and would have to happen
at compile time.
Michael Schwern: I thought you said it only effected plugins
rjbs: so now it's like BEGIN { PACKAGE->register_with_etc }
rjbs: no, it allows plugins to affect command subclasses
Michael Schwern: oh, you're doing some sort of wrapper/hijacking of
command methods?
rjbs: basically, the plugin system allows the command to cause a
compile-time import into every command subclass to give things subs
rjbs: so you can end up writing:
rjbs: sub execute {
exit unless prompt_yn("Really???");
rjbs: and prompt_yn is a sub available everywhere because Your::App
provides it to all subcommands
rjbs: ...but I don't think any of this should really be a big deal. If
we go back to the original confusion that occurred, it was "where do I
figure out wtf methods I need to write."
rjbs: which the tutorial can be clearer about pointing to, as can the
main docs
Michael Schwern: I would put all the basic user-facing methods in
App::Cmd and bury the rest in their respective documentation.
Michael Schwern: Also, what's the last argument to describe_options() in
Getopt::Long::Descriptive?
rjbs: some nightmarish thingI don't remember; I didn't write it :)
rjbs: but I can look it up
rjbs: all I -ever- do is:
Michael Schwern: Oh, that's HDP's fault
rjbs: describe_options("%c %o", [...], [...], ...)
rjbs: and never the final magic thingy
rjbs: I think what I really need is a new document, App::Cmd::Manual
rjbs: which is more thorough than ::Tutorial, more a reference
rjbs: and covers every class you need to care about
rjbs: because I really do wnat each class to document itself normally
rjbs: and I can put a big pair of links atop the other classes
"SERIOUSLY YOU PROBABLY WANT THE MANUAL"
Michael Schwern: Yes
Michael Schwern: So my impression at this point is "that's great, uhh,
I'm going to hack it together myself"
rjbs: ?
Michael Schwern: There's just a bit too much hidden magic in App::Cmd.
Michael Schwern: For something that I can write in three subroutines and
a hash.
rjbs: I agree that there are too many underdocumented bits.
Michael Schwern: I see where its going though
rjbs: I don't agree that you can really do what it does in three
subroutines and a hash. ;)
rjbs: I do appreciate feedback on where its docs are lacking, and I
always try to improve the docs as soon as I get feedback.
rjbs: If you have specific questions, I can answer those, to.
rjbs: too
rjbs: probably what I will do is try to make an outline of Manual.pm
this weekend.
rjbs: do you think that's a bad plan?
rjbs: (Manual.pm)
Michael Schwern: I can do what I need in three subroutines and a hash.
rjbs: right.
Michael Schwern: The argument checking won't be perfect, because it
won't be per command.
Michael Schwern: OIC, the Getopt::Long::Descriptive documentation is
layed out weird.
rjbs: Well, is something actually preventing you from using App::Cmd?
Obviously, I don't get a dollar if you do or anything.
rjbs: How so? I didn't write those docs, nor do I remember how they're
written.
rjbs: I should look at them.
Michael Schwern: Its written almost like its the docs for a program.
Michael Schwern: So it has major sections about describe_options()
Michael Schwern: But then it has regular function documentation for
desribe_options()
rjbs: I see.
rjbs: Yeah, okay.
rjbs: These docs need to be overhauled.
Michael Schwern: So if you just search for "describe_options" you'll
skip over all the real docs
rjbs: I really have barely looked at them, ever, since I had to learn
how it worked before they existed (at work).
rjbs: yeah, that sucks
Michael Schwern: The describe_options() docs point back to the SYNOPSIS,
which is not where the meat is.
rjbs: ha
Michael Schwern: Oh, and the greatest curse of all. "Option
specifications are the same as in Getopt::Long" which are a nightmare to
find in the Getopt::Long docs!
Michael Schwern: Ok, I'm done bitching now
rjbs: I was thinking the EXACT SAME THING
rjbs: I'm going to summarize them in GLD.
rjbs: because I can never find WTF I want in Getopt::Long.
rjbs: EVER
Michael Schwern: Want me to RT any of this?
rjbs: sure! put a ticket in app-cmd, and you can just refrence our chat
and I'll be able to pull it out of logs later in case I forget. thanks1
rjbs: btw
rjbs: I wrote App::Cmd because I wanted something with good
documentation. :-)
rjbs: the pre-existing system was...
rjbs: http://search.cpan.org/~ALEXMV/App-CLI/
perlbrew - v5.32.0
» oe help
Util.c: loadable library and perl binaries are mismatched (got handshake key 0xc180000, needed 0xe180000)
https://rt.cpan.org/Ticket/Display.html?id=64299
I know in principle what A::C::S is supposed to do, but I have no idea
how to use it in my code. Even just a single example would help...
Mark Lawrence
Hey Ricardo,
This is a Play Perl quest: Patch App::Cmd::Command so that abstract method decodes bytes into characters (assuming UTF-8)
I'm thinking of claiming it and doing it, but I wanted to check with you first that this was a desired feature that's worth me providing a patch for?
Example:
sub opt_spec {
[ enable!,'enable bit],
}
help will only contain
--enable enable bit
I believe it should be
--(no)enable enable bit
App::Cmd::Command::Abstract repeats the logic from module_notional_filename. DRY.
(Plus it should probably use PPI to find # ABSTRACT
rather than trying to parse the file itself... PPI can take module names rather than filenames anyway, can't it?)
Description / demonstration of the problem: https://gist.github.com/preaction/5550143
TL;DR: App::Cmd::Tester's use of IO::TieCombine gets untied if the command uses IPC::Open3.
Unfortunately, the only fixes possible on the App::Cmd::Tester side involve either removing the "output" key that shows the combined stdout/stderr, or making that the only output.
I tried using Capture::Tiny inside of App::Cmd::Tester, but it also changed what App::Cmd::Tester is capable of (removing either the combined or the uncombined output).
The only way forward I see right now is to create an Untied version of App::Cmd::Tester that allows the user a choice of split or combined output, but not both.
Issue also reported to System-Command: book/System-Command#10
Hi.
I wrote a command like the one below. . .
use MyApp::Cmd::Command::IDS; ... sub command_names { 'IDS' } ...
The lower line seems to force lowercase letters.
diff --git a/lib/App/Cmd.pm b/lib/App/Cmd.pm index 84e5ce1..162ce3e 100644 --- a/lib/App/Cmd.pm +++ b/lib/App/Cmd.pm @@ -208,7 +208,7 @@ sub _command { next unless $plugin->can("command_names"); - foreach my $command (map { lc } $plugin->command_names) { + foreach my $command ($plugin->command_names) { die "two plugins for command $command: $plugin and $plugin{$command}\n" if exists $plugin{$command};
Can not use uppercase subcommands by just overriding command_names?
Or is it App::Cmd's design to do as below?
my $app = MyApp::Cmd->new; $app->{command}{IDS} = delete $app->{command}{ids}; $app->run;
Regards,
Tomohiro Hosaka
Any arguments against letting
myapp somecommand --help
call
myapp help somecommand
I remember accidently typing the former form several times when I started to use dzil
. By the way git
also supports both calling conventions.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.