File Coverage

blib/lib/Getopt/Lucid.pm
Criterion Covered Total %
statement 480 483 99.3
branch 301 322 93.4
condition 42 50 84.0
subroutine 53 53 100.0
pod 16 16 100.0
total 892 924 96.5


line stmt bran cond sub pod time code
1 12     12   940237 use 5.008001;
  12         120  
2 12     12   53 use strict;
  12         18  
  12         207  
3 12     12   49 use warnings;
  12         18  
  12         899  
4             package Getopt::Lucid;
5             # ABSTRACT: Clear, readable syntax for command line processing
6              
7             our $VERSION = '1.10';
8              
9             our @EXPORT_OK = qw(Switch Counter Param List Keypair);
10             our %EXPORT_TAGS = ( all => [ @EXPORT_OK ] );
11             our @ISA = qw( Exporter );
12              
13 12     12   71 use Carp;
  12         25  
  12         660  
14 12     12   78 use Exporter ();
  12         25  
  12         209  
15 12     12   73 use File::Basename ();
  12         39  
  12         208  
16 12     12   59 use List::Util ();
  12         21  
  12         306  
17 12     12   3609 use Getopt::Lucid::Exception;
  12         24  
  12         607  
18 12     12   6502 use Storable 2.16 qw(dclone);
  12         32912  
  12         19061  
19              
20             # Definitions
21             my $VALID_STARTCHAR = "a-zA-Z0-9";
22             my $VALID_CHAR = "a-zA-Z0-9_-";
23             my $VALID_LONG = qr/--[$VALID_STARTCHAR][$VALID_CHAR]*/;
24             my $VALID_SHORT = qr/-[$VALID_STARTCHAR]/;
25             my $VALID_BARE = qr/[$VALID_STARTCHAR][$VALID_CHAR]*/;
26             my $VALID_NAME = qr/$VALID_LONG|$VALID_SHORT|$VALID_BARE/;
27             my $SHORT_BUNDLE = qr/-[$VALID_STARTCHAR]{2,}/;
28             my $NEGATIVE = qr/(?:--)?no-/;
29              
30             my @valid_keys = qw( name type default nocase valid needs canon doc );
31             my @valid_types = qw( switch counter parameter list keypair);
32              
33             sub Switch {
34 49     49 1 9726 return bless { name => shift, type => 'switch' },
35             "Getopt::Lucid::Spec";
36             }
37             sub Counter {
38 24     24 1 4900 return bless { name => shift, type => 'counter' },
39             "Getopt::Lucid::Spec";
40             }
41             sub Param {
42 36     36 1 164 my $self = { name => shift, type => 'parameter' };
43 36 100       72 $self->{valid} = shift if @_;
44 36         201 return bless $self, "Getopt::Lucid::Spec";
45             }
46             sub List {
47 10     10 1 22 my $self = { name => shift, type => 'list' };
48 10 100       25 $self->{valid} = shift if @_;
49 10         53 return bless $self, "Getopt::Lucid::Spec";
50             }
51             sub Keypair {
52 13     13 1 77 my $self = { name => shift, type => 'keypair' };
53 13 100       41 $self->{valid} = [ @_ ] if scalar @_;
54 13         100 return bless $self, "Getopt::Lucid::Spec";
55             }
56              
57             package
58             Getopt::Lucid::Spec;
59             $Getopt::Lucid::Spec::VERSION = $Getopt::Lucid::VERSION;
60              
61             # alternate way to specify validation
62             sub valid {
63 2     2   4 my $self = shift;
64             Getopt::Lucid::throw_spec("valid() is not supported for '$self->{type}' options")
65 2 50       3 unless grep { $self->{type} eq $_ } qw/parameter list keypair/;
  6         14  
66 2 50       5 $self->{valid} = $self->{type} eq 'keypair' ? [ @_ ] : shift;
67 2         7 return $self;
68             }
69              
70             sub default {
71 37     37   45 my $self = shift;
72 37         58 my $type = $self->{type};
73 37 100       79 if ($self->{type} eq 'keypair') {
    100          
74 6 100       22 if (ref($_[0]) eq 'HASH') {
    100          
75 2         5 $self->{default} = shift;
76             }
77             elsif ( @_ % 2 == 0 ) {
78 3         9 $self->{default} = { @_ };
79             }
80             else {
81 1         2 $self->{default} = []; # will cause an exception later
82             }
83             }
84             elsif ( $self->{type} eq 'list' ) {
85 5         13 $self->{default} = [ @_ ];
86             }
87             else {
88 26         34 $self->{default} = shift;
89             }
90 37         184 return $self
91             };
92              
93 2     2   4 sub anycase { my $self = shift; $self->{nocase}=1; return $self };
  2         7  
  2         1730  
94              
95 5     5   7 sub needs { my $self = shift; $self->{needs}=[@_]; return $self };
  5         14  
  5         14  
96              
97 3     3   4 sub doc { my $self = shift; $self->{doc}=shift; return $self };
  3         9  
  3         7  
98              
99 541     541   591 sub _clone { my $self = shift; bless { %$self }, ref $self }
  541         1797  
100              
101             package Getopt::Lucid;
102              
103             #--------------------------------------------------------------------------#
104             # new()
105             #--------------------------------------------------------------------------#
106              
107             my @params = qw/strict target/;
108              
109             sub new {
110 190     190 1 41209 my ($class, $spec, $target) = @_;
111 190 100       531 my $args = ref($_[-1]) eq 'HASH' ? pop(@_) : {};
112 190 100       492 $args->{target} = ref($target) eq 'ARRAY' ? $target : \@ARGV;
113 190         249 my $self = {};
114 190         582 $self->{$_} = $args->{$_} for @params;
115 190         272 $self->{raw_spec} = $spec;
116 190 50       348 bless ($self, ref($class) ? ref($class) : $class);
117             throw_usage("Getopt::Lucid->new() requires an option specification array reference")
118 190 100       463 unless ref($self->{raw_spec}) eq 'ARRAY';
119 189         407 _parse_spec($self);
120 180         376 _set_defaults($self);
121 178         402 $self->{options} = {};
122 178         265 $self->{parsed} = [];
123 178         228 $self->{seen}{$_} = 0 for keys %{$self->{spec}};
  178         608  
124 178         613 return $self;
125             }
126              
127             #--------------------------------------------------------------------------#
128             # append_defaults()
129             #--------------------------------------------------------------------------#
130              
131             sub append_defaults {
132 8     8 1 3741 my $self = shift;
133             my %append =
134 8 100       32 ref $_[0] eq 'HASH' ? %{+shift} :
  4 100       19  
135             (@_ % 2 == 0) ? @_ :
136             throw_usage("Argument to append_defaults() must be a hash or hash reference");
137 7         11 for my $name ( keys %{$self->{spec}} ) {
  7         22  
138 42         59 my $spec = $self->{spec}{$name};
139 42         52 my $strip = $self->{strip}{$name};
140 42 100       63 next unless exists $append{$strip};
141 29         44 for ( $spec->{type} ) {
142 29 100       87 /switch|parameter/ && do {
143 15         26 $self->{default}{$strip} = $append{$strip};
144 15         19 last;
145             };
146 14 100       28 /counter/ && do {
147 4         8 $self->{default}{$strip} += $append{$strip};
148 4         5 last;
149             };
150 10 100       99 /list/ && do {
151             throw_usage("Option '$strip' in append_defaults() must be scalar or array reference")
152 5 100 100     25 if ref($append{$strip}) && ref($append{$strip}) ne 'ARRAY';
153             $append{$strip} = ref($append{$strip}) eq 'ARRAY'
154             ? dclone( $append{$strip} )
155 4 100       43 : [ $append{$strip} ] ;
156 4         8 push @{$self->{default}{$strip}}, @{$append{$strip}};
  4         9  
  4         8  
157 4         7 last;
158             };
159 5 50       13 /keypair/ && do {
160             throw_usage("Option '$strip' in append_defaults() must be scalar or hash reference")
161 5 100 66     31 if ref($append{$strip}) && ref($append{$strip}) ne 'HASH';
162             $self->{default}{$strip} = {
163 4         8 %{$self->{default}{$strip}},
164 4         6 %{$append{$strip}},
  4         13  
165             };
166 4         9 last;
167             };
168             }
169             throw_spec("Default '$spec->{canon}' = '$self->{default}{$strip}' fails to validate")
170 27 100       54 unless _validate_value($self, $self->{default}{$strip}, $spec->{valid} );
171             }
172 4         14 _recalculate_options($self);
173 4         10 return $self->options;
174             }
175              
176             #--------------------------------------------------------------------------#
177             # defaults()
178             #--------------------------------------------------------------------------#
179              
180             sub defaults {
181 7     7 1 11 my ($self) = @_;
182 7         7 return %{dclone($self->{default})};
  7         200  
183             }
184              
185              
186             #--------------------------------------------------------------------------#
187             # getopt()
188             #--------------------------------------------------------------------------#
189              
190             sub getopt {
191 141     141 1 3342 my ($self,$spec,$target) = @_;
192 141 100       335 if ( $self eq 'Getopt::Lucid' ) {
193 2 100       8 throw_usage("Getopt::Lucid->getopt() requires an option specification array reference")
194             unless ref($spec) eq 'ARRAY';
195 1         2 $self = new(@_)
196             }
197 140         192 my (@passthrough);
198 140         208 while (@{$self->{target}}) {
  375         682  
199 287         305 my $raw = shift @{$self->{target}};
  287         420  
200 287 100       602 last if $raw =~ /^--$/;
201 272         393 my ($orig, $val) = _split_equals($self, $raw);
202 272 100       428 next if _unbundle($self, $orig, $val);
203 248 100       745 my $neg = $orig =~ s/^$NEGATIVE(.*)$/$1/ ? 1 : 0;
204 248         392 my $arg = _find_arg($self, $orig);
205 248 100       395 if ( $arg ) {
206             $neg ?
207             $self->{seen}{$arg} = 0 :
208 232 100       369 $self->{seen}{$arg}++;
209 232         363 for ($self->{spec}{$arg}{type}) {
210 232 50       718 /switch/ ? _switch ($self, $arg, $val, $neg) :
    100          
    100          
    100          
    100          
211             /counter/ ? _counter ($self, $arg, $val, $neg) :
212             /parameter/ ? _parameter($self, $arg, $val, $neg) :
213             /list/ ? _list ($self, $arg, $val, $neg) :
214             /keypair/ ? _keypair ($self, $arg, $val, $neg) :
215             throw_usage("can't handle type '$_'");
216             }
217             } else {
218 16 100       67 throw_argv("Invalid argument: $orig")
219             if $orig =~ /^-./; # invalid if looks like it could be an arg;
220 5         11 push @passthrough, $orig;
221             }
222             }
223 103         222 _recalculate_options($self);
224 103         133 @{$self->{target}} = (@passthrough, @{$self->{target}});
  103         146  
  103         153  
225 103         275 return $self;
226             }
227              
228 12     12   52077 BEGIN { *getopts = \&getopt }; # handy alias
229              
230             #--------------------------------------------------------------------------#
231             # validate
232             #--------------------------------------------------------------------------#
233              
234             sub validate {
235 83     83 1 131 my ($self, $arg) = @_;
236 83 50 33     282 throw_usage("Getopt::Lucid->validate() takes a hashref argument")
237             if $arg && ref($arg) ne 'HASH';
238              
239 83 100 66     235 if ( $arg && exists $arg->{requires} ) {
240 7         13 my $requires = $arg->{requires};
241 7 50 33     29 throw_usage("'validate' argument 'requires' must be an array reference")
242             if $requires && ref($requires) ne 'ARRAY';
243 7         15 for my $p ( @$requires ) {
244             throw_spec("Requiring an unspecified option ('$p') in validate()")
245 7 50       15 unless exists $self->{spec}{$p};
246             throw_argv( "Required option '$self->{spec}{$p}{canon}' not found")
247 7 100       26 if ( !$self->{seen}{$p} );
248             }
249             }
250              
251 81         153 _check_prereqs($self);
252              
253 76         152 return $self;
254             }
255              
256             #--------------------------------------------------------------------------#
257             # merge_defaults()
258             #--------------------------------------------------------------------------#
259              
260             sub merge_defaults {
261 8     8 1 2865 my $self = shift;
262             my %merge =
263 8 100       33 ref $_[0] eq 'HASH' ? %{+shift} :
  4 100       15  
264             (@_ % 2 == 0) ? @_ :
265             throw_usage("Argument to merge_defaults() must be a hash or hash reference");
266 7         11 for my $name ( keys %{$self->{spec}} ) {
  7         21  
267 44         62 my $spec = $self->{spec}{$name};
268 44         53 my $strip = $self->{strip}{$name};
269 44 100       71 next unless exists $merge{$strip};
270 29         45 for ( $self->{spec}{$name}{type} ) {
271 29 100       99 /switch|counter|parameter/ && do {
272 19         34 $self->{default}{$strip} = $merge{$strip};
273 19         20 last;
274             };
275 10 100       24 /list/ && do {
276             throw_usage("Option '$strip' in merge_defaults() must be scalar or array reference")
277 5 100 100     25 if ref($merge{$strip}) && ref($merge{$strip}) ne 'ARRAY';
278             $merge{$strip} = ref($merge{$strip}) eq 'ARRAY'
279             ? dclone( $merge{$strip} )
280 4 100       32 : [ $merge{$strip} ] ;
281 4         8 $self->{default}{$strip} = $merge{$strip};
282 4         7 last;
283             };
284 5 50       12 /keypair/ && do {
285             throw_usage("Option '$strip' in merge_defaults() must be scalar or hash reference")
286 5 100 66     29 if ref($merge{$strip}) && ref($merge{$strip}) ne 'HASH';
287 4         60 $self->{default}{$strip} = dclone($merge{$strip});
288 4         9 last;
289             };
290             }
291             throw_spec("Default '$spec->{canon}' = '$self->{default}{$strip}' fails to validate")
292 27 100       57 unless _validate_value($self, $self->{default}{$strip}, $spec->{valid} );
293             }
294 4         14 _recalculate_options($self);
295 4         8 return $self->options;
296             }
297              
298             #--------------------------------------------------------------------------#
299             # names()
300             #--------------------------------------------------------------------------#
301              
302             sub names {
303 1     1 1 2 my ($self) = @_;
304 1         2 return values %{$self->{strip}};
  1         5  
305             }
306              
307              
308             #--------------------------------------------------------------------------#
309             # options()
310             #--------------------------------------------------------------------------#
311              
312             sub options {
313 122     122 1 239 my ($self) = @_;
314 122         126 return %{dclone($self->{options})};
  122         3203  
315             }
316              
317             #--------------------------------------------------------------------------#
318             # replace_defaults()
319             #--------------------------------------------------------------------------#
320              
321             sub replace_defaults {
322 8     8 1 4344 my $self = shift;
323             my %replace =
324 8 100       33 ref $_[0] eq 'HASH' ? %{+shift} :
  4 100       15  
325             (@_ % 2 == 0) ? @_ :
326             throw_usage("Argument to replace_defaults() must be a hash or hash reference");
327 7         12 for my $name ( keys %{$self->{spec}} ) {
  7         23  
328 45         65 my $spec = $self->{spec}{$name};
329 45         55 my $strip = $self->{strip}{$name};
330 45         69 for ( $self->{spec}{$name}{type} ) {
331 45 100       125 /switch|counter/ && do {
332 15   100     44 $self->{default}{$strip} = $replace{$strip} || 0;
333 15         17 last;
334             };
335 30 100       58 /parameter/ && do {
336 18         33 $self->{default}{$strip} = $replace{$strip};
337 18         23 last;
338             };
339 12 100       22 /list/ && do {
340             throw_usage("Option '$strip' in replace_defaults() must be scalar or array reference")
341 5 100 100     26 if ref($replace{$strip}) && ref($replace{$strip}) ne 'ARRAY';
342 4 50       7 if ( exists $replace{$strip} ) {
343             $replace{$strip} = ref($replace{$strip}) eq 'ARRAY' ?
344 4 100       14 $replace{$strip} : [ $replace{$strip} ];
345             } else {
346 0         0 $replace{$strip} = [];
347             }
348 4         40 $self->{default}{$strip} = dclone($replace{$strip});
349 4         7 last;
350             };
351 7 50       17 /keypair/ && do {
352             throw_usage("Option '$strip' in replace_defaults() must be scalar or hash reference")
353 7 100 100     34 if ref($replace{$strip}) && ref($replace{$strip}) ne 'HASH';
354 6 100       15 $replace{$strip} = {} unless exists $replace{$strip};
355 6         113 $self->{default}{$strip} = dclone($replace{$strip});
356 6         14 last;
357             };
358             }
359             throw_spec("Default '$spec->{canon}' = '$self->{default}{$strip}' fails to validate")
360 43 100       93 unless _validate_value($self, $self->{default}{$strip}, $spec->{valid} );
361             }
362 4         13 _recalculate_options($self);
363 4         9 return $self->options;
364             }
365              
366             #--------------------------------------------------------------------------#
367             # reset_defaults()
368             #--------------------------------------------------------------------------#
369              
370             sub reset_defaults {
371 6     6 1 10 my ($self) = @_;
372 6         12 _set_defaults($self);
373 6         14 _recalculate_options($self);
374 6         15 return $self->options;
375             }
376              
377             #--------------------------------------------------------------------------#
378             # usage()
379             #--------------------------------------------------------------------------#
380              
381             sub usage {
382 1     1 1 3 my ($self) = @_;
383 1         1 my @short_opts;
384             my @doc;
385 1         2 for my $opt ( sort { $a->{strip} cmp $b->{strip} } values %{$self->{spec}} ) {
  13         18  
  1         5  
386 7         7 my $names = [ @{ $opt->{names} } ];
  7         15  
387             push @doc, [
388             _build_usage_left_column( $names, \@short_opts ),
389 7         13 _build_usage_right_column( $opt->{doc}, $opt->{default}, $opt->{type} ),
390             ];
391             }
392              
393 1         2 my $max_width = 3 + List::Util::max( map { length } @doc );
  7         12  
394              
395 1         22 my $prog = File::Basename::basename($0);
396              
397 1         3 local $" = '';
398             my $usage = "Usage: $prog [-@short_opts] [long options] [arguments]\n"
399 1         4 . join( "", map { sprintf( "\t%-${max_width}s %s\n", @$_ ) } @doc );
  7         23  
400             }
401              
402             sub _build_usage_left_column {
403 7     7   10 my ($names, $all_short_opts) = @_;
404             my @sorted_names =
405 7         10 sort { length $a <=> length $b } map { my $s = $_; $s =~ s/^-*//; $s } @$names;
  1         3  
  8         10  
  8         20  
  8         17  
406              
407 7         12 my @short_opts = grep { length == 1 } @sorted_names;
  8         14  
408 7         9 my @long_opts = grep { length > 1 } @sorted_names;
  8         13  
409              
410 7         10 push @$all_short_opts, @short_opts;
411              
412             my $group = sub {
413 8     8   8 my $list = shift;
414 8 50       51 '-' . ( @$list == 1 ? $list->[0] : '[' . join( '|', @$list ) . ']' );
415 7         16 };
416             my $prepare = sub {
417 14     14   15 my $list = shift;
418 14 100       31 return ( length $list->[0] > 1 ? '-' : '' ) . $group->($list) if @$list;
    100          
419 6         10 return;
420 7         14 };
421              
422 7         13 return join ', ' => map { $prepare->($_) } \@short_opts, \@long_opts;
  14         17  
423             }
424              
425             sub _build_usage_right_column {
426 7     7   16 my ( $doc, $default, $type ) = @_;
427 7 100       14 my $str = defined $doc ? $doc : '';
428 7 100       17 return $str unless defined $default;
429 4 100       7 $str .= " " if length $str;
430 4         7 $str .= "(default: ";
431 4 100       8 if ($type eq 'list') {
    100          
432 1         3 $str .= join( ", ", @$default );
433             }
434             elsif ( $type eq 'keypair' ) {
435 1         3 $str .= join( ", ", map { "$_=$default->{$_}" } sort keys %$default );
  2         6  
436             }
437             else {
438 2         3 $str .= $default
439             }
440 4         6 $str .= ')';
441 4         10 return $str;
442             }
443              
444             #--------------------------------------------------------------------------#
445             # _check_prereqs()
446             #--------------------------------------------------------------------------#
447              
448             sub _check_prereqs {
449 81     81   104 my ($self) = @_;
450 81         82 for my $key ( keys %{$self->{seen}} ) {
  81         202  
451 205 100       326 next unless $self->{seen}{$key};
452 103 100       197 next unless exists $self->{spec}{$key}{needs};
453 10         12 for (@{$self->{spec}{$key}{needs}}) {
  10         22  
454             throw_argv("Option '$self->{spec}{$key}{canon}' ".
455             "requires option '$self->{spec}{$_}{canon}'")
456 12 100       42 unless $self->{seen}{$_};
457             }
458             }
459             }
460              
461             #--------------------------------------------------------------------------#
462             # _counter()
463             #--------------------------------------------------------------------------#
464              
465             sub _counter {
466 82     82   136 my ($self, $arg, $val, $neg) = @_;
467 82 100       136 throw_argv("Counter option can't take a value: $self->{spec}{$arg}{canon}=$val")
468             if defined $val;
469 80         81 push @{$self->{parsed}}, [ $arg, 1, $neg ];
  80         242  
470             }
471              
472             #--------------------------------------------------------------------------#
473             # _find_arg()
474             #--------------------------------------------------------------------------#
475              
476             sub _find_arg {
477 344     344   525 my ($self, $arg) = @_;
478              
479 344 100       980 $arg =~ s/^-*// unless $self->{strict};
480 344 100       873 return $self->{alias_hr}{$arg} if exists $self->{alias_hr}{$arg};
481              
482 66         85 for ( keys %{$self->{alias_nocase}} ) {
  66         155  
483 14 100       110 return $self->{alias_nocase}{$_} if $arg =~ /^$_$/i;
484             }
485              
486 62         162 return;
487             }
488              
489             #--------------------------------------------------------------------------#
490             # _keypair()
491             #--------------------------------------------------------------------------#
492              
493             sub _keypair {
494 24     24   49 my ($self, $arg, $val, $neg) = @_;
495 24         32 my ($key, $data);
496 24 100       36 if ($neg) {
497 4         5 $key = $val;
498             }
499             else {
500 20 100       36 my $value = defined $val ? $val : shift @{$self->{target}};
  17         34  
501 20 100 100     79 if (! defined $val && ! defined $value) {
502 1         5 throw_argv("Option '$self->{spec}{$arg}{canon}' requires a value");
503             }
504              
505 19 100       78 throw_argv("Badly formed keypair for '$self->{spec}{$arg}{canon}'")
506             unless $value =~ /[^=]+=.+/;
507 16         61 ($key, $data) = ( $value =~ /^([^=]*)=(.*)$/ ) ;
508             throw_argv("Invalid keypair '$self->{spec}{$arg}{canon}': $key => $data")
509             unless _validate_value($self, { $key => $data },
510 16 100       62 $self->{spec}{$arg}{valid});
511             }
512 16         31 push @{$self->{parsed}}, [ $arg, [ $key, $data ], $neg ];
  16         76  
513             }
514              
515             #--------------------------------------------------------------------------#
516             # _list()
517             #--------------------------------------------------------------------------#
518              
519             sub _list {
520 20     20   53 my ($self, $arg, $val, $neg) = @_;
521 20         23 my $value;
522 20 100       30 if ($neg) {
523 4         4 $value = $val;
524             }
525             else {
526 16 100       30 $value = defined $val ? $val : shift @{$self->{target}};
  13         23  
527 16 100       36 if (! defined $val) {
528 13 100       31 if (! defined $value) {
529 1         4 throw_argv("Option '$self->{spec}{$arg}{canon}' requires a value");
530             }
531 12         82 $value =~ s/^$NEGATIVE(.*)$/$1/;
532             }
533              
534 15 100 100     50 throw_argv("Ambiguous value for $self->{spec}{$arg}{canon} could be option: $value")
535             if ! defined $val and _find_arg($self, $value);
536             throw_argv("Invalid list option $self->{spec}{$arg}{canon} = $value")
537 14 100       48 unless _validate_value($self, $value, $self->{spec}{$arg}{valid});
538             }
539 17         27 push @{$self->{parsed}}, [ $arg, $value, $neg ];
  17         61  
540             }
541              
542             #--------------------------------------------------------------------------#
543             # _parameter()
544             #--------------------------------------------------------------------------#
545              
546             sub _parameter {
547 52     52   99 my ($self, $arg, $val, $neg) = @_;
548 52         55 my $value;
549 52 100       83 if ($neg) {
550 6 100       15 throw_argv("Negated parameter option can't take a value: $self->{spec}{$arg}{canon}=$val")
551             if defined $val;
552             }
553             else {
554 46 100       71 $value = defined $val ? $val : shift @{$self->{target}};
  39         60  
555 46 100       93 if (! defined $val) {
556 39 100       59 if (! defined $value) {
557 2         9 throw_argv("Option '$self->{spec}{$arg}{canon}' requires a value");
558             }
559 37         154 $value =~ s/^$NEGATIVE(.*)$/$1/;
560             }
561 44 100 100     116 throw_argv("Ambiguous value for $self->{spec}{$arg}{canon} could be option: $value")
562             if ! defined $val and _find_arg($self, $value);
563             throw_argv("Invalid parameter $self->{spec}{$arg}{canon} = $value")
564 41 100       110 unless _validate_value($self, $value, $self->{spec}{$arg}{valid});
565             }
566 42         73 push @{$self->{parsed}}, [ $arg, $value, $neg ];
  42         134  
567             }
568              
569             #--------------------------------------------------------------------------#
570             # _parse_spec()
571             #--------------------------------------------------------------------------#
572              
573             sub _parse_spec {
574 189     189   261 my ($self) = @_;
575 189         229 my $spec = $self->{raw_spec};
576 189         268 for my $v ( @$spec ) {
577 541         651 my $type = ref $v;
578 541 50       910 throw_spec(
579             "'$type' is not a valid option type"
580             ) unless $type eq 'Getopt::Lucid::Spec';
581             }
582 189         316 for my $opt ( map { $_->_clone } @$spec ) {
  541         830  
583 541         690 my $name = $opt->{name};
584 541         1087 my @names = split( /\|/, $name );
585 541         1741 $opt->{canon} = $names[0];
586 541         1055 _validate_spec($self,\@names,$opt);
587 533         825 $opt->{names} = \@names;
588 533         1214 ($opt->{strip} = $names[0]) =~ s/^-+//;
589 533 100       1028 @names = map { s/^-*//; $_ } @names unless $self->{strict}; ## no critic
  800         1488  
  800         1545  
590 533         774 for (@names) {
591 848         1386 $self->{alias_hr}{$_} = $names[0];
592 848 100       1378 $self->{alias_nocase}{$_} = $names[0] if $opt->{nocase};
593             }
594 533         1088 $self->{spec}{$names[0]} = $opt;
595 533         1005 $self->{strip}{$names[0]} = $opt->{strip};
596             }
597 181         327 _validate_prereqs($self);
598             }
599              
600             #--------------------------------------------------------------------------#
601             # _recalculate_options()
602             #--------------------------------------------------------------------------#
603              
604             sub _recalculate_options {
605 121     121   177 my ($self) = @_;
606 121         134 my %result;
607 121         131 for my $k ( keys %{$self->{default}} ) {
  121         352  
608 463         584 my $d = $self->{default}{$k};
609 463 100       1056 $result{$k} = ref($d) eq 'ARRAY' ? [ @$d ] :
    100          
610             ref($d) eq 'HASH' ? { %$d } : $d;
611             }
612 121         165 for my $opt ( @{$self->{parsed}} ) {
  121         188  
613 274         408 my ($name, $value, $neg) = @$opt;
614 274         394 for ($self->{spec}{$name}{type}) {
615 274         337 my $strip = $self->{strip}{$name};
616 274 100       469 /switch/ && do {
617 59 100       108 $result{$strip} = $neg ? 0 : $value;
618 59         94 last;
619             };
620 215 100       331 /counter/ && do {
621 102 100       189 $result{$strip} = $neg ? 0 : $result{$strip} + $value;
622 102         423 last;
623             };
624 113 100       187 /parameter/ && do {
625 42 100       83 $result{$strip} = $neg ? "" : $value;
626 42         73 last;
627             };
628 71 100       119 /list/ && do {
629 40 100       55 if ($neg) {
630             $result{$strip} = $value ?
631 4 100       8 [ grep { $_ ne $value } @{$result{$strip}} ] :
  4         9  
  2         4  
632             [];
633             }
634 36         38 else { push @{$result{$strip}}, $value }
  36         57  
635 40         67 last;
636             };
637 31 50       60 /keypair/ && do {
638 31 100       56 if ($neg) {
639 4 100       6 if ($value->[0]) { delete $result{$strip}{$value->[0]} }
  2         5  
640 2         4 else { $result{$strip} = {} }
641             }
642 27         58 else { $result{$strip}{$value->[0]} = $value->[1]};
643 31         52 last;
644             };
645             }
646             }
647 121         286 return $self->{options} = \%result;
648             }
649              
650             #--------------------------------------------------------------------------#
651             # _regex_or_code
652             #--------------------------------------------------------------------------#
653              
654             sub _regex_or_code {
655 174     174   244 my ($value,$valid) = @_;
656 174 100       237 return 1 unless defined $valid;
657 171 100       291 if ( ref($valid) eq 'CODE' ) {
658 10         12 local $_ = $value;
659 10         19 return $valid->($value);
660             } else {
661 161         2675 return $value =~ /^$valid$/;
662             }
663             }
664              
665             #--------------------------------------------------------------------------#
666             # _set_defaults()
667             #--------------------------------------------------------------------------#
668              
669             sub _set_defaults {
670 186     186   273 my ($self) = @_;
671 186         216 my %default;
672 186         209 for my $k ( keys %{$self->{spec}} ) {
  186         328  
673 588         839 my $spec = $self->{spec}{$k};
674 588 100       871 my $d = exists ($spec->{default}) ? $spec->{default} : undef;
675 588         720 my $type = $self->{spec}{$k}{type};
676 588         683 my $strip = $self->{strip}{$k};
677 588 50 100     1163 throw_spec("Default for list '$spec->{canon}' must be array reference")
      66        
678             if ( $type eq "list" && defined $d && ref($d) ne "ARRAY" );
679 588 100 100     1074 throw_spec("Default for keypair '$spec->{canon}' must be hash reference")
      100        
680             if ( $type eq "keypair" && defined $d && ref($d) ne "HASH" );
681 587 100       820 if (defined $d) {
682             throw_spec("Default '$spec->{canon}' = '$d' fails to validate")
683 221 100       408 unless _validate_value($self, $d, $spec->{valid});
684             }
685 586         705 $default{$strip} = do {
686 586         670 local $_ = $type;
687 586 100       3346 /switch/ ? (defined $d ? $d: 0) :
    100          
    100          
    100          
    50          
    100          
    100          
    100          
    100          
688             /counter/ ? (defined $d ? $d: 0) :
689             /parameter/ ? $d :
690             /list/ ? (defined $d ? dclone($d): []) :
691             /keypair/ ? (defined $d ? dclone($d): {}) :
692             undef;
693             };
694             }
695 184         473 $self->{default} = \%default;
696             }
697              
698             #--------------------------------------------------------------------------#
699             # _split_equals()
700             #--------------------------------------------------------------------------#
701              
702             sub _split_equals {
703 272     272   390 my ($self,$raw) = @_;
704 272         296 my ($arg,$val);
705 272 100       1396 if ( $raw =~ /^($NEGATIVE?$VALID_NAME|$SHORT_BUNDLE)=(.*)/ ) {
706 27         67 $arg = $1;
707 27         48 $val = $2;
708             } else {
709 245         329 $arg = $raw;
710             }
711 272         600 return ($arg, $val);
712             }
713              
714             #--------------------------------------------------------------------------#
715             # _switch()
716             #--------------------------------------------------------------------------#
717              
718             sub _switch {
719 54     54   94 my ($self, $arg, $val, $neg) = @_;
720 54 100       106 throw_argv("Switch can't take a value: $self->{spec}{$arg}{canon}=$val")
721             if defined $val;
722 52 100       84 if (! $neg ) {
723             throw_argv("Switch used twice: $self->{spec}{$arg}{canon}")
724 48 100       113 if $self->{seen}{$arg} > 1;
725             }
726 51         67 push @{$self->{parsed}}, [ $arg, 1, $neg ];
  51         161  
727             }
728              
729             #--------------------------------------------------------------------------#
730             # _unbundle()
731             #--------------------------------------------------------------------------#
732              
733             sub _unbundle {
734 272     272   374 my ($self,$arg, $val) = @_;
735 272 100       854 if ( $arg =~ /^$SHORT_BUNDLE$/ ) {
736 24         68 my @flags = split(//,substr($arg,1));
737 24 100       54 unshift @{$self->{target}}, ("-" . pop(@flags) . "=" . $val)
  4         15  
738             if defined $val;
739 24         38 for ( reverse @flags ) {
740 61         64 unshift @{$self->{target}}, "-$_";
  61         122  
741             }
742 24         59 return 1;
743             }
744 248         458 return 0;
745             }
746              
747             #--------------------------------------------------------------------------#
748             # _validate_prereqs()
749             #--------------------------------------------------------------------------#
750              
751             sub _validate_prereqs {
752 181     181   267 my ($self) = @_;
753 181         187 for my $key ( keys %{$self->{spec}} ) {
  181         433  
754 529 100       951 next unless exists $self->{spec}{$key}{needs};
755 18         23 my $needs = $self->{spec}{$key}{needs};
756 18 50       52 my @prereq = ref($needs) eq 'ARRAY' ? @$needs : ( $needs );
757 18         29 for (@prereq) {
758 24 100       41 throw_spec("Prerequisite '$_' for '$self->{spec}{$key}{canon}' is not recognized")
759             unless _find_arg($self,$_);
760 23         40 $_ = _find_arg($self,$_);
761             }
762 17         30 $self->{spec}{$key}{needs} = \@prereq;
763             }
764             }
765              
766              
767             #--------------------------------------------------------------------------#
768             # _validate_spec()
769             #--------------------------------------------------------------------------#
770              
771             sub _validate_spec {
772 541     541   715 my ($self,$names,$details) = @_;
773 541         701 for my $name ( @$names ) {
774 857         1010 my $alt_name = $name;
775 857 100       2358 $alt_name =~ s/^-*// unless $self->{strict};
776 857 100       3728 throw_spec(
777             "'$name' is not a valid option name/alias"
778             ) unless $name =~ /^$VALID_NAME$/;
779             throw_spec(
780             "'$name' is not unique"
781 855 100       1596 ) if exists $self->{alias_hr}{$alt_name};
782 852         855 my $strip;
783 852         1579 ($strip = $name) =~ s/^-+//;
784             throw_spec(
785             "'$strip' conflicts with other options"
786 852 50       954 ) if grep { $strip eq $_ } values %{$self->{strip}};
  1044         1939  
  852         1784  
787             }
788 536         1133 for my $key ( keys %$details ) {
789             throw_spec(
790             "'$key' is not a valid option specification key"
791 1909 100       2159 ) unless grep { $key eq $_ } @valid_keys;
  15272         18980  
792             }
793 535         794 my $type = $details->{type};
794             throw_spec(
795             "'$type' is not a valid option type"
796 535 100       630 ) unless grep { $type eq $_ } @valid_types;
  2675         3720  
797             }
798              
799             #--------------------------------------------------------------------------#
800             # _validate_value()
801             #--------------------------------------------------------------------------#
802              
803             sub _validate_value {
804 389     389   813 my ($self, $value, $valid) = @_;
805 389 100       1276 return 1 unless defined $valid;
806 101 100       200 if ( ref($value) eq 'HASH' ) {
    100          
807 30         72 my $valid_key = $valid->[0];
808 30         38 my $valid_val = $valid->[1];
809 30         87 while (my ($k,$v) = each %$value) {
810 44 100       76 _regex_or_code($k, $valid_key) or return 0;
811 42 100       110 _regex_or_code($v, $valid_val) or return 0;
812             }
813 26         70 return 1;
814             } elsif ( ref($value) eq 'ARRAY' ) {
815 19         30 for (@$value) {
816 36 50       63 _regex_or_code($_, $valid) or return 0;
817             }
818 19         40 return 1;
819             } else {
820 52         87 return _regex_or_code($value, $valid);
821             }
822             }
823              
824             #--------------------------------------------------------------------------#
825             # AUTOLOAD()
826             #--------------------------------------------------------------------------#
827              
828             sub AUTOLOAD {
829 205     205   110105 my $self = shift;
830 205         313 my $name = $Getopt::Lucid::AUTOLOAD;
831 205         1040 $name =~ s/.*:://; # strip fully-qualified portion
832 205 100       2462 return if $name eq "DESTROY";
833 15         58 my ($action, $maybe_opt) = $name =~ /^(get|set)_(.+)/ ;
834 15 50       28 if ($action) {
835             # look for a match
836 15         15 my $opt;
837             SEARCH:
838 15         16 for my $known_opt ( values %{ $self->{strip} } ) {
  15         50  
839 45 100       73 if ( $maybe_opt eq $known_opt ) {
840 12         16 $opt = $known_opt;
841 12         15 last SEARCH;
842             }
843             # try without dashes
844 33         50 (my $fuzzy_opt = $known_opt) =~ s/-/_/g;
845 33 100       50 if ( $maybe_opt eq $fuzzy_opt ) {
846 3         4 $opt = $known_opt;
847 3         5 last SEARCH;
848             }
849             }
850              
851             # throw if no valid option was found
852 15 50       27 throw_usage("Can't $action unknown option '$maybe_opt'")
853             if ! $opt;
854              
855             # handle the accessor if an option was found
856 15 100       21 if ($action eq "set") {
857             $self->{options}{$opt} =
858             ref($self->{options}{$opt}) eq 'ARRAY' ? [@_] :
859 5 100       21 ref($self->{options}{$opt}) eq 'HASH' ? {@_} : shift;
    100          
860              
861             }
862 15         23 my $ans = $self->{options}{$opt};
863 15 100       120 return ref($ans) eq 'ARRAY' ? @$ans :
    100          
864             ref($ans) eq 'HASH' ? %$ans : $ans;
865             }
866 0           my $super = "SUPER::$name";
867 0           $self->$super(@_);
868             }
869              
870             1; # modules must be true
871              
872             __END__