File Coverage

blib/lib/OptArgs.pm
Criterion Covered Total %
statement 346 365 94.7
branch 160 206 77.6
condition 58 82 70.7
subroutine 20 21 95.2
pod 7 7 100.0
total 591 681 86.7


line stmt bran cond sub pod time code
1             package OptArgs;
2 11     11   334752 use strict;
  11         21  
  11         383  
3 11     11   53 use warnings;
  11         15  
  11         346  
4 11     11   45 use Carp qw/croak carp/;
  11         16  
  11         586  
5 11     11   6805 use Encode qw/decode/;
  11         167522  
  11         942  
6             use Exporter::Tidy
7 11         68 default => [qw/opt arg optargs usage subcmd/],
8 11     11   11184 other => [qw/dispatch class_optargs/];
  11         98  
9 11     11   8982 use Getopt::Long qw/GetOptionsFromArray/;
  11         130857  
  11         89  
10 11     11   3649 use List::Util qw/max/;
  11         18  
  11         49926  
11              
12             our $VERSION = '0.1.15_1';
13             our $COLOUR = 0;
14             our $ABBREV = 0;
15             our $SORT = 0;
16              
17             my %seen; # hash of hashes keyed by 'caller', then opt/arg name
18             my %opts; # option configuration keyed by 'caller'
19             my %args; # argument configuration keyed by 'caller'
20             my %caller; # current 'caller' keyed by real caller
21             my %desc; # sub-command descriptions
22             my %dispatching; # track optargs() calls from dispatch classes
23             my %hidden; # subcmd hiding by default
24              
25             # internal method for App::optargs
26             sub _cmdlist {
27 32   33 32   49 my $package = shift || croak '_cmdlist($package)';
28 32         32 $package =~ s/-/_/g;
29 32         32 my @list = ($package);
30              
31 32 50       56 if ( exists $args{$package} ) {
32 12 50       38 my @subcmd =
33 32         39 map { exists $_->{subcommands} ? $_->{subcommands} : () }
34 32         23 @{ $args{$package} };
35              
36 12 50       19 push( @subcmd,
37 32         33 map { exists $_->{fallback} ? [ uc $_->{fallback}->{name} ] : () }
38 32         24 @{ $args{$package} } );
39              
40 32 50       35 if ($SORT) {
41 0         0 foreach my $subcmd ( sort map { @$_ } @subcmd ) {
  0         0  
42 0         0 push( @list, _cmdlist( $package . '::' . $subcmd ) );
43             }
44             }
45             else {
46 32         40 foreach my $subcmd ( map { @$_ } @subcmd ) {
  12         25  
47 28         54 push( @list, _cmdlist( $package . '::' . $subcmd ) );
48             }
49             }
50             }
51 32         62 return @list;
52             }
53              
54             # ------------------------------------------------------------------------
55             # Sub-command definition
56             #
57             # This works by faking caller context in opt() and arg()
58             # ------------------------------------------------------------------------
59             my %subcmd_params = (
60             cmd => undef,
61             comment => undef,
62             hidden => undef,
63              
64             # alias => '',
65             # ishelp => undef,
66             );
67              
68             my @subcmd_required = (qw/cmd comment/);
69              
70             sub subcmd {
71 18     18 1 1075 my $params = {@_};
72 18         21 my $caller = caller;
73              
74 18 100       24 if ( my @missing = grep { !exists $params->{$_} } @subcmd_required ) {
  36         94  
75 1         143 croak "missing required parameter(s): @missing";
76             }
77              
78 17 50       35 if ( my @invalid = grep { !exists $subcmd_params{$_} } keys %$params ) {
  36         61  
79 0         0 my @valid = keys %subcmd_params;
80 0         0 croak "invalid parameter(s): @invalid (valid: @valid)";
81             }
82              
83             # croak "'ishelp' can only be applied to Bool opts"
84             # if $params->{ishelp} and $params->{isa} ne 'Bool';
85              
86 10         14 my @cmd =
87             ref $params->{cmd} eq 'ARRAY'
88 17 100       46 ? @{ $params->{cmd} }
89             : ( $params->{cmd} );
90 17 50       29 croak 'missing cmd elements' unless @cmd;
91              
92 17         17 my $name = pop @cmd;
93 17         25 my $parent = join( '::', $caller, @cmd );
94 17         22 $parent =~ s/-/_/g;
95              
96 17 100       162 croak "parent command not found: @cmd" unless $seen{$parent};
97              
98 16         21 my $package = $parent . '::' . $name;
99 16         19 $package =~ s/-/_/g;
100              
101 16 100       130 croak "sub command already defined: @cmd $name" if $seen{$package};
102              
103 15         15 $caller{$caller} = $package;
104 15         30 $desc{$package} = $params->{comment};
105 15         20 $seen{$package} = {};
106 15         24 $opts{$package} = [];
107 15         18 $args{$package} = [];
108 15         26 $hidden{$package} = $params->{hidden};
109              
110 15         13 my $parent_arg = ( grep { $_->{isa} eq 'SubCmd' } @{ $args{$parent} } )[0];
  16         28  
  15         19  
111 15         18 push( @{ $parent_arg->{subcommands} }, $name );
  15         24  
112              
113 15         34 return;
114             }
115              
116             # ------------------------------------------------------------------------
117             # Option definition
118             # ------------------------------------------------------------------------
119             my %opt_params = (
120             isa => undef,
121             comment => undef,
122             default => undef,
123             alias => '',
124             ishelp => undef,
125             hidden => undef,
126             );
127              
128             my @opt_required = (qw/isa comment/);
129              
130             my %opt_isa = (
131             'Bool' => '!',
132             'Counter' => '+',
133             'Str' => '=s',
134             'Int' => '=i',
135             'Num' => '=f',
136             'ArrayRef' => '=s@',
137             'HashRef' => '=s%',
138             );
139              
140             sub opt {
141 43     43 1 4045 my $name = shift;
142 43         104 my $params = {@_};
143 43         58 my $caller = caller;
144 43   66     140 my $package = $caller{$caller} || $caller;
145              
146 43 100       367 croak 'usage: opt $name => (%parameters)' unless $name;
147 39 100       338 croak "'$name' already defined" if $seen{$package}->{$name};
148              
149 37 100       55 if ( my @missing = grep { !exists $params->{$_} } @opt_required ) {
  74         166  
150 2         167 croak "missing required parameter(s): @missing";
151             }
152              
153 35 100       74 if ( my @invalid = grep { !exists $opt_params{$_} } keys %$params ) {
  91         172  
154 1         9 my @valid = keys %opt_params;
155 1         108 croak "invalid parameter(s): @invalid (valid: @valid)";
156             }
157              
158 34 100 100     193 croak "'ishelp' can only be applied to Bool opts"
159             if $params->{ishelp} and $params->{isa} ne 'Bool';
160              
161 33 100       249 croak "unknown type: $params->{isa}"
162             unless exists $opt_isa{ $params->{isa} };
163              
164 32         148 $params = { %opt_params, %$params };
165 32         74 $params->{package} = $package;
166 32         49 $params->{name} = $name;
167 32         45 $params->{length} = length $name;
168 32         29 $params->{acount} = do { my @tmp = split( '|', $params->{alias} ) };
  32         103  
169 32         56 $params->{type} = 'opt';
170 32         42 $params->{ISA} = $params->{name};
171              
172 32 100       172 if ( ( my $dashed = $params->{name} ) =~ s/_/-/g ) {
173 3         6 $params->{dashed} = $dashed;
174 3         13 $params->{ISA} .= '|' . $dashed;
175             }
176              
177 32 100       72 $params->{ISA} .= '|' . $params->{alias} if $params->{alias};
178 32         55 $params->{ISA} .= $opt_isa{ $params->{isa} };
179              
180 32         26 push( @{ $opts{$package} }, $params );
  32         49  
181 32   100     76 $args{$package} ||= [];
182 32         49 $seen{$package}->{$name}++;
183              
184 32         59 return;
185             }
186              
187             # ------------------------------------------------------------------------
188             # Argument definition
189             # ------------------------------------------------------------------------
190             my %arg_params = (
191             isa => undef,
192             comment => undef,
193             required => undef,
194             default => undef,
195             greedy => undef,
196             fallback => undef,
197             );
198              
199             my @arg_required = (qw/isa comment/);
200              
201             my %arg_isa = (
202             'Str' => '=s',
203             'Int' => '=i',
204             'Num' => '=f',
205             'ArrayRef' => '=s@',
206             'HashRef' => '=s%',
207             'SubCmd' => '=s',
208             );
209              
210             sub arg {
211 32     32 1 6969 my $name = shift;
212 32         88 my $params = {@_};
213 32         47 my $caller = caller;
214 32   66     126 my $package = $caller{$caller} || $caller;
215              
216 32 100       484 croak 'usage: arg $name => (%parameters)' unless $name;
217 28 100       384 croak "'$name' already defined" if $seen{$package}->{$name};
218              
219 26 100       45 if ( my @missing = grep { !exists $params->{$_} } @arg_required ) {
  52         146  
220 2         300 croak "missing required parameter(s): @missing";
221             }
222              
223 24 100       55 if ( my @invalid = grep { !exists $arg_params{$_} } keys %$params ) {
  65         121  
224 1         5 my @valid = keys %arg_params;
225 1         109 croak "invalid parameter(s): @invalid (valid: @valid)";
226             }
227              
228 23 100       186 croak "unknown type: $params->{isa}"
229             unless exists $arg_isa{ $params->{isa} };
230              
231 22 100 100     184 croak "'default' and 'required' cannot be used together"
232             if defined $params->{default} and defined $params->{required};
233              
234 21 100 100     215 croak "'fallback' only valid with isa 'SubCmd'"
235             if $params->{fallback} and $params->{isa} ne 'SubCmd';
236              
237 20 100 100     222 croak "fallback must be a hashref"
238             if defined $params->{fallback} && ref $params->{fallback} ne 'HASH';
239              
240 19         29 $params->{package} = $package;
241 19         40 $params->{name} = $name;
242 19         28 $params->{length} = length $name;
243 19         26 $params->{acount} = 0;
244 19         37 $params->{type} = 'arg';
245 19         49 $params->{ISA} = $params->{name} . $arg_isa{ $params->{isa} };
246              
247 19         45 push( @{ $args{$package} }, $params );
  19         30  
248 19   100     62 $opts{$package} ||= [];
249 19         31 $seen{$package}->{$name}++;
250              
251 19 100       46 if ( $params->{fallback} ) {
252 1         4 my $p = $package . '::' . uc $params->{fallback}->{name};
253 1         3 $p =~ s/-/_/g;
254 1         2 $opts{$p} = [];
255 1         2 $args{$p} = [];
256 1         2 $desc{$p} = $params->{fallback}->{comment};
257             }
258              
259 19         35 return;
260             }
261              
262             # ------------------------------------------------------------------------
263             # Usage message generation
264             # ------------------------------------------------------------------------
265              
266             sub _usage {
267 7     7   11 my $caller = shift;
268 7         10 my $error = shift;
269 7         7 my $ishelp = shift;
270 7         38 my $terminal = -t STDOUT;
271 7 50 66     31 my $red = ( $COLOUR && $terminal ) ? "\e[0;31m" : '';
272 7         11 my $yellow = ''; #( $COLOUR && $terminal ) ? "\e[0;33m" : '';
273 7         8 my $grey = ''; #( $COLOUR && $terminal ) ? "\e[1;30m" : '';
274 7 50 66     27 my $reset = ( $COLOUR && $terminal ) ? "\e[0m" : '';
275 7         8 my $parent = $caller;
276 7         9 my @args = @{ $args{$caller} };
  7         13  
277 7         7 my @opts = @{ $opts{$caller} };
  7         14  
278 7         7 my @parents;
279             my @usage;
280 0         0 my @uargs;
281 0         0 my @uopts;
282 0         0 my $usage;
283              
284 7         43 require File::Basename;
285 7 50       283 my $me = File::Basename::basename( defined &static::list ? $^X : $0 );
286              
287 7 100       20 if ($error) {
288 3         10 $usage .= "${red}error:$reset $error\n\n";
289             }
290              
291 7 100       26 $usage .= $yellow . ( $ishelp ? 'help:' : 'usage:' ) . $reset . ' ' . $me;
292              
293 7         49 while ( $parent =~ s/(.*)::(.*)/$1/ ) {
294 8 100       17 last unless $seen{$parent};
295 3         8 ( my $name = $2 ) =~ s/_/-/g;
296 3         5 unshift( @parents, $name );
297 3         4 unshift( @opts, @{ $opts{$parent} } );
  3         15  
298             }
299              
300 7 100       19 $usage .= ' ' . join( ' ', @parents ) if @parents;
301              
302 7         13 my $last = $args[$#args];
303              
304 7 100       22 if ($last) {
305 6         13 foreach my $def (@args) {
306 6         11 $usage .= ' ';
307 6 50       47 $usage .= '[' unless $def->{required};
308 6         17 $usage .= uc $def->{name};
309 6 50       16 $usage .= '...' if $def->{greedy};
310 6 50       18 $usage .= ']' unless $def->{required};
311 6         29 push( @uargs, [ uc $def->{name}, $def->{comment} ] );
312             }
313             }
314              
315 7 50       24 $usage .= ' [OPTIONS...]' if @opts;
316              
317 7         9 $usage .= "\n";
318              
319 7 100 66     34 $usage .= "\n ${grey}Synopsis:$reset\n $desc{$caller}\n"
320             if $ishelp and $desc{$caller};
321              
322 7 50 66     40 if ( $ishelp and my $version = $caller->VERSION ) {
323 0         0 $usage .= "\n ${grey}Version:$reset\n $version\n";
324             }
325              
326 7 100 100     44 if ( $last && $last->{isa} eq 'SubCmd' ) {
327 4         32 $usage .= "\n ${grey}" . ucfirst( $last->{name} ) . ":$reset\n";
328              
329 4         8 my @subcommands = @{ $last->{subcommands} };
  4         13  
330              
331 4 0 0     12 push( @subcommands, uc $last->{fallback}->{name} )
      33        
332             if (
333             exists $last->{fallback}
334             && ( $ishelp
335             or !$last->{fallback}->{hidden} )
336             );
337              
338 4 100       10 @subcommands = sort @subcommands if $SORT;
339              
340 4         9 foreach my $subcommand (@subcommands) {
341 10         14 my $pkg = $last->{package} . '::' . $subcommand;
342 10         13 $pkg =~ s/-/_/g;
343 10 50 66     31 next if $hidden{$pkg} and !$ishelp;
344 10         32 push( @usage, [ $subcommand, $desc{$pkg} ] );
345             }
346              
347             }
348              
349 7 100       19 @opts = sort { $a->{name} cmp $b->{name} } @opts if $SORT;
  3         5  
350              
351 7         13 foreach my $opt (@opts) {
352 18 50 33     42 next if $opt->{hidden} and !$ishelp;
353              
354 18         38 ( my $name = $opt->{name} ) =~ s/_/-/g;
355 18 100       34 $name .= ',' if $opt->{alias};
356 18 100       63 push(
357             @uopts,
358             [
359             '--' . $name,
360             $opt->{alias}
361             ? '-' . $opt->{alias}
362             : '',
363             $opt->{comment}
364             ]
365             );
366             }
367              
368 7 50       18 if (@uopts) {
369 7         12 my $w1 = max( map { length $_->[0] } @uopts );
  18         51  
370 7         17 my $fmt = '%-' . $w1 . "s %s";
371              
372 7         10 @uopts = map { [ sprintf( $fmt, $_->[0], $_->[1] ), $_->[2] ] } @uopts;
  18         75  
373             }
374              
375 7         14 my $w1 = max( map { length $_->[0] } @usage, @uargs, @uopts );
  34         46  
376 7         16 my $format = ' %-' . $w1 . "s %s\n";
377              
378 7 100       17 if (@usage) {
379 4         6 foreach my $row (@usage) {
380 10         24 $usage .= sprintf( $format, @$row );
381             }
382             }
383 7 100 100     43 if ( @uargs and $last->{isa} ne 'SubCmd' ) {
384 2         7 $usage .= "\n ${grey}Arguments:$reset\n";
385 2         3 foreach my $row (@uargs) {
386 2         10 $usage .= sprintf( $format, @$row );
387             }
388             }
389 7 50       16 if (@uopts) {
390 7         15 $usage .= "\n ${grey}Options:$reset\n";
391 7         11 foreach my $row (@uopts) {
392 18         39 $usage .= sprintf( $format, @$row );
393             }
394             }
395              
396 7         10 $usage .= "\n";
397 7         91 return bless( \$usage, 'OptArgs::Usage' );
398             }
399              
400             sub _synopsis {
401 32     32   31 my $caller = shift;
402 32         22 my $parent = $caller;
403 32         22 my @args = @{ $args{$caller} };
  32         54  
404 32         24 my @parents;
405              
406 32         92 require File::Basename;
407 32         656 my $usage = File::Basename::basename($0);
408              
409 32         132 while ( $parent =~ s/(.*)::(.*)/$1/ ) {
410 88 100       153 last unless $seen{$parent};
411 56         62 ( my $name = $2 ) =~ s/_/-/g;
412 56         187 unshift( @parents, $name );
413             }
414              
415 32 100       69 $usage .= ' ' . join( ' ', @parents ) if @parents;
416              
417 32 100       59 if ( my $last = $args[$#args] ) {
418 12         14 foreach my $def (@args) {
419 12         11 $usage .= ' ';
420 12 50       20 $usage .= '[' unless $def->{required};
421 12         17 $usage .= uc $def->{name};
422 12 50       24 $usage .= '...' if $def->{greedy};
423 12 50       31 $usage .= ']' unless $def->{required};
424             }
425             }
426              
427 32         90 return 'usage: ' . $usage . "\n";
428             }
429              
430             sub usage {
431 0     0 1 0 my $caller = caller;
432 0         0 return _usage( $caller, @_ );
433             }
434              
435             # ------------------------------------------------------------------------
436             # Option/Argument processing
437             # ------------------------------------------------------------------------
438             sub _optargs {
439 50     50   55 my $caller = shift;
440 50         82 my $source = \@_;
441 50         57 my $package = $caller;
442              
443 50 100 100     208 if ( !@_ and @ARGV ) {
444             my $CODESET =
445 27         35 eval { require I18N::Langinfo; I18N::Langinfo::CODESET() };
  27         4463  
  27         5113  
446              
447 27 50       60 if ($CODESET) {
448 27         70 my $codeset = I18N::Langinfo::langinfo($CODESET);
449 27         106 $_ = decode( $codeset, $_ ) for @ARGV;
450             }
451              
452 27         5121 $source = \@ARGV;
453             }
454              
455 50 50       78 map { Carp::croak('_optargs argument undefined!') if !defined $_ } @$source;
  84         187  
456              
457 50 100 66     217 croak "no option or argument defined for $caller"
458             unless exists $opts{$package}
459             or exists $args{$package};
460              
461 49         184 Getopt::Long::Configure(qw/pass_through no_auto_abbrev no_ignore_case/);
462              
463 49         2318 my @config = ( @{ $opts{$package} }, @{ $args{$package} } );
  49         85  
  49         105  
464              
465 49         54 my $ishelp;
466             my $missing_required;
467 49         63 my $optargs = {};
468 49         43 my @coderef_default_keys;
469              
470 49         130 while ( my $try = shift @config ) {
471 210         150 my $result;
472              
473 210 100       404 if ( $try->{type} eq 'opt' ) {
    50          
474 155         373 GetOptionsFromArray( $source, $try->{ISA} => \$result );
475             }
476             elsif ( $try->{type} eq 'arg' ) {
477 55 100 100     146 if (@$source) {
    100          
478 34 50       82 die _usage( $package, qq{Unknown option "$source->[0]"} )
479             if $source->[0] =~ m/^--\S/;
480              
481 34 50 0     85 die _usage( $package, qq{Unknown option "$source->[0]"} )
      33        
482             if $source->[0] =~ m/^-\S/
483             and !(
484             $source->[0] =~ m/^-\d/ and ( $try->{isa} ne 'Num'
485             or $try->{isa} ne 'Int' )
486             );
487              
488 34 100       54 if ( $try->{greedy} ) {
489 2         3 my @later;
490 2 50 33     5 if ( @config and @$source > @config ) {
491 0         0 push( @later, pop @$source ) for @config;
492             }
493              
494 2 50       5 if ( $try->{isa} eq 'ArrayRef' ) {
    50          
495 0         0 $result = [@$source];
496             }
497             elsif ( $try->{isa} eq 'HashRef' ) {
498 0         0 $result = { map { split /=/, $_ } @$source };
  0         0  
499             }
500             else {
501 2         5 $result = "@$source";
502             }
503              
504 2         7 shift @$source while @$source;
505 2         4 push( @$source, @later );
506             }
507             else {
508 32 100       91 if ( $try->{isa} eq 'ArrayRef' ) {
    100          
509 1         3 $result = [ shift @$source ];
510             }
511             elsif ( $try->{isa} eq 'HashRef' ) {
512 1         5 $result = { split /=/, shift @$source };
513             }
514             else {
515 30         43 $result = shift @$source;
516             }
517             }
518              
519             # TODO: type check using Param::Utils?
520             }
521             elsif ( $try->{required} and !$ishelp ) {
522 2         3 $missing_required++;
523 2         8 next;
524             }
525              
526 53 100 100     133 if ( $try->{isa} eq 'SubCmd' and $result ) {
527              
528             # look up abbreviated words
529 10 100       17 if ($ABBREV) {
530 6         791 require Text::Abbrev;
531 13         44 my %words =
532 13         37 map { m/^$package\:\:(\w+)$/; $1 => 1 }
  48         150  
533 6         52 grep { m/^$package\:\:(\w+)$/ }
534             keys %seen;
535 6         20 my %abbrev = Text::Abbrev::abbrev( keys %words );
536 6 50       313 $result = $abbrev{$result} if defined $abbrev{$result};
537             }
538              
539 10         17 my $newpackage = $package . '::' . $result;
540 10         20 $newpackage =~ s/-/_/g;
541              
542 10 100       24 if ( exists $seen{$newpackage} ) {
    50          
543 8         7 $package = $newpackage;
544 8         17 @config = grep { $_->{type} eq 'opt' } @config;
  0         0  
545 8         5 push( @config, @{ $opts{$package} }, @{ $args{$package} } );
  8         14  
  8         10  
546             }
547             elsif ( !$ishelp ) {
548 2 100       6 if ( $try->{fallback} ) {
549 1         2 unshift @$source, $result;
550 1         2 $try->{fallback}->{type} = 'arg';
551 1         1 unshift( @config, $try->{fallback} );
552 1         3 next;
553             }
554             else {
555 1         6 die _usage( $package,
556             "Unknown " . uc( $try->{name} ) . qq{ "$result"} );
557             }
558             }
559              
560 8         10 $result = undef;
561             }
562              
563             }
564              
565 206 100       17418 if ( defined $result ) {
    100          
566 51         103 $optargs->{ $try->{name} } = $result;
567             }
568             elsif ( defined $try->{default} ) {
569 16 100       45 push( @coderef_default_keys, $try->{name} )
570             if ref $try->{default} eq 'CODE';
571 16         32 $optargs->{ $try->{name} } = $result = $try->{default};
572             }
573              
574 206 100 100     794 $ishelp = 1 if $result and $try->{ishelp};
575              
576             }
577              
578 48 100       157 if ($ishelp) {
    100          
    100          
579 2         6 die _usage( $package, undef, 1 );
580             }
581             elsif ($missing_required) {
582 2         9 die _usage($package);
583             }
584             elsif (@$source) {
585 2         10 die _usage( $package,
586             qq{Unexpected option or argument "} . ( shift @$source ) . '"' );
587             }
588              
589             # Re-calculate the default if it was a subref
590 42         73 foreach my $key (@coderef_default_keys) {
591 8         454 $optargs->{$key} = $optargs->{$key}->( {%$optargs} );
592             }
593              
594 42         2429 return ( $package, $optargs );
595             }
596              
597             sub optargs {
598 37     37 1 2265 my $caller = caller;
599              
600 37 50       87 carp "optargs() called from dispatch handler"
601             if $dispatching{$caller};
602              
603 37         89 my ( $package, $optargs ) = _optargs( $caller, @_ );
604 34         196 return $optargs;
605             }
606              
607             sub class_optargs {
608 13     13 1 20 my $caller = shift;
609              
610 13 50       25 croak 'dispatch($class, [@argv])' unless $caller;
611 13 50       31 carp "optargs_class() called from dispatch handler"
612             if $dispatching{$caller};
613              
614 13 50       496 die $@ unless eval "require $caller;";
615              
616 13         23 my ( $class, $optargs );
617              
618 13 100       23 if (@_) {
619 12         14 my @args;
620              
621 12         23 foreach my $element (@_) {
622 27 50       37 if ( ref $element eq 'HASH' ) {
623             push( @args,
624             '--' . $_, defined $element->{$_} ? $element->{$_} : () )
625 0 0       0 for keys %$element;
626             }
627             else {
628 27         44 push( @args, $element );
629             }
630             }
631              
632 12         29 ( $class, $optargs ) = _optargs( $caller, @args );
633             }
634             else {
635 1         4 ( $class, $optargs ) = _optargs($caller);
636             }
637              
638 8 50       444 croak $@ unless eval "require $class;1;";
639 8         26 return ( $class, $optargs );
640             }
641              
642             sub dispatch {
643 16     16 1 6633 my $method = shift;
644 16         25 my $class = shift;
645              
646 16 100 100     229 croak 'dispatch($method, $class, [@argv])' unless $method and $class;
647 14 100       829 croak $@ unless eval "require $class;1;";
648              
649 13         44 my ( $package, $optargs ) = class_optargs( $class, @_ );
650              
651 8 50       295 croak $@ unless eval "require $package";
652              
653 8         61 my $sub = $package->can($method);
654 8 50       18 if ( !$sub ) {
655 0 0       0 croak $@ unless eval "require $package;";
656 0         0 $sub = $package->can($method);
657             }
658              
659 8 50       15 die "Can't find method $method via package $package" unless $sub;
660              
661 8         14 $dispatching{$class}++;
662 8         18 my @results = $sub->($optargs);
663 8         258 $dispatching{$class}--;
664 8 100       37 return @results if wantarray;
665 4         13 return $results[0];
666             }
667              
668             package OptArgs::Usage;
669             use overload
670 7     7   261 bool => sub { 1 },
671 7     7   813 '""' => sub { ${ $_[0] } },
  7         87  
672 11     11   78 fallback => 1;
  11         17  
  11         116  
673              
674             1;
675              
676             __END__