我想为我的Perl程序提供更好的文档。为此,我没有很多解决方案。 Actuatlly我发现只有一个:POD。
对于我们通常拥有的NAME
部分:
=head1 NAME
program_name - Short description
=cut
需要5行,其中唯一的相关信息是简短描述。 program_name应自动填充basename($0)
。
然后是选项。从GetOptions
参数中,我可以自动提取:
我们可以轻松添加category
,mandatory
,description
和in_conflict_with
等选项。那我为什么要在POD中重复一遍呢?
为了说明我的例子,我写了这个:
#!/usr/bin/env perl
use strict;
use warnings;
use feature 'say';
use Getopt::Long;
use Pod::Usage 'pod2usage';
use File::Basename;
=head1 AUTHOR
John Doe <j@doe.com>
=head1 DESCRIPTION
B<This program> does nothing important. But at least it is properly documented.
=head1 COPYRIGHT
Copyright(c) Nobody
=head1 VERSION
v0.1
=cut
my %cfg;
CliInfo (
args => [
{arg => "l|length=i", dest => \$cfg{length}, desc => "Length of the string", type => 'mandatory'},
{arg => "f|file=s" , dest => \$cfg{data}, desc => "Input filename", type => 'mandatory'},
{arg => "v" , dest => sub {\$cfg{verbose}++}, desc => "Verbose"},
]
);
sub CliInfo {
my %info = @_;
my $programName = basename $0;
GetOptions(map( {$_->{arg} => $_->{dest}} @{$info{args}}),
'h|help' => sub {
say "Usage: $programName [options]...";
say pod2scalar(-verbose => 99, -sections => "DESCRIPTION");
say "\nOptions:";
say sprintf('%-20s', (sub {
my @opt = split /\|/, shift =~ s/=.*//r;
return " -$opt[0], --$opt[1]" if @opt > 1;
return " --$opt[0]" if length $opt[0] > 1;
return " -$opt[0]";
})->($_->{arg})), $_->{desc} for @{$info{args}};
say "\n";
},
'version' => sub {
my $ver = pod2scalar(-verbose => 99, -sections => "VERSION");
say STDERR $programName, " - $ver";
say pod2scalar(-verbose => 99, -sections => "COPYRIGHT");
say "";
exit;
})
or say "Invalid option, try --help" and exit 1;
sub pod2scalar {
open my $fh, '>', \my $text;
pod2usage(@_, -output => $fh, -exitval => 'NOEXIT');
$text =~ s/^(?:.*\n)//;
$text =~ s/(?:\s*\n)\z//r;
}
}
__END__
这给出了这个输出(也与GNU标准非常兼容):
$ ./help.pl --help
Usage: help.pl [options]...
This program does nothing important. But at least it is properly documented.
Options:
-l, --length Length of the string
-f, --file Input filename
-v Verbose
所以问题是:
对于DRY原则,我在这里展示的是否有任何标准和类似的解决方案?
答案 0 :(得分:1)
也许你需要Perl库Getopt::Long::Descriptive。
这是用Getopt::Long::Descriptive重写的脚本:
#!/usr/bin/env perl
use strict;
use warnings;
use Pod::Usage 'pod2usage';
use Capture::Tiny ':all';
use Getopt::Long::Descriptive;
=head1 AUTHOR
John Doe <j@doe.com>
=head1 DESCRIPTION
B<This program> does nothing important. But at least it is properly documented.
=head1 COPYRIGHT
Copyright(c) Nobody
=head1 VERSION
v0.1
=cut
sub pod2scalar {
my $stdout = capture_merged {
pod2usage(-verbose => 99, -sections => "DESCRIPTION", -exitval => "noexit");
};
return $stdout;
}
my ($opt, $usage) = describe_options(
pod2scalar() . "%c %o <some-arg>",
[ 'l|length=i', 'Length of the string', { required => 1, default => 4 } ],
[ 'f|file=s', 'Input filename', { required => 1 } ],
[ 'v', 'Verbose' ],
[ 'help', "print usage message and exit" ],
{
show_defaults => 1,
},
);
if ($opt->help) {
print($usage->text);
exit;
}
这是原始脚本的输出:
$ ./before.pl --help
Usage: before.pl [options]...
This program does nothing important. But at least it is properly
documented.
Options:
-l, --length Length of the string
-f, --file Input filename
-v Verbose
这是新脚本的输出:
$ ./after.pl --help
Mandatory parameter 'f' missing in call to (eval)
Description:
This program does nothing important. But at least it is properly
documented.
after.pl [-flv] [long options...] <some-arg>
--length INT -l INT Length of the string
(default value: 4)
--file STR -f STR Input filename
-v Verbose
--help print usage message and exit