如何使用App :: Cmd覆盖或自定义帮助命令?

时间:2014-12-11 22:34:16

标签: perl

我发现App::Cmd对编写命令行应用非常有帮助,但是覆盖默认命令很有挑战性。有两个默认命令,helpcommands。似乎help命令解析子命令类中的opt_spec定义以生成列表形式的帮助菜单。对于具有多个选项的命令,此默认帮助菜单非常难以理解。

我想要的是覆盖help命令以提供我自己的自定义菜单,或完全禁用help命令,只允许通过特定子命令的选项生成菜单。后一种选择很容易实现,但我仍然希望在这种情况下禁用全局help选项,以便不打印两个不同的菜单,具体取决于帮助选项的位置。


我首先尝试的是在子命令类中定义usage_descdescription方法(在App::Cmd::Command::help文档中解释),但这只是在选项列表之前添加要打印的文本。例如,将自定义菜单添加到opt_spec只会导致打印两个菜单。

我还尝试在我的help课程中停用MyApp::Command插件:

package MyApp::Command;

sub validate_args {
    my ( $self, $opt, $args ) = @_;
    $self->app->no_help_plugin;

    $self->validate( $opt, $args );
}

但这似乎没有效果。我也尝试修改default_command方法但没有成功。没有看到例子,很难理解如何使用这些方法。

任何人都可以提供一个示例(或指向CPAN上的一个示例),了解如何在使用App :: Cmd时覆盖或禁用全局help命令?

1 个答案:

答案 0 :(得分:0)

经过大量的实验,我能够找到解决问题的方法。文档没有告诉您的是,如果您停用帮助插件,则还必须提供自己的default_command并在opt_spec中对其进行定义。文档说您可以提供自己的默认命令或覆盖默认命令,但我的发现是您必须同时执行这两项操作来禁止显示警告消息。我将提供一个例子。

在MyApp.pm中:

package MyApp;

use App::Cmd::Setup -app;

sub global_opt_spec {
    return (
        [ 'man|m'  => "Get the manual entry for a command" ],
        [ 'help|h' => "Print some usage" ],
    );
}

sub help {
    print STDERR<<END

Usage:
myapp <command> [-h] [-m]
    -m --man    Get the manual entry for a command
    -h --help   Print some usage

Available commands:
   commands:    list the application's commands

 initialize:    A really useful description

END
}

在MyApp :: Command :: initialize中:

package MyApp::Command::initialize;

use strict;
use warnings;
use MyApp -command;

sub opt_spec {
    return (    
        [ "file|f=s",   "A required file"],
    );
}

sub validate_args {
    my ($self, $opt, $args) = @_;

    my $command = __FILE__;
    if ($self->app->global_options->{man}) {
        system("perldoc $command");
    }
    elsif ($self->app->global_options->{help}) {
        $self->help;
     }
     else {
        $self->help and exit(0) unless $opt->{file};
    }
}

sub execute {
    my ($self, $opt, $args) = @_;

    exit(0) if $self->app->global_options->{man} ||
        $self->app->global_options->{help};

    my $result = _some_method($opt);
}

sub help {
    print STDERR<<END

Usage:
    myapp <command> [-h] [-m]
    -m --man    Get the manual entry for a command
    -h --help   Print some usage

Options:
    -f --file   A required file

END
}

在myapp中:

#!/usr/bin/env perl

use strict;
use warnings;
use MyApp;

my $cmd = MyApp->new({ no_help_plugin => 1 });
$cmd->default_command( $cmd->help ) and exit unless @ARGV;
$cmd->run;

现在您可以运行myapp,它将生成您提供的使用菜单。因为我已经定义了default_command,所以默认帮助只会呈现您的帮助菜单而不会抱怨缺少命令。请注意,myapp help initialize现在不会被识别,因此使用情况会更为熟悉myapp initialize -h。前一个命令将只呈现我们想要的自定义帮助。

此外,现在每个子命令都有一个唯一的菜单。与仅编写自己的脚本或类相比,这对于一个简单的例子来说是多么荒谬的工作,但是对于复杂的命令,这应该使得使用更容易理解。

我愿意接受改进或简化此代码的建议,但它似乎正是我想要的,并且与App :: Cmd期望的一致。