File Coverage

blib/lib/OptArgs2.pm
Criterion Covered Total %
statement 56 86 65.1
branch 10 26 38.4
condition 11 41 26.8
subroutine 14 21 66.6
pod 9 11 81.8
total 100 185 54.0


line stmt bran cond sub pod time code
1             package OptArgs2;
2 6     6   576535 use strict;
  6         12  
  6         198  
3 6     6   49 use warnings;
  6         10  
  6         271  
4 6     6   3407 use Encode::Locale 'decode_argv';
  6         143777  
  6         471  
5 6     6   3290 use OptArgs2::Cmd;
  6         30  
  6         325  
6             use Exporter::Tidy
7 6         52 default => [qw/class_optargs cmd optargs subcmd arg opt/],
8 6     6   8933 other => [qw/usage cols rows/];
  6         98  
9              
10             our $VERSION = 'v2.0.17';
11             our @CARP_NOT = (
12             qw/
13             OptArgs2
14             OptArgs2::Arg
15             OptArgs2::Cmd
16             OptArgs2::CmdBase
17             OptArgs2::Opt
18             OptArgs2::OptArgBase
19             OptArgs2::SubCmd
20             /
21             );
22              
23             # constants
24             sub USAGE_USAGE() { 'Usage' } # default
25             sub USAGE_HELP() { 'Help' }
26             sub USAGE_HELPTREE() { 'HelpTree' }
27             sub USAGE_HELPSUMMARY() { 'HelpSummary' }
28              
29             our $CURRENT; # legacy interface
30             my %COMMAND;
31             my @chars;
32              
33             sub _chars {
34 0 0   0   0 if ( $^O eq 'MSWin32' ) {
35 0         0 require Win32::Console;
36 0         0 @chars = Win32::Console->new()->Size();
37             }
38             else {
39 0         0 require Term::Size::Perl;
40 0         0 @chars = Term::Size::Perl::chars();
41             }
42 0         0 \@chars;
43             }
44              
45             sub cols {
46 0   0 0 1 0 $chars[0] // _chars()->[0];
47             }
48              
49             sub rows {
50 0   0 0 1 0 $chars[1] // _chars()->[1];
51             }
52              
53             sub die_paged {
54 7   50 7 0 32 my $err = shift // 'die_paged($ERR)';
55 7 50       46 if ( -t STDERR ) {
56 0         0 my $lines = scalar( split /\n/, $err );
57 0 0       0 $lines++ if $err =~ m/\n\z/;
58              
59 0 0       0 if ( $lines >= OptArgs2::rows() ) {
60 0         0 require OptArgs2::Pager;
61 0         0 my $pager = OptArgs2::Pager->new( auto => 0 );
62 0         0 local *STDERR = $pager->fh;
63 0         0 die $err;
64             }
65             }
66              
67 7         95 die $err;
68             }
69              
70             my %error_types = (
71             CmdExists => undef,
72             CmdNotFound => undef,
73             Conflict => undef,
74             DuplicateAlias => undef,
75             InvalidIsa => undef,
76             ParentCmdNotFound => undef,
77             SubCmdExists => undef,
78             UndefOptArg => undef,
79             Usage => undef,
80             );
81              
82             package OptArgs2::Status {
83             use overload
84 7     7   288 bool => sub { 1 },
85 0     0   0 '""' => sub { ${ $_[0] } },
  0         0  
86 6     6   3659 fallback => 1;
  6         12  
  6         76  
87             }
88              
89             sub croak {
90 2     2 0 19 require Carp;
91 2   33     9 my $type = shift // Carp::croak( 'Usage', 'croak($TYPE, [$msg])' );
92 2         5 my $pkg = 'OptArgs2::Error::' . $type;
93 2   33     7 my $msg = shift // "($pkg)";
94 2 50       7 $msg = sprintf( $msg, @_ ) if @_;
95              
96             Carp::croak( 'Usage', "unknown error type: $type" )
97 2 50       10 unless exists $error_types{$type};
98              
99 2         759 $msg .= ' ' . Carp::longmess('');
100              
101 6     6   1418 no strict 'refs';
  6         15  
  6         4801  
102 2         10 *{ $pkg . '::ISA' } = ['OptArgs2::Status'];
  2         41  
103              
104 2         15 die_paged( bless \$msg, $pkg );
105             }
106              
107             sub class_optargs {
108 14   33 14 1 10089 my $class = shift
109             || croak( 'Usage', 'class_optargs($CMD,[@argv])' );
110              
111 14   33     80 my $cmd = $COMMAND{$class}
112             || croak( 'CmdNotFound', 'command class not found: ' . $class );
113              
114 14         37 my @source = @_;
115              
116 14 100 100     106 if ( !@_ and @ARGV ) {
117 4         21 decode_argv(Encode::FB_CROAK);
118 4         562 @source = @ARGV;
119             }
120              
121 14         62 $cmd->parse(@source);
122             }
123              
124             sub cmd {
125 11   33 11 1 610915 my $class = shift || croak( 'Usage', 'cmd($CLASS,@args)' );
126              
127             croak( 'CmdExists', "command already defined: $class" )
128 11 50       92 if exists $COMMAND{$class};
129              
130 11         118 $COMMAND{$class} = OptArgs2::Cmd->new( class => $class, @_ );
131             }
132              
133             sub optargs {
134 4     4 1 706987 my $class = caller;
135              
136 4 0 33     18 if ( !@_ and exists $COMMAND{$class} ) { # Legacy interface
137 0         0 return ( class_optargs($class) )[1];
138             }
139              
140 4         31 delete $COMMAND{$class};
141 4         18 cmd( $class, @_ );
142 4         16 ( class_optargs($class) )[1];
143             }
144              
145             sub subcmd {
146 6   33 6 1 351821 my $class = shift || croak( 'Usage', 'subcmd($CLASS,%%args)' );
147              
148             croak( 'SubCmdExists', "subcommand already defined: $class" )
149 6 50       19 if exists $COMMAND{$class};
150              
151 6 100       55 croak( 'ParentCmdNotFound',
152             "no '::' in class '$class' - must have a parent" )
153             unless $class =~ m/(.+)::(.+)/;
154              
155 5         19 my $parent_class = $1;
156              
157             croak( 'ParentCmdNotFound', "parent class not found: " . $parent_class )
158 5 50       23 unless exists $COMMAND{$parent_class};
159              
160 5         27 $COMMAND{$class} = $COMMAND{$parent_class}->add_cmd(
161             class => $class,
162             @_
163             );
164             }
165              
166             sub usage {
167 0   0 0 1   my $class = shift || do {
168             my ($pkg) = caller;
169             $pkg;
170             };
171 0           my $style = shift;
172              
173             croak( 'CmdNotFound', "command not found: $class" )
174 0 0         unless exists $COMMAND{$class};
175              
176 0           return $COMMAND{$class}->usage_string($style);
177             }
178              
179             # Legacy interface, no longer documented
180              
181             sub arg {
182 0     0 1   my $name = shift;
183 0           my $class = scalar caller;
184              
185 0   0       $OptArgs2::CURRENT //= cmd( $class, comment => '' );
186 0           $OptArgs2::CURRENT->add_arg(
187             name => $name,
188             @_,
189             );
190              
191             }
192              
193             sub opt {
194 0     0 1   my $name = shift;
195 0           my $class = scalar caller;
196              
197 0   0       $OptArgs2::CURRENT //= cmd( $class, comment => '' );
198 0           $OptArgs2::CURRENT->add_opt(
199             name => $name,
200             @_,
201             );
202             }
203              
204             1;
205              
206             __END__