📄 usage.pm
字号:
Most scripts should print some type of usage message to C<STDERR> when acommand line syntax error is detected. They should also provide anoption (usually C<-H> or C<-help>) to print a (possibly more verbose)usage message to C<STDOUT>. Some scripts may even wish to go so far as toprovide a means of printing their complete documentation to C<STDOUT>(perhaps by allowing a C<-man> option). The following complete exampleuses B<Pod::Usage> in combination with B<Getopt::Long> to do all of thesethings: use Getopt::Long; use Pod::Usage; my $man = 0; my $help = 0; ## Parse options and print usage if there is a syntax error, ## or if usage was explicitly requested. GetOptions('help|?' => \$help, man => \$man) or pod2usage(2); pod2usage(1) if $help; pod2usage(-verbose => 2) if $man; ## If no arguments were given, then allow STDIN to be used only ## if it's not connected to a terminal (otherwise print usage) pod2usage("$0: No files given.") if ((@ARGV == 0) && (-t STDIN)); __END__ =head1 NAME sample - Using GetOpt::Long and Pod::Usage =head1 SYNOPSIS sample [options] [file ...] Options: -help brief help message -man full documentation =head1 OPTIONS =over 8 =item B<-help> Print a brief help message and exits. =item B<-man> Prints the manual page and exits. =back =head1 DESCRIPTION B<This program> will read the given input file(s) and do something useful with the contents thereof. =cut=head1 CAVEATSBy default, B<pod2usage()> will use C<$0> as the path to the pod inputfile. Unfortunately, not all systems on which Perl runs will set C<$0>properly (although if C<$0> isn't found, B<pod2usage()> will searchC<$ENV{PATH}> or else the list specified by the C<-pathlist> option).If this is the case for your system, you may need to explicitly specifythe path to the pod docs for the invoking script using somethingsimilar to the following: pod2usage(-exitval => 2, -input => "/path/to/your/pod/docs");In the pathological case that a script is called via a relative pathI<and> the script itself changes the current working directory(see L<perlfunc/chdir>) I<before> calling pod2usage, Pod::Usage willfail even on robust platforms. Don't do that.=head1 AUTHORPlease report bugs using L<http://rt.cpan.org>.Brad Appleton E<lt>bradapp@enteract.comE<gt>Based on code for B<Pod::Text::pod2text()> written byTom Christiansen E<lt>tchrist@mox.perl.comE<gt>=head1 ACKNOWLEDGEMENTSSteven McDougall E<lt>swmcd@world.std.comE<gt> for his help and patiencewith re-writing this manpage.=cut#############################################################################use strict;#use diagnostics;use Carp;use Config;use Exporter;use File::Spec;use vars qw(@ISA @EXPORT);@EXPORT = qw(&pod2usage);BEGIN { if ( $] >= 5.005_58 ) { require Pod::Text; @ISA = qw( Pod::Text ); } else { require Pod::PlainText; @ISA = qw( Pod::PlainText ); }}##---------------------------------------------------------------------------##---------------------------------## Function definitions begin here##---------------------------------sub pod2usage { local($_) = shift; my %opts; ## Collect arguments if (@_ > 0) { ## Too many arguments - assume that this is a hash and ## the user forgot to pass a reference to it. %opts = ($_, @_); } elsif (!defined $_) { $_ = ""; } elsif (ref $_) { ## User passed a ref to a hash %opts = %{$_} if (ref($_) eq 'HASH'); } elsif (/^[-+]?\d+$/) { ## User passed in the exit value to use $opts{"-exitval"} = $_; } else { ## User passed in a message to print before issuing usage. $_ and $opts{"-message"} = $_; } ## Need this for backward compatibility since we formerly used ## options that were all uppercase words rather than ones that ## looked like Unix command-line options. ## to be uppercase keywords) %opts = map { my $val = $opts{$_}; s/^(?=\w)/-/; /^-msg/i and $_ = '-message'; /^-exit/i and $_ = '-exitval'; lc($_) => $val; } (keys %opts); ## Now determine default -exitval and -verbose values to use if ((! defined $opts{"-exitval"}) && (! defined $opts{"-verbose"})) { $opts{"-exitval"} = 2; $opts{"-verbose"} = 0; } elsif (! defined $opts{"-exitval"}) { $opts{"-exitval"} = ($opts{"-verbose"} > 0) ? 1 : 2; } elsif (! defined $opts{"-verbose"}) { $opts{"-verbose"} = (lc($opts{"-exitval"}) eq "noexit" || $opts{"-exitval"} < 2); } ## Default the output file $opts{"-output"} = (lc($opts{"-exitval"}) eq "noexit" || $opts{"-exitval"} < 2) ? \*STDOUT : \*STDERR unless (defined $opts{"-output"}); ## Default the input file $opts{"-input"} = $0 unless (defined $opts{"-input"}); ## Look up input file in path if it doesnt exist. unless ((ref $opts{"-input"}) || (-e $opts{"-input"})) { my ($dirname, $basename) = ('', $opts{"-input"}); my $pathsep = ($^O =~ /^(?:dos|os2|MSWin32)$/) ? ";" : (($^O eq 'MacOS' || $^O eq 'VMS') ? ',' : ":"); my $pathspec = $opts{"-pathlist"} || $ENV{PATH} || $ENV{PERL5LIB}; my @paths = (ref $pathspec) ? @$pathspec : split($pathsep, $pathspec); for $dirname (@paths) { $_ = File::Spec->catfile($dirname, $basename) if length; last if (-e $_) && ($opts{"-input"} = $_); } } ## Now create a pod reader and constrain it to the desired sections. my $parser = new Pod::Usage(USAGE_OPTIONS => \%opts); if ($opts{"-verbose"} == 0) { $parser->select('SYNOPSIS\s*'); } elsif ($opts{"-verbose"} == 1) { my $opt_re = '(?i)' . '(?:OPTIONS|ARGUMENTS)' . '(?:\s*(?:AND|\/)\s*(?:OPTIONS|ARGUMENTS))?'; $parser->select( 'SYNOPSIS', $opt_re, "DESCRIPTION/$opt_re" ); } elsif ($opts{"-verbose"} == 99) { $parser->select( $opts{"-sections"} ); $opts{"-verbose"} = 1; } ## Now translate the pod document and then exit with the desired status if ( !$opts{"-noperldoc"} and $opts{"-verbose"} >= 2 and !ref($opts{"-input"}) and $opts{"-output"} == \*STDOUT ) { ## spit out the entire PODs. Might as well invoke perldoc my $progpath = File::Spec->catfile($Config{scriptdir}, "perldoc"); system($progpath, $opts{"-input"}); } else { $parser->parse_from_file($opts{"-input"}, $opts{"-output"}); } exit($opts{"-exitval"}) unless (lc($opts{"-exitval"}) eq 'noexit');}##---------------------------------------------------------------------------##-------------------------------## Method definitions begin here##-------------------------------sub new { my $this = shift; my $class = ref($this) || $this; my %params = @_; my $self = {%params}; bless $self, $class; if ($self->can('initialize')) { $self->initialize(); } else { $self = $self->SUPER::new(); %$self = (%$self, %params); } return $self;}sub select { my ($self, @res) = @_; if ($ISA[0]->can('select')) { $self->SUPER::select(@_); } else { $self->{USAGE_SELECT} = \@res; }}# Override Pod::Text->seq_i to return just "arg", not "*arg*".sub seq_i { return $_[1] }# This overrides the Pod::Text method to do something very akin to what# Pod::Select did as well as the work done below by preprocess_paragraph.# Note that the below is very, very specific to Pod::Text.sub _handle_element_end { my ($self, $element) = @_; if ($element eq 'head1') { $$self{USAGE_HEAD1} = $$self{PENDING}[-1][1]; $$self{PENDING}[-1][1] =~ s/^\s*SYNOPSIS\s*$/USAGE/; } elsif ($element eq 'head2') { $$self{USAGE_HEAD2} = $$self{PENDING}[-1][1]; } if ($element eq 'head1' || $element eq 'head2') { $$self{USAGE_SKIPPING} = 1; my $heading = $$self{USAGE_HEAD1}; $heading .= '/' . $$self{USAGE_HEAD2} if defined $$self{USAGE_HEAD2}; for (@{ $$self{USAGE_SELECT} }) { if ($heading =~ /^$_\s*$/) { $$self{USAGE_SKIPPING} = 0; last; } } # Try to do some lowercasing instead of all-caps in headings, and use # a colon to end all headings. local $_ = $$self{PENDING}[-1][1]; s{([A-Z])([A-Z]+)}{((length($2) > 2) ? $1 : lc($1)) . lc($2)}ge; s/\s*$/:/ unless (/:\s*$/); $_ .= "\n"; $$self{PENDING}[-1][1] = $_; } if ($$self{USAGE_SKIPPING}) { pop @{ $$self{PENDING} }; } else { $self->SUPER::_handle_element_end($element); }}sub start_document { my $self = shift; $self->SUPER::start_document(); my $msg = $self->{USAGE_OPTIONS}->{-message} or return 1; my $out_fh = $self->output_fh(); print $out_fh "$msg\n";}sub begin_pod { my $self = shift; $self->SUPER::begin_pod(); ## Have to call superclass my $msg = $self->{USAGE_OPTIONS}->{-message} or return 1; my $out_fh = $self->output_handle(); print $out_fh "$msg\n";}sub preprocess_paragraph { my $self = shift; local $_ = shift; my $line = shift; ## See if this is a heading and we arent printing the entire manpage. if (($self->{USAGE_OPTIONS}->{-verbose} < 2) && /^=head/) { ## Change the title of the SYNOPSIS section to USAGE s/^=head1\s+SYNOPSIS\s*$/=head1 USAGE/; ## Try to do some lowercasing instead of all-caps in headings s{([A-Z])([A-Z]+)}{((length($2) > 2) ? $1 : lc($1)) . lc($2)}ge; ## Use a colon to end all headings s/\s*$/:/ unless (/:\s*$/); $_ .= "\n"; } return $self->SUPER::preprocess_paragraph($_);}1; # keep require happy
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -