File Coverage

lib/Getopt/ArgParse/Parser.pm
Criterion Covered Total %
statement 543 562 96.6
branch 264 306 86.2
condition 116 141 82.2
subroutine 36 37 97.3
pod 0 15 0.0
total 959 1061 90.3


line stmt bran cond sub pod time code
1             package Getopt::ArgParse::Parser;
2              
3 20     20   249279 use Moo;
  20         260564  
  20         109  
4              
5 20     20   42676 use Getopt::Long qw(GetOptionsFromArray);
  20         245645  
  20         120  
6 20     20   16386 use Text::Wrap;
  20         48359  
  20         1219  
7 20     20   136 use Scalar::Util qw(blessed);
  20         27  
  20         1657  
8              
9 20     20   102 use File::Basename ();
  20         26  
  20         277  
10 20     20   6509 use Getopt::ArgParse::Namespace;
  20         40  
  20         1010  
11              
12             use constant {
13 20         143891 TYPE_UNDEF => 0,
14             TYPE_SCALAR => 1,
15             TYPE_ARRAY => 2,
16             TYPE_COUNT => 3,
17             TYPE_PAIR => 4, # key=value pair
18             TYPE_BOOL => 5,
19              
20             CONST_TRUE => 1,
21             CONST_FALSE => 0,
22              
23             # Export these?
24             ScalarArg => 'scalar',
25             ArrayArg => 'Array',
26             PairArg => 'Pair',
27             CountArg => 'Count',
28             BoolArg => 'Bool',
29              
30             # Internal
31             ERROR_PREFIX => 'Getopt::ArgParse: ',
32             PRINT_REQUIRED => 1,
33             PRINT_OPTIONAL => 2,
34 20     20   95 };
  20         23  
35              
36             # Allow customization
37             # default actions
38             my %Action2ClassMap = (
39             '_store' => 'Getopt::ArgParse::ActionStore',
40             '_append' => 'Getopt::ArgParse::ActionAppend',
41             '_count' => 'Getopt::ArgParse::ActionCount',
42             # Not supported - Maybe in the future
43             # '_help' => 'Getopt::ArgParse::ActionHelp',
44             # '_version' => 'Getopt::ArgParse::ActionVersion',
45             );
46              
47             my %Type2ConstMap = (
48             '' => TYPE_UNDEF(),
49             'Scalar' => TYPE_SCALAR(),
50             'Array' => TYPE_ARRAY(),
51             'Count' => TYPE_COUNT(),
52             'Pair' => TYPE_PAIR(),
53             'Bool' => TYPE_BOOL(),
54             );
55              
56              
57             sub _croak {
58 38     38   373 die join('', @_, "\n");
59             }
60              
61             # Program name. Default $0
62              
63             has prog => ( is => 'rw', required => 1, default => sub { File::Basename::basename($0) }, );
64              
65             # short one
66             has help => ( is => 'rw', required => 1, default => sub { '' }, );
67              
68             # long one
69             has description => ( is => 'rw', required => 1, default => sub { '' }, );
70              
71             has epilog => ( is => 'rw', required => 1, default => sub { '' }, );
72              
73             has error_prefix => (is => 'rw', default => sub { ERROR_PREFIX() }, );
74              
75             has aliases => (is => 'ro', default => sub { [] }); # for subcommand only
76              
77             # namespace() - Read/write
78             # Contains the parsed results.
79             has namespace => (
80             is => 'rw',
81             isa => sub {
82             return undef unless $_[0]; # allow undef
83             my $class = blessed $_[0];
84             die 'namespace doesn\'t comform to the required interface'
85             unless $class && $class->can('set_attr') && $class->can('get_attr');
86             },
87             );
88              
89             # parent - Readonly
90             has parents => (
91             is => 'ro',
92             isa => sub {
93             my $parents = shift;
94             for my $parent (@$parents) {
95             my $parent_class = blessed $parent;
96             die 'parent is not a Getopt::ArgParse::Parser'
97             unless $parent_class && $parent_class->isa(__PACKAGE__);
98             }
99             },
100             default => sub { [] },
101             );
102              
103             # parser_configs - Read/write
104              
105             # The configurations that will be passed to Getopt::Long::Configure(
106             # $self->parser_configs ) when parse_args is invoked.
107             has parser_configs => ( is => 'rw', required => 1, default => sub { [] }, );
108              
109             # Behavioural properties
110             #
111             # Print usage message if help is no, by default. Turn this off by
112             # setting this to a false value
113             has print_usage_if_help => (is => 'ro', default => 1);
114              
115             # internal properties
116              
117             has _option_position => ( is => 'rw', required => 1, default => sub { 0 } );
118              
119             # The current subcommand the same as namespace->current_command
120             has _command => ( is => 'rw');
121              
122             sub BUILD {
123 62     62 0 398 my $self = shift;
124              
125 62         163 $self->{-option_specs} = {};
126 62         127 $self->{-position_specs} = {};
127              
128 62         191 $self->add_argument(
129             '--help', '-h',
130             type => 'Bool',
131             dest => 'help',
132             help => 'show this help message and exit',
133             reset => 1,
134             );
135              
136             # merge
137 62         76 for my $parent (@{$self->parents}) {
  62         1244  
138 5         14 $self->copy($parent);
139             }
140             }
141              
142             #
143             sub _check_parent {
144 18     18   16 my $parent = shift;
145 18         41 my $parent_class = blessed $parent;
146 18 50 33     158 _croak 'Parent is not a Getopt::ArgParse::Parser'
147             unless $parent_class && $parent_class->isa(__PACKAGE__);
148             }
149              
150             sub copy {
151 5     5 0 6 my $self = shift;
152 5         4 my $parent = shift;
153              
154 5 50       9 _croak 'Parent is missing' unless $parent;
155 5         7 _check_parent($parent);
156              
157 5         7 $self->copy_args($parent);
158 5         14 $self->copy_parsers($parent);
159             }
160              
161             sub copy_args {
162 7     7 0 23 my $self = shift;
163 7         5 my $parent = shift;
164              
165 7 50       11 _croak 'Parent is missing' unless $parent;
166 7         12 _check_parent($parent);
167              
168 7         6 $self->add_arguments( @{ $parent->{-pristine_add_arguments} } );
  7         17  
169             }
170              
171             sub copy_parsers {
172 6     6 0 12 my $self = shift;
173 6         7 my $parent = shift;
174              
175 6 50       12 _croak 'Parent is missing' unless $parent;
176 6         9 _check_parent($parent);
177              
178 6 100       101 if (exists $parent->{-subparsers}) {
179 2         7 $self->add_subparsers(
180 2         2 @{$parent->{-pristine_add_subparsers}->[0]}
181             );
182              
183 2         2 for my $args (@{$parent->{-pristine_add_parser}}) {
  2         6  
184 6         20 my $command = $args->[0];
185 6 100       12 next if $command eq 'help';
186 4         13 $self->add_parser(
187             @$args,
188             parents => [ $parent->{-subparsers}{-parsers}{$command} ],
189             );
190             }
191             }
192             }
193              
194             #
195             # subcommands
196             #
197             sub add_subparsers {
198 16     16 0 3767 my $self = shift;
199              
200 16         21 push @{$self->{-pristine_add_subparsers}}, [ @_ ];
  16         70  
201              
202 16 100       211 _croak $self->error_prefix . 'Incorrect number of arguments' if scalar(@_) % 2;
203              
204 15         35 my $args = { @_ };
205              
206 15   100     83 my $title = (delete $args->{title} || 'subcommands') . ':';
207 15   100     91 my $description = delete $args->{description} || '';
208              
209 15 100       63 _croak $self->error_prefix . sprintf(
210             'Unknown parameters: %s',
211             join(',', keys %$args)
212             ) if keys %$args;
213              
214 14 100       52 if (exists $self->{-subparsers}) {
215 1         10 _croak $self->error_prefix . 'Subparsers already added';
216             }
217              
218 13         75 $self->{-subparsers}{-title} = $title;
219 13         35 $self->{-subparsers}{-description} = $description;
220 13         55 $self->{-subparsers}{-alias_map} = {};
221              
222 13         128 my $hp = $self->add_parser(
223             'help',
224             help => 'display help information about ' . $self->prog,
225             );
226              
227 13         176 $hp->add_arguments(
228             [
229             '--all', '-a',
230             help => 'Show the full usage',
231             type => 'Bool',
232             ],
233             [
234             'command',
235             help => 'Show the usage for this command',
236             dest => 'help_command',
237             nargs => 1,
238             ],
239             );
240              
241 13         51 return $self;
242             }
243              
244             # $command, aliases => [], help => ''
245             sub add_parser {
246 36     36 0 3512 my $self = shift;
247              
248 36 100       183 _croak $self->error_prefix . 'add_subparsers() is not called first' unless $self->{-subparsers};
249              
250 35         44 my $command = shift;
251              
252 35 100       132 _croak $self->error_prefix . 'Subcommand is empty' unless $command;
253              
254 34 100       105 _croak $self->error_prefix . 'Incorrect number of arguments' if scalar(@_) % 2;
255              
256 33 100       120 if (exists $self->{-subparsers}{-parsers}{$command}) {
257 1         8 _croak $self->error_prefix . "Subcommand $command already defined";
258             }
259              
260 32         66 my $args = { @_ };
261              
262 32   100     129 my $parents = delete $args->{parents} || [];
263 32         35 push @{ $self->{-pristine_add_parser} }, [ $command, %$args ];
  32         124  
264              
265 32 50       86 _croak $self->error_prefix . 'Add_subparsers() is not called first' unless $self->{-subparsers};
266              
267 32   100     100 my $help = delete $args->{help} || '';
268 32   100     128 my $description = delete $args->{description} || '';
269 32   100     110 my $aliases = delete $args->{aliases} || [];
270              
271 32 100       89 _croak $self->error_prefix . 'Aliases is not an arrayref'
272             if ref($aliases) ne 'ARRAY';
273              
274 31 100       78 _croak $self->error_prefix . sprintf(
275             'Unknown parameters: %s',
276             join(',', keys %$args)
277             ) if keys %$args;
278              
279 30         39 my $alias_map = {};
280              
281 30         57 for my $alias ($command, @$aliases) {
282 35 100       119 if (exists $self->{-subparsers}{-alias_map}{$alias}) {
283 1         9 _croak $self->error_prefix
284             . "Alias=$alias already used by command="
285             . $self->{-subparsers}{-alias_map}{$alias};
286             }
287             }
288              
289 29         118 $self->{-subparsers}{-alias_map}{$_} = $command for ($command, @$aliases);
290              
291 29         47 my $prog = $command;
292              
293             # $prog .= ' (' . join(', ', @$aliases) . ')' if @$aliases;
294              
295 29         75 $self->{-subparsers}{-aliases}{$command} = $aliases;
296 29         819 return $self->{-subparsers}{-parsers}{$command} = __PACKAGE__->new(
297             prog => $prog,
298             aliases => $aliases, # subcommand
299             help => $help,
300             parents => $parents,
301             description => $description,
302             error_prefix => $self->error_prefix,
303             print_usage_if_help => $self->print_usage_if_help,
304             );
305             }
306              
307 0     0 0 0 sub get_parser { $_[0]->_get_subcommand_parser(@_) }
308              
309             *add_arg = \&add_argument;
310              
311             *add_args = \&add_arguments;
312              
313             # add_arguments([arg_spec], [arg_spec1], ...)
314             # Add multiple arguments.
315             # Interface method
316             sub add_arguments {
317 22     22 0 48 my $self = shift;
318              
319 22         69 $self->add_argument(@$_) for @_;
320              
321 22         43 return $self;
322             }
323              
324             #
325             sub add_argument {
326 204     204 0 11556 my $self = shift;
327              
328 204 100       439 return unless @_; # mostly harmless
329             #
330             # FIXME: This is for merginng parent parents This is a dirty hack
331             # and should be done properly by merging internal specs
332             # and subcommand merging is missing
333             #
334 203         185 push @{ $self->{-pristine_add_arguments} }, [ @_ ];
  203         742  
335              
336 203         566 my ($name, $flags, $rest) = $self->_parse_for_name_and_flags([ @_ ]);
337              
338 203 100       543 _croak $self->error_prefix . 'Incorrect number of arguments' if scalar(@$rest) % 2;
339              
340 202 100       439 _croak $self->error_prefix . 'Empty option name' unless $name;
341              
342 201         466 my $args = { @$rest };
343              
344 201         194 my @flags = @{ $flags };
  201         355  
345              
346             ################
347             # nargs - positional only
348             ################
349             ################
350             # type
351             ################
352 201   100     594 my $type_name = delete $args->{type} || 'Scalar';
353 201 100       568 my $type = $Type2ConstMap{$type_name} if exists $Type2ConstMap{$type_name};
354 201 100       375 _croak $self->error_prefix . "Unknown type=$type_name" unless defined $type;
355              
356 200         227 my $nargs = delete $args->{nargs};
357              
358 200 100       346 if ( defined $nargs ) {
359 28 100       61 _croak $self->error_prefix . 'Nargs only allowed for positional options' if @flags;
360              
361 27 100 100     201 if ( $type != TYPE_PAIR
      100        
      100        
362             && $type != TYPE_ARRAY
363             && $nargs ne '1'
364             && $nargs ne '?'
365             ) {
366 3         4 $type = TYPE_ARRAY;
367             }
368             }
369              
370 199 100 100     946 if ($type == TYPE_COUNT) {
    100          
371 10 50       41 $args->{action} = '_count' unless defined $args->{action};
372 10 100       35 $args->{default} = 0 unless defined $args->{default};
373             } elsif ($type == TYPE_ARRAY || $type == TYPE_PAIR) {
374 23 50       76 $args->{action} = '_append' unless defined $args->{action};
375             } else {
376             # pass
377             }
378              
379             ################
380             # action
381             ################
382 199   100     570 my $action_name = delete $args->{action} || '_store';
383              
384 199 50       452 my $action = $Action2ClassMap{$action_name}
385             if exists $Action2ClassMap{$action_name};
386              
387 199 50       314 $action = $action_name unless $action;
388              
389             {
390 199         169 local $SIG{__WARN__};
  199         527  
391 199         375 local $SIG{__DIE__};
392              
393 199         10043 eval "require $action";
394              
395 199 50       1059 _croak $self->error_prefix . "Cannot load $action for action=$action_name" if $@;
396             };
397              
398             ################
399             # split
400             ################
401 199         341 my $split = delete $args->{split};
402 199 50 66     453 if (defined $split && !$split && $split =~ /^ +$/) {
      33        
403 0         0 _croak $self->error_prefix . 'Cannot use whitespaces to split';
404             }
405              
406 199 50 100     399 if (defined $split && $type != TYPE_ARRAY && $type != TYPE_PAIR) {
      66        
407 0         0 _croak $self->error_prefix . 'Split only for Array and Pair';
408             }
409              
410             ################
411             # default
412             ################
413 199         186 my $default;
414 199 100       377 if (exists $args->{default}) {
415 20         39 my $val = delete $args->{default};
416              
417 20 100       96 if (ref($val) eq 'ARRAY') {
    100          
418 2         3 $default = $val;
419             } elsif (ref($val) eq 'HASH') {
420 5 100       18 _croak $self->error_prefix . 'HASH default only for type Pair'
421             if $type != TYPE_PAIR;
422 4         4 $default = $val;
423             } else {
424 13         32 $default = [ $val ];
425             }
426              
427 19 100       98 if ($type != TYPE_PAIR) {
428 15 100 100     98 if ($type != TYPE_ARRAY && scalar(@$default) > 1) {
429 1         8 _croak $self->error_prefix . 'Multiple default values for scalar type: $name';
430             }
431             }
432             }
433              
434             ################
435             # choices
436             ################
437 197   100     703 my $choices = delete $args->{choices} || undef;
438 197 50 100     425 if ( $choices
      66        
439             && ref($choices) ne 'CODE'
440             && ref($choices) ne 'ARRAY' )
441             {
442 0         0 _croak $self->error_prefix . "Must provide choices in an arrayref or a coderef";
443             }
444              
445 197   100     601 my $choices_i = delete $args->{choices_i} || undef;
446              
447 197 100 100     389 if ($choices && $choices_i) {
448 1         6 _croak $self->error_prefix . 'Not allow to specify choices and choices_i';
449             }
450              
451 196 100 100     365 if ( $choices_i
452             && ref($choices_i) ne 'ARRAY' )
453             {
454 1         5 _croak $self->error_prefix . "Must provide choices_i in an arrayref";
455             }
456              
457             ################
458             # required
459             ################
460 195   100     566 my $required = delete $args->{required} || '';
461              
462 195 100 100     576 if ($type == TYPE_BOOL || $type == TYPE_COUNT) {
463 117         139 $required = ''; # TYPE_BOOL and TYPE_COUNT will already have default values
464             }
465              
466             ################
467             # help
468             ################
469 195   100     490 my $help = delete $args->{help} || '';
470              
471             ################
472             # metavar
473             ################
474 195   33     657 my $metavar = delete $args->{metavar} || uc($name);
475              
476 195 100 100     552 $metavar = ''
477             if $type == TYPE_BOOL
478             || $action_name eq '_count';
479              
480             ################
481             # dest
482             ################
483 195   66     482 my $dest = delete $args->{dest} || $name;
484 195         347 $dest =~ s/-/_/g; # option-name becomes option_name
485              
486 195 100       348 if (@flags) {
487 153         144 while (my ($d, $s) = each %{$self->{-option_specs}}) {
  293         1041  
488 141 100       270 if ($dest ne $d) {
489 125         180 for my $f (@flags) {
490 312         844 _croak $self->error_prefix . "Flag $f already used for a different option ($d)"
491 177 100       138 if grep { $f eq $_ } @{$s->{flags}};
  177         270  
492             }
493             }
494             }
495              
496 152 50       450 if (exists $self->{-position_specs}{$dest}) {
497 0         0 _croak $self->error_prefix . "Option dest=$dest already used by a positional argument";
498             }
499             } else {
500 42 100       154 if (exists $self->{-option_specs}{$dest}) {
501 1         13 _croak $self->error_prefix . "Option dest=$dest already used by an optional argument";
502             }
503             }
504              
505             # never modify existing ones so that the parent's structure will
506             # not be modified
507 193   100     2302 my $spec = {
508             name => $name,
509             flags => \@flags,
510             action => $action,
511             nargs => $nargs,
512             split => $split,
513             required => $required || '',
514             type => $type,
515             default => $default,
516             choices => $choices,
517             choices_i => $choices_i,
518             dest => $dest,
519             metavar => $metavar,
520             help => $help,
521             position => $self->{-option_position}++, # sort order
522             groups => [ '' ],
523             };
524              
525 193         192 my $specs;
526 193 100       288 if (@flags) {
527 152         238 $specs = $self->{-option_specs};
528             } else {
529 41         75 $specs = $self->{-position_specs};
530             }
531              
532             # reset
533 193 100       419 if (delete $args->{reset}) {
534 81 100       1399 $self->namespace->set_attr($spec->{dest}, undef) if $self->namespace;
535 81         10065 delete $specs->{$spec->{dest}};
536             }
537              
538 193 50       477 _croak $self->error_prefix . sprintf(
539             'Unknown spec: %s',
540             join(',', keys %$args)
541             ) if keys %$args;
542              
543             # type check
544 193 100       401 if (exists $specs->{$spec->{dest}}) {
545 3         45 _croak $self->error_prefix . sprintf(
546             'Redefine option %s without reset',
547             $spec->{dest},
548             );
549             }
550              
551             # override
552 190         307 $specs->{$spec->{dest}} = $spec;
553              
554             # specs changed, need to force to resort specs by groups
555 190 50       394 delete $self->{-groups} if $self->{-groups};
556              
557             # Return $self for chaining, $self->add_argument()->add_argument()
558             # or use add_arguments
559 190         910 return $self;
560             }
561              
562             sub _parse_for_name_and_flags {
563 203     203   200 my $self = shift;
564 203         176 my $args = shift;
565              
566 203         164 my ($name, @flags);
567             FLAG:
568 203         430 while (my $flag = shift @$args) {
569 463 100       820 if (substr($flag, 0, 1) eq '-') {
570 274         604 push @flags, $flag;
571             } else {
572 189         266 unshift @$args, $flag;
573 189         281 last FLAG;
574             }
575             }
576              
577             # It's a positional argument spec if there are no flags
578 203 100       383 $name = @flags ? $flags[0] : shift(@$args);
579 203         647 $name =~ s/^-+//g;
580              
581 203         503 return ( $name, \@flags, $args );
582             }
583              
584             #
585             # parse_args([@_])
586             #
587             # Parse @ARGV if called without passing arguments. It returns an
588             # instance of ArgParse::Namespace upon success
589             #
590             # Interface
591              
592             sub parse_args {
593 82     82 0 6051 my $self = shift;
594              
595 82 100       403 my @argv = scalar(@_) ? @_ : @ARGV;
596              
597 82         372 $self->{-saved_argv} = \@ARGV;
598 82         140 @ARGV = ();
599              
600 123         313 my @option_specs = sort {
601 82         486 $a->{position} <=> $b->{position}
602 82         113 } values %{$self->{-option_specs}};
603              
604 27         52 my @position_specs = sort {
605 82         242 $a->{position} <=> $b->{position}
606 82         94 } values %{$self->{-position_specs}};
607              
608 82         220 $self->{-argv} = \@argv;
609             # We still want to continue even if @argv is empty to allow:
610             # - namespace initialization
611             # - default values asssigned
612             # - post checks applied, e.g. required check
613              
614 82 100       2268 $self->namespace(Getopt::ArgParse::Namespace->new) unless $self->namespace;
615              
616 82         493 my $parsed_subcmd;
617 82         1364 $self->namespace->set_attr(current_command => undef);
618              
619             # If the first argument is a subcommand, it will parse for the
620             # subcommand
621 82 100 100     433 if (exists $self->{-subparsers} && scalar(@argv) && defined($argv[0]) && substr($argv[0], 0, 1) ne '-') {
      33        
      66        
622             # Subcommand must appear as the first argument
623             # or it will parse as the top command
624 11         23 my $cmd = shift @argv;
625 11         32 my $subparser = $self->_get_subcommand_parser($cmd);
626 11 100       59 _croak $self->error_prefix
627             . sprintf("%s is not a %s command. See help", $cmd, $self->prog)
628             unless $subparser;
629              
630 10         35 $parsed_subcmd = $self->_parse_subcommand($self->_command => $subparser);
631              
632 10         164 $self->namespace->set_attr(current_command => $self->_command);
633             }
634              
635 81 100       148 if (!$parsed_subcmd) {
636 71 50       271 $self->_parse_optional_args(\@option_specs) if @option_specs;
637 64 100       190 $self->_parse_positional_args(\@position_specs) if @position_specs;
638              
639 56 100 100     1058 if ($self->print_usage_if_help() && $self->namespace->get_attr('help')) {
640 1         3 $self->print_usage();
641 1         99 exit(0);
642             }
643             } else {
644 10 100 100     78 if ($self->print_usage_if_help() && $self->_command() eq 'help') {
645 2 100       39 if ($self->namespace->get_attr('help_command')) {
646 1         4 $self->print_command_usage();
647 1         86 exit(0);
648             } else {
649 1         9 $self->print_usage();
650 1         110 exit(0);
651             }
652             }
653             }
654              
655             # Return value
656 63         994 return $self->namespace;
657             }
658              
659             sub _get_subcommand_parser {
660 13     13   16 my $self = shift;
661 13         20 my $alias = shift;
662              
663 13 50       42 return unless $alias;
664              
665 13 100       138 my $command = $self->{-subparsers}{-alias_map}{$alias}
666             if exists $self->{-subparsers}{-alias_map}{$alias};
667              
668 13 100       125 return unless $command;
669              
670 12         77 $self->_command($command);
671             # The subcommand parser must exist if the alias is mapped
672 12         40 return $self->{-subparsers}{-parsers}{$command};
673             }
674              
675             sub _parse_subcommand {
676 10     10   12 my $self = shift;
677 10         16 my ($cmd, $subparser) = @_;
678              
679 10         241 $subparser->namespace($self->namespace);
680 10         74 $subparser->parse_args(@{$self->{-argv}});
  10         79  
681              
682 10         60 $self->{-argv} = $subparser->{-argv};
683              
684 10         18 return 1;
685             }
686              
687             #
688             # After each call of parse_args(), call this to retrieve any
689             # unconsumed arguments
690             # Interface call
691             #
692             sub argv {
693 1 50   1 0 2 @{ $_[0]->{-argv} || [] };
  1         8  
694             }
695              
696             sub _parse_optional_args {
697 71     71   112 my $self = shift;
698 71         62 my $specs = shift;
699 71         109 my $options = {};
700 71         119 my $dest2spec = {};
701              
702 71         139 for my $spec ( @$specs ) {
703 158         130 my @values;
704 158         310 $dest2spec->{$spec->{dest}} = $self->_get_option_spec($spec);
705 158 100 100     1142 if ( $spec->{type} == TYPE_ARRAY
      100        
      100        
706             || $spec->{type} == TYPE_COUNT
707             || $spec->{type} == TYPE_PAIR
708             || $spec->{type} == TYPE_SCALAR
709             ) {
710 66         55 my @values;
711 66         175 $options->{ $dest2spec->{$spec->{dest}} } = \@values;
712             } else {
713 92         80 my $value;
714 92         254 $options->{ $dest2spec->{$spec->{dest}} } = \$value;
715             }
716             }
717              
718 71         127 Getopt::Long::Configure( @{ $self->parser_configs });
  71         447  
719              
720 71         768 my (@warns, $result);
721              
722 71         82 eval {
723 71     2   478 local $SIG{__WARN__} = sub { push @warns, @_ };
  2         363  
724 71         168 local $SIG{__DIE__};
725              
726 71         362 $result = GetOptionsFromArray( $self->{-argv}, %$options );
727              
728 71         19051 1;
729             };
730              
731             # die on errors
732 71 50       177 _croak $self->error_prefix, $@ if $@;
733              
734 71 100       174 _croak $self->error_prefix, @warns if @warns;
735              
736 69 50       152 _croak $self->error_prefix, 'Failed to parse for options' if !$result;
737              
738 69         166 Getopt::Long::Configure('default');
739              
740 69         1659 $self->_post_parse_processing($specs, $options, $dest2spec);
741              
742 66         202 $self->_apply_action($specs, $options, $dest2spec);
743              
744 65         160 $self->_post_apply_processing($specs, $options, $dest2spec);
745             }
746              
747             sub _parse_positional_args {
748 32     32   41 my $self = shift;
749 32         33 my $specs = shift;
750              
751             # short-circuit it if it's for help
752 32 100       576 return if $self->namespace->get_attr('help');
753              
754 31         46 my $options = {};
755 31         36 my $dest2spec = {};
756              
757 31         50 for my $spec (@$specs) {
758 53         93 $dest2spec->{$spec->{dest}} = $spec->{dest};
759 53         56 my @values = ();
760             # Always assigne values to an option
761 53         108 $options->{$spec->{dest}} = \@values;
762             }
763              
764             POSITION_SPEC:
765 31         43 for my $spec (@$specs) {
766 53         73 my $values = $options->{$spec->{dest}};
767              
768 53 50       97 if ($spec->{type} == TYPE_BOOL) {
769 0         0 _croak $self->error_prefix . 'Bool not allowed for positional arguments';
770             }
771              
772 53         64 my $number = 1;
773 53 100       104 my $nargs = defined $spec->{nargs} ? $spec->{nargs} : 1;
774 53 100       106 if (defined $spec->{nargs}) {
775 32 100       169 if ($nargs eq '?') {
    100          
    100          
    100          
776 5         5 $number = 1;
777             } elsif ($nargs eq '+') {
778 3 100       4 _croak $self->error_prefix . "Too few arguments: narg='+'" unless @{$self->{-argv}};
  3         14  
779 2         3 $number = scalar @{$self->{-argv}};
  2         4  
780             } elsif ($nargs eq '*') { # remainder
781 3         4 $number = scalar @{$self->{-argv}};
  3         6  
782             } elsif ($nargs !~ /^\d+$/) {
783 1         6 _croak $self->error_prefix . 'Invalid nargs:' . $nargs;
784             } else {
785 20         27 $number = $nargs;
786             }
787             }
788              
789 51 100       40 push @$values, splice(@{$self->{-argv}}, 0, $number) if @{$self->{-argv}};
  37         87  
  51         182  
790              
791             # If no values, let it pass for required checking
792             # If there are values, make sure there is the right number of
793             # values
794 51 100 100     211 if (scalar(@$values) && scalar(@$values) != $number) {
795 3         25 _croak($self->error_prefix . sprintf(
796             'Too few arguments for %s: expected:%d,actual:%d',
797             $spec->{dest}, $number, scalar(@$values),
798             )
799             );
800             }
801             }
802              
803 26         59 $self->_post_parse_processing($specs, $options, $dest2spec);
804              
805 26         55 $self->_apply_action($specs, $options, $dest2spec);
806              
807 26         71 $self->_post_apply_processing($specs, $options, $dest2spec);
808             }
809              
810             #
811             sub _post_parse_processing {
812 95     95   110 my $self = shift;
813 95         126 my ($option_specs, $options, $dest2spec) = @_;
814              
815             #
816 95         162 for my $spec ( @$option_specs ) {
817 198         320 my $values = $options->{ $dest2spec->{$spec->{dest}} };
818              
819 198 50       291 if (defined($values)) {
820 198 100       378 if (ref $values eq 'SCALAR') {
821 90 100       143 if (defined($$values)) {
822 11         23 $values = [ $$values ];
823             } else {
824 79         130 $values = [];
825             }
826             }
827             } else {
828 0         0 $values = [];
829             }
830              
831 198         280 $options->{ $dest2spec->{$spec->{dest}} } = $values;
832              
833             # default
834 198 100 100     3750 if (!defined($self->namespace->get_attr($spec->{dest}))
      100        
835             && scalar(@$values) < 1
836             && defined($spec->{default}) )
837             {
838 8 100       43 if ($spec->{type} == TYPE_COUNT) {
    100          
    100          
839 1         17 $self->namespace->set_attr($spec->{dest}, @{$spec->{default}});
  1         7  
840             } elsif ($spec->{type} == TYPE_BOOL) {
841 1         19 $self->namespace->set_attr($spec->{dest}, @{$spec->{default}});
  1         5  
842             } elsif ($spec->{type} == TYPE_PAIR) {
843 2         32 $self->namespace->set_attr($spec->{dest}, $spec->{default});
844             } else {
845 4         4 push @$values, @{$spec->{default}};
  4         8  
846             }
847             }
848              
849             # split and expand
850             # Pair are processed here as well
851 198 100       378 if ( my $delimit = $spec->{split} ) {
852 5         5 my @expanded;
853 5         6 for my $v (@$values) {
854 12 100       34 push @expanded,
855             map {
856 4         21 $spec->{type} == TYPE_PAIR ? { split('=', $_) } : $_
857             } split($delimit, $v);
858             }
859              
860 5         11 $options->{ $dest2spec->{$spec->{dest} } } = \@expanded;
861             } else {
862             # Process PAIR only
863 193 100       346 if ($spec->{type} == TYPE_PAIR) {
864 6         19 $options->{ $dest2spec->{$spec->{dest} } }
865 5         11 = [ map { { split('=', $_) } } @$values ];
866             }
867             }
868              
869             # choices
870 198 100       325 if ( $spec->{choices} ) {
871 5 100       10 if (ref($spec->{choices}) eq 'CODE') {
872 2         3 for my $v (@$values) {
873 2         4 $spec->{choices}->($v);
874             }
875             } else {
876 9 50       26 my %choices =
877 3         4 map { defined($_) ? $_ : '_undef' => 1 }
878 3         7 @{$spec->{choices}};
879              
880             VALUE:
881 3         8 for my $v (@$values) {
882 2 50       3 my $k = defined($v) ? $v : '_undef';
883 2 100       7 next VALUE if exists $choices{$k};
884              
885 1         9 _croak $self->error_prefix . sprintf(
886             "Option %s value %s not in choices: [ %s ]",
887 1         3 $spec->{dest}, $v, join( ', ', @{ $spec->{choices} } ),
888             );
889             }
890             }
891             }
892              
893 196 100       428 if ( $spec->{choices_i} ) {
894 6 50       17 my %choices =
895 3         7 map { defined($_) ? uc($_) : '_undef' => 1 }
896 3         3 @{$spec->{choices_i}};
897              
898             VALUE:
899 3         7 for my $v (@$values) {
900 3 50       6 my $k = defined($v) ? uc($v) : '_undef';
901 3 100       11 next VALUE if exists $choices{$k};
902              
903 1         9 _croak $self->error_prefix . sprintf(
904             "Option %s value %s not in choices: [ %s ] (case insensitive)",
905 1         3 $spec->{dest}, $v, join( ', ', @{ $spec->{choices_i} } ),
906             );
907             }
908             }
909             }
910              
911 92         122 return '';
912             }
913              
914             sub _apply_action {
915 92     92   95 my $self = shift;
916 92         111 my ($specs, $options, $dest2spec) = @_;
917              
918 92         122 for my $spec (@$specs) {
919             # Init
920             # We want to preserve already set attributes if the namespace
921             # is passed in.
922             #
923             # This is because one may want to load configs from a file
924             # into a namespace and then use the same namespace for parsing
925             # configs from command line.
926             #
927 189 100       3046 $self->namespace->set_attr($spec->{dest}, undef)
928             unless defined($self->namespace->get_attr($spec->{dest}));
929              
930 189         2804 my $error = $spec->{action}->apply(
931             $spec,
932             $self->namespace,
933             $options->{ $dest2spec->{$spec->{dest}} },
934             $spec->{name},
935             );
936              
937 189 100       411 _croak $self->error_prefix . $error if $error;
938             }
939              
940 91         113 return '';
941             }
942              
943             sub _post_apply_processing {
944 91     91   97 my $self = shift;
945 91         100 my ($specs, $options, $dest2spec) = @_;
946              
947             #
948             # required is checked after applying actions
949             # This is because required checking is bypassed if help is on
950             #
951 91         145 for my $spec (@$specs) {
952 186         2886 my $v = $self->namespace->get_attr($spec->{dest});
953              
954             # required
955 186 100 100     922 if ( $spec->{required} && not $self->namespace->get_attr('help') ) {
956 15         15 my $has_v;
957 15 100       46 if ($spec->{type} == TYPE_ARRAY) {
    50          
958 6         9 $has_v = @$v;
959             } elsif ($spec->{type} == TYPE_PAIR) {
960 0         0 $has_v = scalar(keys %$v);
961             } else {
962 9         11 $has_v = defined $v;
963             }
964              
965 15 100       84 _croak $self->error_prefix . sprintf("Option %s is required\n", $spec->{dest}) unless $has_v;
966             }
967             }
968             }
969              
970             # interface
971             sub print_usage {
972 3     3 0 9 my $self = shift;
973              
974 3         20 my $usage = $self->format_usage;
975              
976 3         350 print STDERR $_, "\n" for @$usage;
977             }
978              
979             # interface
980             sub print_command_usage {
981 1     1 0 1 my $self = shift;
982 1   33     21 my $command = shift
983             || $self->namespace->get_attr('help_command')
984             || $self->namespace->get_attr('current_command'); # running help command
985              
986 1         14 my $usage = $self->format_command_usage($command);
987 1 50       5 if ($usage) {
988 1         98 print STDERR $_, "\n" for @$usage;
989             } else {
990 0         0 print STDERR
991             $self->error_prefix,
992             sprintf('No help for %s. See help', $self->namespace->get_attr('help_command')),
993             "\n";
994             }
995             }
996              
997             # Interface
998             sub format_usage {
999 5     5 0 14 my $self = shift;
1000              
1001 5 50       53 $self->_sort_specs_by_groups() unless $self->{-groups};
1002              
1003 5         12 my $old_wrap_columns = $Text::Wrap::columns;
1004              
1005 5         9 my @usage;
1006              
1007 5         44 my $aliases = $self->aliases;
1008 5         31 my $prog = $self->prog;
1009 5 100       26 $prog .= ' (' . join(', ', @$aliases) . ')' if @$aliases;
1010 5 100       32 if( $self->help ) {
1011 2         30 push @usage, wrap('', '', $prog. ': ' . $self->help);
1012 2         569 push @usage, '';
1013             }
1014              
1015 5         24 my ($help, $option_string) = $self->_format_group_usage();
1016 5         9 $Text::Wrap::columns = 80;
1017              
1018 5         110 my $header = sprintf(
1019             'usage: %s %s',
1020             $self->prog, $option_string
1021             );
1022              
1023 5         21 push @usage, wrap('', '', $header);
1024              
1025 5 100       1052 if ($self->description) {
1026 2         20 my @lines = split("\n", $self->description);
1027              
1028 2         5 my @paragraphs;
1029              
1030 2         5 my $para = '';
1031 2         4 for my $line (@lines) {
1032 32 100       51 if ($line =~ /^\s*$/) {
1033 2         3 push @paragraphs, $para;
1034 2         4 $para = '';
1035             } else {
1036 30 100       48 $para .= ( $para ? ' ' : '' ) . $line;
1037             }
1038             }
1039              
1040 2         5 push @paragraphs, $para;
1041 2         4 for (@paragraphs) {
1042 4         2315 push @usage, '';
1043 4         13 push @usage, wrap('', '', $_);
1044             }
1045             }
1046              
1047 5         838 push @usage, @$help;
1048              
1049 5 100       28 if (exists $self->{-subparsers}) {
1050 3         19 push @usage, '';
1051 3         27 push @usage, wrap('', '', $self->{-subparsers}{-title});
1052 3 100       387 push @usage, wrap('', '', $self->{-subparsers}{-description}) if $self->{-subparsers}{-description};
1053              
1054 3         150 my $max = 12;
1055              
1056 3         11 for my $command ( keys %{$self->{-subparsers}{-parsers}} ) {
  3         36  
1057 6         10 my $len = length($command);
1058 6 50       21 $max = $len if $len > $max;
1059             }
1060              
1061 3         8 for my $command ( sort keys %{$self->{-subparsers}{-parsers}} ) {
  3         19  
1062 6         20 my $parser = $self->{-subparsers}{-parsers}{$command};
1063 6         25 my $tab_head = ' ' x ( $max + 2 );
1064              
1065 6         43 my @desc = split("\n", wrap('', '', $parser->help));
1066 6   50     992 my $desc = (shift @desc) || '';
1067 6         23 $_ = $tab_head . $_ for @desc;
1068 6         43 push @usage, sprintf(" %-${max}s %s", $command, join("\n", $desc, @desc));
1069             }
1070             }
1071              
1072 5 100       54 push @usage, '', wrap('', '', $self->epilog) if $self->epilog;
1073              
1074 5         130 $Text::Wrap::columns = $old_wrap_columns; # restore to original
1075              
1076 5         33 return \@usage;
1077             }
1078              
1079             sub format_command_usage {
1080 2     2 0 10 my $self = shift;
1081 2         4 my $alias = shift;
1082              
1083 2         9 my $subp = $self->_get_subcommand_parser($alias);
1084 2 50       10 return '' unless $subp;
1085              
1086 2         7 return $subp->format_usage();
1087             }
1088              
1089             # FIXME: Maybe we should remove this grouping thing
1090             sub _sort_specs_by_groups {
1091 5     5   8 my $self = shift;
1092              
1093 5         15 my $specs = $self->{-option_specs};
1094              
1095 5         7 for my $dest ( keys %{ $specs } ) {
  5         40  
1096 16         17 for my $group ( @{ $specs->{$dest}{groups} } ) {
  16         43  
1097 16         14 push @{ $self->{-groups}{$group}{-option} }, $specs->{$dest};
  16         102  
1098             }
1099             }
1100              
1101 5         16 $specs = $self->{-position_specs};
1102              
1103 5         7 for my $dest ( keys %{ $specs } ) {
  5         16  
1104 4         5 for my $group ( @{ $specs->{$dest}{groups} } ) {
  4         13  
1105 4         6 push @{ $self->{-groups}{$group}{-position} }, $specs->{$dest};
  4         24  
1106             }
1107             }
1108             }
1109              
1110             sub _format_group_usage {
1111 5     5   10 my $self = shift;
1112 5         8 my $group = '';
1113             # my $group = shift || '';
1114              
1115 5 50       21 unless ($self->{-groups}) {
1116 0         0 $self->_sort_specs_by_groups();
1117             }
1118              
1119 5         11 my $old_wrap_columns = $Text::Wrap::columns;
1120 5         24 $Text::Wrap::columns = 80;
1121              
1122 5         11 my @usage;
1123              
1124 18         44 my @option_specs = sort {
1125 5 50       43 $a->{position} <=> $b->{position}
1126 5         9 } @{ $self->{-groups}{$group}{-option} || [] };
1127              
1128 16         83 my @flag_items = map {
1129 5         13 ($_->{required} ? '' : '[')
1130 16 100       116 . join('|', @{$_->{flags}})
    100          
1131             . ($_->{required} ? '' : ']')
1132             } @option_specs;
1133              
1134 2         8 my @position_specs = sort {
1135 5 100       69 $a->{position} <=> $b->{position}
1136 5         12 } @{ $self->{-groups}{$group}{-position} || [] };
1137              
1138 4 100       24 my @position_items = map {
    100          
1139 5         9 ($_->{required} ? '' : '[')
1140             . $_->{metavar}
1141             . ($_->{required} ? '' : ']')
1142             } @position_specs;
1143              
1144 5 100       35 my @subcommand_items = ('', '[]') if exists $self->{-subparsers};
1145              
1146 5 50       15 if ($group) {
1147 0   0     0 push @usage, wrap('', '', $group . ': ' . ($self->{-group_description}{$group} || '') );
1148             }
1149              
1150             # named arguments are arguments preceded by a hyphen as optional
1151             # vs. positional are too confusing.
1152 5         35 for my $spec_name ( [ \@position_specs, 'positional' ], [ \@option_specs, 'named' ]) {
1153 10         17 my ($specs, $spec_name) = @$spec_name;
1154 10         30 for my $type_name ( [ PRINT_REQUIRED, 'required'], [ PRINT_OPTIONAL, 'optional'] ) {
1155 20         30 my ($type, $type_name) = @$type_name;
1156 20         45 my $output = $self->_format_usage_by_spec($specs, $type);
1157 20 100       61 if (@$output) {
1158 10         23 push @usage, '';
1159             # Start a section: e.g. required positional arguments:
1160 10         28 push @usage, sprintf('%s %s arguments:', $type_name, $spec_name);
1161 10         36 push @usage, @$output;
1162             }
1163             }
1164             }
1165              
1166 5         12 $Text::Wrap::columns = $old_wrap_columns; # restore to original
1167              
1168 5         43 return ( \@usage, join(' ', @position_items, @flag_items, @subcommand_items) ) ;
1169             }
1170              
1171             sub _format_usage_by_spec {
1172 20     20   161 my $self = shift;
1173 20         26 my $specs = shift;
1174 20         24 my $print_type = shift;
1175              
1176 20 50       40 return unless $specs;
1177              
1178 20         21 my @usage;
1179 20         21 my $max = 10;
1180 20         32 my @item_help;
1181              
1182 20         43 SPEC: for my $spec ( @$specs ) {
1183 40 100 100     294 next SPEC if ($print_type == PRINT_OPTIONAL && $spec->{'required'})
      100        
      66        
1184             || ($print_type == PRINT_REQUIRED && !$spec->{'required'});
1185              
1186 20         38 my $item = $spec->{metavar};
1187              
1188 20 100       18 if (@{$spec->{flags}}) {
  20         58  
1189 16         84 $item = sprintf(
1190             "%s %s",
1191 16         18 join(', ', @{$spec->{flags}}),
1192             $spec->{metavar},
1193             );
1194             }
1195 20         35 my $len = length($item);
1196 20 100       42 $max = $len if $len > $max;
1197              
1198             # generate default string
1199 20         41 my $default = '';
1200 20         31 my $values = [];
1201              
1202 20 100       45 if (defined $spec->{default}) {
1203 3 100       14 if (ref $spec->{default} eq 'HASH') {
    50          
1204 1         2 while (my ($k, $v) = each %{$spec->{default}}) {
  3         10  
1205 2         4 push @$values, "$k=$v";
1206             }
1207             } elsif (ref $spec->{default} eq 'ARRAY') {
1208 2         13 $values = $spec->{default};
1209             } else {
1210 0         0 $values = [ $spec->{default} ];
1211             }
1212             }
1213              
1214 20 100       40 if (@$values) {
1215 3         7 $default = 'Default: ' . join(', ', @$values);
1216             }
1217              
1218             # generate choice string
1219 20         17 my $choices;
1220 20         25 my $case = '';
1221              
1222 20 50 33     84 if ($spec->{choices} && ref $spec->{choices} ne 'CODE') {
    50          
1223 0         0 $choices = $spec->{choices};
1224 0         0 $case = 'case sensitive';
1225             } elsif ($spec->{choices_i}) {
1226 0         0 $choices = $spec->{choices_i};
1227 0         0 $case = 'case insensitive';
1228             } else {
1229 20         21 $choices = undef;
1230             }
1231              
1232 20         25 my $choice_str = '';
1233 20 50       36 if ($choices) {
1234 0         0 $choice_str = 'Choices: [' . join(', ', @$choices) . '], ' . $case . "\n";
1235             }
1236              
1237 20 100 66     212 push @item_help, [
1238             $item,
1239             ($spec->{required} ? ' ' : '?'),
1240             join("\n", ($spec->{help} || 'This is option ' . $spec->{dest}), $choice_str . $default),
1241             ];
1242             }
1243              
1244 20         56 my $format = " %-${max}s %s %s";
1245 20         22 $Text::Wrap::columns = 60;
1246 20         29 for my $ih (@item_help) {
1247 20         35 my $item_len = length($ih->[0]);
1248             # The prefixed whitespace in subsequent lines in the wrapped
1249             # help string
1250 20         61 my $sub_tab = " " x ($max + 4 + 4 + 2);
1251 20         107 my @help = split("\n", wrap('', '', $ih->[2]));
1252              
1253 20   50     3535 my $help = (shift @help) || '' ; # head
1254 20         49 $_ = $sub_tab . $_ for @help; # tail
1255              
1256 20         143 push @usage, sprintf($format, $ih->[0], $ih->[1], join("\n", $help, @help));
1257             }
1258              
1259 20         62 return \@usage;
1260             }
1261              
1262             # translate option spec to the one accepted by
1263             # Getopt::Long::GetOptions
1264             sub _get_option_spec {
1265 158     158   163 my $self = shift;
1266 158         134 my $spec = shift;
1267              
1268 158         128 my @flags = @{ $spec->{flags} };
  158         332  
1269 158         845 $_ =~ s/^-+// for @flags;
1270 158         270 my $name = join('|', @flags);
1271 158         157 my $type = 's';
1272 158         135 my $desttype = '';
1273              
1274 158         154 my $optional_flag = '='; # not optional
1275              
1276 158 100       631 if ($spec->{type} == TYPE_SCALAR) {
    100          
    100          
    50          
    100          
    50          
1277 48         48 $desttype = '@';
1278             } elsif ($spec->{type} == TYPE_ARRAY) {
1279 10         12 $desttype = '@';
1280             } elsif ($spec->{type} == TYPE_PAIR) {
1281 4         6 $desttype = '@';
1282             } elsif ($spec->{type} == TYPE_UNDEF) {
1283 0         0 $optional_flag = ':';
1284             } elsif ($spec->{type} == TYPE_BOOL) {
1285 92         111 $type = '';
1286 92         97 $optional_flag = '';
1287 92         92 $desttype = '';
1288             } elsif ($spec->{type} == TYPE_COUNT) {
1289             # pass
1290 4         4 $type = '';
1291 4         3 $optional_flag = '';
1292 4         3 $desttype = '+';
1293             } else {
1294             # pass
1295             # should never be here
1296 0   0     0 _croak $self->error_prefix . 'Unknown type:' . ($spec->{type} || 'undef');
1297             }
1298              
1299 158         137 my $repeat = '';
1300              
1301 158         226 my $opt = join('', $name, $optional_flag, $type, $repeat, $desttype);
1302              
1303 158         433 return $opt;
1304             }
1305              
1306             1;
1307              
1308             __END__