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   2604937 use 5.008001;
  31         425  
3 31     31   184 use strict;
  31         59  
  31         629  
4 31     31   149 use warnings;
  31         57  
  31         1080  
5 31     31   15689 use Object::Simple -base;
  31         38988  
  31         222  
6 31     31   16332 use Getopt::Kingpin::Flags;
  31         94  
  31         251  
7 31     31   15718 use Getopt::Kingpin::Args;
  31         77  
  31         231  
8 31     31   13479 use Getopt::Kingpin::Commands;
  31         79  
  31         281  
9 31     31   1009 use File::Basename;
  31         61  
  31         3172  
10 31     31   238 use Carp;
  31         72  
  31         1648  
11 31     31   265 use Scalar::Util qw(blessed);
  31         58  
  31         2703  
12              
13             our $VERSION = "0.10";
14              
15             use overload (
16 7     7   3877 '""' => sub {$_[0]->name},
17 31         312 fallback => 1,
18 31     31   226 );
  31         61  
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 370981 my $class = shift;
64 264         554 my @args = @_;
65              
66 264         694 my $self;
67 264 100       667 if (@args == 2) {
68 1         5 $self = $class->SUPER::new(
69             name => $args[0],
70             description => $args[1],
71             );
72             } else {
73 263         893 $self = $class->SUPER::new(@args);
74             }
75              
76 264         1881 return $self;
77             }
78              
79             sub flag {
80 180     180 1 2336 my $self = shift;
81 180         398 my ($name, $description) = @_;
82 180         3627 my $ret = $self->flags->add(
83             name => $name,
84             description => $description,
85             );
86 179         2130 return $ret;
87             }
88              
89             sub arg {
90 123     123 1 901 my $self = shift;
91 123         277 my ($name, $description) = @_;
92 123         2268 my $ret = $self->args->add(
93             name => $name,
94             description => $description,
95             );
96 123         865 return $ret;
97             }
98              
99             sub command {
100 57     57 1 868 my $self = shift;
101 57         110 my ($name, $description) = @_;
102 57 100       856 if ($self->commands->count == 0) {
103 36         504 $self->commands->add(
104             name => "help",
105             description => "Show help.",
106             );
107             }
108 57         879 my $ret = $self->commands->add(
109             name => $name,
110             description => $description,
111             parent => $self,
112             );
113 57         119 return $ret;
114             }
115              
116             sub parse {
117 164     164 1 108381 my $self = shift;
118 164         408 my @argv = @_;
119              
120 164 100       509 if (scalar @argv == 0) {
121 161         405 @argv = @ARGV;
122             }
123              
124 164         478 my ($ret, $exit_code) = $self->_parse(@argv);
125 163 100       432 if (defined $exit_code) {
126 73         1506 return $self->terminate->($ret, $exit_code);
127             }
128 90         259 return $ret;
129             }
130              
131             sub _parse {
132 191     191   341 my $self = shift;
133 191         385 my @argv = @_;
134              
135 191 100       4044 if (defined $self->parent) {
136 27         522 $self->flags->unshift($self->parent->flags->values);
137             }
138              
139             my $required_but_not_found = {
140 191         3139 map {$_->name => $_} grep {$_->_required} $self->flags->values,
  8         179  
  341         6173  
141             };
142 191         1500 my $arg_index = 0;
143 191         270 my $arg_only = 0;
144            
145 191 100 100     789 if (@argv == 1 and ref($argv[0]) and ref($argv[0]) eq "ARRAY") {
      66        
146 2         41 @argv = @{ $argv[0] };
  2         8  
147             }
148            
149 191         480 while (scalar @argv > 0) {
150 221         585 my $arg = shift @argv;
151 221 100 100     1796 if ($arg eq "--") {
    100 100        
    100          
152 3         6 $arg_only = 1;
153             } elsif ($arg_only == 0 and $arg =~ /^--(no-)?(\S+?)(=(\S+))?$/) {
154 110         246 my $no = $1;
155 110         223 my $name = $2;
156 110         186 my $equal = $3;
157 110         215 my $val = $4;
158              
159 110 100       284 delete $required_but_not_found->{$name} if exists $required_but_not_found->{$name};
160 110         1891 my $v = $self->flags->get($name);
161              
162 110 100       734 if (not defined $v) {
163 1         20 printf STDERR "%s: error: unknown long flag '--%s', try --help\n", $self->name, $name;
164 1         10 return undef, 1;
165             }
166              
167 109         175 my $value;
168 109 100       1694 if ($v->type eq "Bool") {
    100          
169 52 100       358 $value = defined $no ? 0 : 1;
170             } elsif (defined $equal) {
171 13         119 $value = $val;
172             } else {
173 44         368 $value = shift @argv;
174             }
175              
176 109         416 my ($dummy, $exit) = $v->set_value($value);
177 108 100       1159 if (defined $exit) {
178 6         42 return undef, $exit;
179             }
180             } elsif ($arg_only == 0 and $arg =~ /^-(\S+)$/) {
181 16         43 my $short_name = $1;
182 16         64 while (length $short_name > 0) {
183 18         92 my ($s, $remain) = split //, $short_name, 2;
184 18         37 my $name;
185 18         313 foreach my $f ($self->flags->values) {
186 46 100 100     1033 if (defined $f->short_name and $f->short_name eq $s) {
187 16         678 $name = $f->name;
188             }
189             }
190 18 100       251 if (not defined $name) {
191 2         38 printf STDERR "%s: error: unknown short flag '-%s', try --help\n", $self->name, $s;
192 2         21 return undef, 1;
193             }
194 16 100       41 delete $required_but_not_found->{$name} if exists $required_but_not_found->{$name};
195 16         263 my $v = $self->flags->get($name);
196              
197 16         95 my $value;
198 16 100       251 if ($v->type eq "Bool") {
199 9         66 $value = 1;
200             } else {
201 7 100       53 if (length $remain > 0) {
202 3         4 $value = $remain;
203 3         5 $remain = "";
204             } else {
205 4         9 $value = shift @argv;
206             }
207             }
208              
209 16         46 my ($dummy, $exit) = $v->set_value($value);
210 16 100       133 if (defined $exit) {
211 1         5 return undef, $exit;
212             }
213 15         93 $short_name = $remain;
214             }
215             } else {
216 92 100       215 if ($arg_index == 0) {
217 76         1284 my $cmd = $self->commands->get($arg);
218 76 100       221 if (defined $cmd) {
219 34 100       447 if ($cmd->name eq "help") {
220 7         150 $self->flags->get("help")->set_value(1)
221             } else {
222 27         160 my @argv_for_command = @argv;
223 27         38 @argv = ();
224              
225 27 100       358 if ($self->flags->get("help")) {
226 13         252 push @argv_for_command, "--help";
227             }
228 27         177 return $cmd->_parse(@argv_for_command);
229             }
230             }
231             }
232              
233 65 100 100     315 if (not ($arg_index == 0 and $arg eq "help")) {
234 58 100       1017 if ($arg_index < $self->args->count) {
235 57         1210 my $arg_obj = $self->args->get_by_index($arg_index);
236 57         459 my ($dummy, $exit) = $arg_obj->set_value($arg);
237 57 100       598 if (defined $exit) {
238 5         20 return undef, $exit;
239             }
240 52 100 100     858 if (not $arg_obj->is_cumulative || $arg_obj->is_hash) {
241 34         1027 $arg_index++;
242             }
243             } else {
244 1         25 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       2585 if ($self->flags->get("help")) {
252 45         994 $self->help;
253 45         407 return undef, 0;
254             }
255              
256 102 100       2240 if ($self->flags->get("version")) {
257 1         32 printf STDERR "%s\n", $self->_version;
258 1         67 return undef, 0;
259             }
260              
261             my $process_item = sub {
262 257     257   407 my $item = shift;
263 257 100       4145 if (defined $item->value) {
    100          
    100          
    100          
    100          
264 90         565 return;
265             } elsif (defined $item->_envar) {
266 5         209 my ($dummy, $exit) = $item->set_value($item->_envar);
267 5 100       43 if (defined $exit) {
268 2         7 return undef, $exit;
269             }
270             } elsif (defined $item->_default) {
271 136         8002 my $default = $item->_default;
272 136 100 100     1394 if (ref($default) eq 'CODE'
      100        
273             || (blessed($default) && overload::Method($default, '&{}'))) {
274 12         488 $default = $default->();
275             }
276 136 100       2484 if ($item->type =~ /List$/) {
    100          
277 8         64 foreach my $val (@{$default}) {
  8         21  
278 14         41 my ($dummy, $exit) = $item->set_value($val);
279 14 100       121 if (defined $exit) {
280 2         8 return undef, $exit;
281             }
282             }
283             } elsif ($item->type =~ /Hash$/) {
284 8         209 while (my ($key, $val) = each %{$default}) {
  23         88  
285 16         54 my ($dummy, $exit) = $item->set_value([ $key, $val ]);
286 16 100       163 if (defined $exit) {
287 1         5 return undef, $exit;
288             }
289             }
290             } else {
291 120         3529 my ($dummy, $exit) = $item->set_value($default);
292 120 100       1169 if (defined $exit) {
293 2         7 return undef, $exit;
294             }
295             }
296             } elsif ($item->type =~ /List$/) {
297 8         635 $item->value([]);
298             } elsif ($item->type =~ /Hash$/) {
299 7         706 $item->value({});
300             }
301 160         1388 return;
302 101         808 };
303              
304 101         1754 foreach my $f ($self->flags->values) {
305 188         413 my @r = $process_item->($f);
306 188 100       594 return @r if @r > 1;
307             }
308 97         1729 for (my $i = 0; $i < $self->args->count; $i++) {
309 69         1437 my $arg = $self->args->get_by_index($i);
310 69         450 my @r = $process_item->($arg);
311 69 100       1193 return @r if @r > 1;
312             }
313              
314 94         591 foreach my $r (values %$required_but_not_found) {
315 2         45 printf STDERR "%s: error: required flag --%s not provided, try --help\n", $self->name, $r->name;
316 2         169 return undef, 1;
317             }
318 92         1662 for (my $i = 0; $i < $self->args->count; $i++) {
319 66         1368 my $arg = $self->args->get_by_index($i);
320 66 100 100     1334 if ($arg->_required and not $arg->_defined) {
321 2         93 printf STDERR "%s: error: required arg '%s' not provided, try --help\n", $self->name, $arg->name;
322 2         182 return undef, 1;
323             }
324             }
325              
326 90         1703 return $self;
327             }
328              
329             sub version {
330 2     2 1 99 my $self = shift;
331 2         5 my ($version) = @_;
332              
333 2         30 my $f = $self->flags->add(
334             name => 'version',
335             description => 'Show application version.',
336             )->bool();
337 2         29 $self->_version($version);
338             }
339              
340             sub help_short {
341 26     26 1 39 my $self = shift;
342 26         390 my @help = ($self->name);
343              
344 26         79 push @help, "[]";
345              
346 26 100       451 if ($self->commands->count > 1) {
347 6         43 push @help, "";
348              
349 6         10 my $has_args = 0;
350 6         77 foreach my $cmd ($self->commands->get_all) {
351 17 100       254 if ($cmd->args->count > 0) {
352 2         13 $has_args = 1;
353             }
354             }
355              
356 6         14 push @help, "[ ...]";
357             } else {
358 20         343 foreach my $arg ($self->args->get_all) {
359 8         179 push @help, sprintf "<%s>", $arg->name;
360             }
361             }
362              
363 26         1298 return join " ", @help;
364             }
365              
366             sub help {
367 26     26 1 40 my $self = shift;
368 26         57 printf "usage: %s\n", $self->help_short;
369 26         357 printf "\n";
370              
371 26 100       682 if ($self->description ne "") {
372 1         28 printf "%s\n", $self->description;
373 1         31 printf "\n";
374             }
375              
376 26         427 printf "%s\n", $self->flags->help;
377              
378 26 100       634 if ($self->commands->count > 1) {
379 6         116 printf "%s\n", $self->commands->help;
380             } else {
381 20 100       437 if ($self->args->count > 0) {
382 5         112 printf "%s\n", $self->args->help;
383             }
384             }
385             }
386              
387              
388             1;
389             __END__