File Coverage

blib/lib/Getopt/Kingpin.pm
Criterion Covered Total %
statement 215 215 100.0
branch 102 102 100.0
condition 29 30 96.6
subroutine 22 22 100.0
pod 8 8 100.0
total 376 377 99.7


line stmt bran cond sub pod time code
1             package Getopt::Kingpin;
2 31     31   2706778 use 5.008001;
  31         517  
3 31     31   179 use strict;
  31         56  
  31         608  
4 31     31   149 use warnings;
  31         56  
  31         1074  
5 31     31   16426 use Object::Simple -base;
  31         39919  
  31         225  
6 31     31   16558 use Getopt::Kingpin::Flags;
  31         85  
  31         290  
7 31     31   15745 use Getopt::Kingpin::Args;
  31         77  
  31         245  
8 31     31   13693 use Getopt::Kingpin::Commands;
  31         87  
  31         301  
9 31     31   1091 use File::Basename;
  31         61  
  31         3394  
10 31     31   231 use Carp;
  31         64  
  31         1804  
11 31     31   213 use Scalar::Util qw(blessed);
  31         66  
  31         2727  
12              
13             our $VERSION = "0.11";
14              
15             use overload (
16 7     7   3880 '""' => sub {$_[0]->name},
17 31         484 fallback => 1,
18 31     31   259 );
  31         77  
19              
20             has flags => sub {
21             my $flags = Getopt::Kingpin::Flags->new;
22             $flags->add(
23             name => 'help',
24             description => 'Show context-sensitive help.',
25             )->bool();
26             return $flags;
27             };
28              
29             has args => sub {
30             my $args = Getopt::Kingpin::Args->new;
31             return $args;
32             };
33              
34             has commands => sub {
35             my $commands = Getopt::Kingpin::Commands->new;
36             return $commands;
37             };
38              
39             has _version => sub {
40             return "";
41             };
42              
43             has parent => sub {
44             return
45             };
46              
47             has name => sub {
48             return basename($0);
49             };
50              
51             has description => sub {
52             return "";
53             };
54              
55             has terminate => sub {
56             return sub {
57             my $ret = defined $_[1] ? $_[1] : 0;
58             exit $ret;
59             };
60             };
61              
62             sub new {
63 264     264 1 396103 my $class = shift;
64 264         571 my @args = @_;
65              
66 264         380 my $self;
67 264 100       644 if (@args == 2) {
68 1         5 $self = $class->SUPER::new(
69             name => $args[0],
70             description => $args[1],
71             );
72             } else {
73 263         883 $self = $class->SUPER::new(@args);
74             }
75              
76 264         1943 return $self;
77             }
78              
79             sub flag {
80 180     180 1 2920 my $self = shift;
81 180         399 my ($name, $description) = @_;
82 180         3693 my $ret = $self->flags->add(
83             name => $name,
84             description => $description,
85             );
86 179         2201 return $ret;
87             }
88              
89             sub arg {
90 123     123 1 1086 my $self = shift;
91 123         266 my ($name, $description) = @_;
92 123         2309 my $ret = $self->args->add(
93             name => $name,
94             description => $description,
95             );
96 123         853 return $ret;
97             }
98              
99             sub command {
100 57     57 1 1014 my $self = shift;
101 57         119 my ($name, $description) = @_;
102 57 100       1022 if ($self->commands->count == 0) {
103 36         568 $self->commands->add(
104             name => "help",
105             description => "Show help.",
106             );
107             }
108 57         1011 my $ret = $self->commands->add(
109             name => $name,
110             description => $description,
111             parent => $self,
112             );
113 57         173 return $ret;
114             }
115              
116             sub parse {
117 164     164 1 96485 my $self = shift;
118 164         359 my @argv = @_;
119              
120 164 100       501 if (scalar @argv == 0) {
121 161         410 @argv = @ARGV;
122             }
123              
124 164         467 my ($ret, $exit_code) = $self->_parse(@argv);
125 163 100       461 if (defined $exit_code) {
126 73         1593 return $self->terminate->($ret, $exit_code);
127             }
128 90         275 return $ret;
129             }
130              
131             sub _parse {
132 191     191   306 my $self = shift;
133 191         396 my @argv = @_;
134              
135 191 100       4088 if (defined $self->parent) {
136 27         569 $self->flags->unshift($self->parent->flags->values);
137             }
138              
139             my $required_but_not_found = {
140 191         4959 map {$_->name => $_} grep {$_->_required} $self->flags->values,
  8         199  
  341         6673  
141             };
142 191         1806 my $arg_index = 0;
143 191         321 my $arg_only = 0;
144            
145 191 100 100     781 if (@argv == 1 and ref($argv[0]) and ref($argv[0]) eq "ARRAY") {
      66        
146 2         4 @argv = @{ $argv[0] };
  2         6  
147             }
148            
149 191         500 while (scalar @argv > 0) {
150 221         598 my $arg = shift @argv;
151 221 100 100     1863 if ($arg eq "--") {
    100 100        
    100          
152 3         7 $arg_only = 1;
153             } elsif ($arg_only == 0 and $arg =~ /^--(no-)?(\S+?)(=(\S+))?$/) {
154 110         259 my $no = $1;
155 110         220 my $name = $2;
156 110         186 my $equal = $3;
157 110         232 my $val = $4;
158              
159 110 100       293 delete $required_but_not_found->{$name} if exists $required_but_not_found->{$name};
160 110         2035 my $v = $self->flags->get($name);
161              
162 110 100       888 if (not defined $v) {
163 1         19 printf STDERR "%s: error: unknown long flag '--%s', try --help\n", $self->name, $name;
164 1         13 return undef, 1;
165             }
166              
167 109         163 my $value;
168 109 100       1792 if ($v->type eq "Bool") {
    100          
169 52 100       464 $value = defined $no ? 0 : 1;
170             } elsif (defined $equal) {
171 13         115 $value = $val;
172             } else {
173 44         454 $value = shift @argv;
174             }
175              
176 109         472 my ($dummy, $exit) = $v->set_value($value);
177 108 100       1369 if (defined $exit) {
178 6         63 return undef, $exit;
179             }
180             } elsif ($arg_only == 0 and $arg =~ /^-(\S+)$/) {
181 16         40 my $short_name = $1;
182 16         48 while (length $short_name > 0) {
183 18         63 my ($s, $remain) = split //, $short_name, 2;
184 18         31 my $name;
185 18         309 foreach my $f ($self->flags->values) {
186 46 100 100     1033 if (defined $f->short_name and $f->short_name eq $s) {
187 16         874 $name = $f->name;
188             }
189             }
190 18 100       240 if (not defined $name) {
191 2         37 printf STDERR "%s: error: unknown short flag '-%s', try --help\n", $self->name, $s;
192 2         20 return undef, 1;
193             }
194 16 100       39 delete $required_but_not_found->{$name} if exists $required_but_not_found->{$name};
195 16         269 my $v = $self->flags->get($name);
196              
197 16         108 my $value;
198 16 100       256 if ($v->type eq "Bool") {
199 9         63 $value = 1;
200             } else {
201 7 100       60 if (length $remain > 0) {
202 3         4 $value = $remain;
203 3         6 $remain = "";
204             } else {
205 4         9 $value = shift @argv;
206             }
207             }
208              
209 16         52 my ($dummy, $exit) = $v->set_value($value);
210 16 100       153 if (defined $exit) {
211 1         6 return undef, $exit;
212             }
213 15         58 $short_name = $remain;
214             }
215             } else {
216 92 100       214 if ($arg_index == 0) {
217 76         1380 my $cmd = $self->commands->get($arg);
218 76 100       198 if (defined $cmd) {
219 34 100       535 if ($cmd->name eq "help") {
220 7         148 $self->flags->get("help")->set_value(1)
221             } else {
222 27         190 my @argv_for_command = @argv;
223 27         47 @argv = ();
224              
225 27 100       457 if ($self->flags->get("help")) {
226 13         308 push @argv_for_command, "--help";
227             }
228 27         230 return $cmd->_parse(@argv_for_command);
229             }
230             }
231             }
232              
233 65 100 100     413 if (not ($arg_index == 0 and $arg eq "help")) {
234 58 100       1028 if ($arg_index < $self->args->count) {
235 57         1295 my $arg_obj = $self->args->get_by_index($arg_index);
236 57         485 my ($dummy, $exit) = $arg_obj->set_value($arg);
237 57 100       584 if (defined $exit) {
238 5         22 return undef, $exit;
239             }
240 52 100 100     859 if (not $arg_obj->is_cumulative || $arg_obj->is_hash) {
241 34         1033 $arg_index++;
242             }
243             } else {
244 1         27 printf STDERR "%s: error: unexpected %s, try --help\n", $self->name, $arg;
245 1         10 return undef, 1;
246             }
247             }
248             }
249             }
250              
251 147 100       2729 if ($self->flags->get("help")) {
252 45         1134 $self->help;
253 45         483 return undef, 0;
254             }
255              
256 102 100       2242 if ($self->flags->get("version")) {
257 1         39 printf STDERR "%s\n", $self->_version;
258 1         91 return undef, 0;
259             }
260              
261             my $process_item = sub {
262 257     257   417 my $item = shift;
263 257 100       4265 if (defined $item->value) {
    100          
    100          
    100          
    100          
264 90         613 return;
265             } elsif (defined $item->_envar) {
266 5         196 my ($dummy, $exit) = $item->set_value($item->_envar);
267 5 100       51 if (defined $exit) {
268 2         6 return undef, $exit;
269             }
270             } elsif (defined $item->_default) {
271 136         8133 my $default = $item->_default;
272 136 100 100     1346 if (ref($default) eq 'CODE'
      100        
273             || (blessed($default) && overload::Method($default, '&{}'))) {
274 12         522 $default = $default->();
275             }
276 136 100       2498 if ($item->type =~ /List$/) {
    100          
277 8         62 foreach my $val (@{$default}) {
  8         19  
278 14         38 my ($dummy, $exit) = $item->set_value($val);
279 14 100       110 if (defined $exit) {
280 2         6 return undef, $exit;
281             }
282             }
283             } elsif ($item->type =~ /Hash$/) {
284 8         213 while (my ($key, $val) = each %{$default}) {
  23         84  
285 16         51 my ($dummy, $exit) = $item->set_value([ $key, $val ]);
286 16 100       146 if (defined $exit) {
287 1         4 return undef, $exit;
288             }
289             }
290             } else {
291 120         3551 my ($dummy, $exit) = $item->set_value($default);
292 120 100       1125 if (defined $exit) {
293 2         10 return undef, $exit;
294             }
295             }
296             } elsif ($item->type =~ /List$/) {
297 8         628 $item->value([]);
298             } elsif ($item->type =~ /Hash$/) {
299 7         671 $item->value({});
300             }
301 160         1393 return;
302 101         858 };
303              
304 101         1837 foreach my $f ($self->flags->values) {
305 188         423 my @r = $process_item->($f);
306 188 100       597 return @r if @r > 1;
307             }
308 97         1859 for (my $i = 0; $i < $self->args->count; $i++) {
309 69         1485 my $arg = $self->args->get_by_index($i);
310 69         475 my @r = $process_item->($arg);
311 69 100       1219 return @r if @r > 1;
312             }
313              
314 94         705 foreach my $r (values %$required_but_not_found) {
315 2         78 printf STDERR "%s: error: required flag --%s not provided, try --help\n", $self->name, $r->name;
316 2         226 return undef, 1;
317             }
318 92         1647 for (my $i = 0; $i < $self->args->count; $i++) {
319 66         1449 my $arg = $self->args->get_by_index($i);
320 66 100 100     1384 if ($arg->_required and not $arg->_defined) {
321 2         88 printf STDERR "%s: error: required arg '%s' not provided, try --help\n", $self->name, $arg->name;
322 2         142 return undef, 1;
323             }
324             }
325              
326 90         1728 return $self;
327             }
328              
329             sub version {
330 2     2 1 109 my $self = shift;
331 2         8 my ($version) = @_;
332              
333 2         36 my $f = $self->flags->add(
334             name => 'version',
335             description => 'Show application version.',
336             )->bool();
337 2         37 $self->_version($version);
338             }
339              
340             sub help_short {
341 26     26 1 45 my $self = shift;
342 26         435 my @help = ($self->name);
343              
344 26         84 push @help, "[]";
345              
346 26 100       480 if ($self->commands->count > 1) {
347 6         48 push @help, "";
348              
349 6         11 my $has_args = 0;
350 6         91 foreach my $cmd ($self->commands->get_all) {
351 17 100       327 if ($cmd->args->count > 0) {
352 2         16 $has_args = 1;
353             }
354             }
355              
356 6         14 push @help, "[ ...]";
357             } else {
358 20         371 foreach my $arg ($self->args->get_all) {
359 8         197 push @help, sprintf "<%s>", $arg->name;
360             }
361             }
362              
363 26         1114 return join " ", @help;
364             }
365              
366             sub help {
367 26     26 1 51 my $self = shift;
368 26         73 printf "usage: %s\n", $self->help_short;
369 26         409 printf "\n";
370              
371 26 100       756 if ($self->description ne "") {
372 1         30 printf "%s\n", $self->description;
373 1         38 printf "\n";
374             }
375              
376 26         523 printf "%s\n", $self->flags->help;
377              
378 26 100       746 if ($self->commands->count > 1) {
379 6         130 printf "%s\n", $self->commands->help;
380             } else {
381 20 100       501 if ($self->args->count > 0) {
382 5         115 printf "%s\n", $self->args->help;
383             }
384             }
385             }
386              
387              
388             1;
389             __END__