File Coverage

blib/lib/Getopt/Kingpin.pm
Criterion Covered Total %
statement 207 207 100.0
branch 104 104 100.0
condition 15 15 100.0
subroutine 20 20 100.0
pod 8 8 100.0
total 354 354 100.0


line stmt bran cond sub pod time code
1             package Getopt::Kingpin;
2 28     28   2158268 use 5.008001;
  28         373  
3 28     28   139 use strict;
  28         48  
  28         517  
4 28     28   120 use warnings;
  28         48  
  28         967  
5 28     28   12812 use Object::Simple -base;
  28         32122  
  28         169  
6 28     28   13088 use Getopt::Kingpin::Flags;
  28         74  
  28         213  
7 28     28   14440 use Getopt::Kingpin::Args;
  28         68  
  28         191  
8 28     28   11036 use Getopt::Kingpin::Commands;
  28         67  
  28         228  
9 28     28   868 use File::Basename;
  28         48  
  28         2562  
10 28     28   170 use Carp;
  28         56  
  28         2295  
11              
12             our $VERSION = "0.09";
13              
14             use overload (
15 6     6   2740 '""' => sub {$_[0]->name},
16 28         294 fallback => 1,
17 28     28   182 );
  28         85  
18              
19             has flags => sub {
20             my $flags = Getopt::Kingpin::Flags->new;
21             $flags->add(
22             name => 'help',
23             description => 'Show context-sensitive help.',
24             )->bool();
25             return $flags;
26             };
27              
28             has args => sub {
29             my $args = Getopt::Kingpin::Args->new;
30             return $args;
31             };
32              
33             has commands => sub {
34             my $commands = Getopt::Kingpin::Commands->new;
35             return $commands;
36             };
37              
38             has _version => sub {
39             return "";
40             };
41              
42             has parent => sub {
43             return
44             };
45              
46             has name => sub {
47             return basename($0);
48             };
49              
50             has description => sub {
51             return "";
52             };
53              
54             has terminate => sub {
55             return sub {
56             my $ret = defined $_[1] ? $_[1] : 0;
57             exit $ret;
58             };
59             };
60              
61             sub new {
62 220     220 1 294841 my $class = shift;
63 220         491 my @args = @_;
64              
65 220         309 my $self;
66 220 100       516 if (@args == 2) {
67 1         4 $self = $class->SUPER::new(
68             name => $args[0],
69             description => $args[1],
70             );
71             } else {
72 219         793 $self = $class->SUPER::new(@args);
73             }
74              
75 220         1625 return $self;
76             }
77              
78             sub flag {
79 132     132 1 1502 my $self = shift;
80 132         272 my ($name, $description) = @_;
81 132         2460 my $ret = $self->flags->add(
82             name => $name,
83             description => $description,
84             );
85 131         1420 return $ret;
86             }
87              
88             sub arg {
89 100     100 1 717 my $self = shift;
90 100         213 my ($name, $description) = @_;
91 100         1691 my $ret = $self->args->add(
92             name => $name,
93             description => $description,
94             );
95 100         612 return $ret;
96             }
97              
98             sub command {
99 53     53 1 912 my $self = shift;
100 53         125 my ($name, $description) = @_;
101 53 100       927 if ($self->commands->count == 0) {
102 33         533 $self->commands->add(
103             name => "help",
104             description => "Show help.",
105             );
106             }
107 53         965 my $ret = $self->commands->add(
108             name => $name,
109             description => $description,
110             parent => $self,
111             );
112 53         124 return $ret;
113             }
114              
115             sub parse {
116 128     128 1 121190 my $self = shift;
117 128         266 my @argv = @_;
118              
119 128 100       384 if (scalar @argv == 0) {
120 127         336 @argv = @ARGV;
121             }
122              
123 128         342 my ($ret, $exit_code) = $self->_parse(@argv);
124 127 100       405 if (defined $exit_code) {
125 64         1302 return $self->terminate->($ret, $exit_code);
126             }
127 63         159 return $ret;
128             }
129              
130             sub _parse {
131 152     152   241 my $self = shift;
132 152         296 my @argv = @_;
133              
134 152 100       3129 if (defined $self->parent) {
135 24         545 $self->flags->unshift($self->parent->flags->values);
136             }
137              
138             my $required_but_not_found = {
139 152         2763 map {$_->name => $_} grep {$_->_required} $self->flags->values,
  8         164  
  267         4559  
140             };
141 152         1197 my $arg_index = 0;
142 152         246 my $arg_only = 0;
143 152         384 while (scalar @argv > 0) {
144 190         462 my $arg = shift @argv;
145 190 100 100     1615 if ($arg eq "--") {
    100 100        
    100          
146 3         9 $arg_only = 1;
147             } elsif ($arg_only == 0 and $arg =~ /^--(no-)?(\S+?)(=(\S+))?$/) {
148 88         200 my $no = $1;
149 88         166 my $name = $2;
150 88         167 my $equal = $3;
151 88         198 my $val = $4;
152              
153 88 100       246 delete $required_but_not_found->{$name} if exists $required_but_not_found->{$name};
154 88         1575 my $v = $self->flags->get($name);
155              
156 88 100       573 if (not defined $v) {
157 1         18 printf STDERR "%s: error: unknown long flag '--%s', try --help\n", $self->name, $name;
158 1         9 return undef, 1;
159             }
160              
161 87         136 my $value;
162 87 100       1318 if ($v->type eq "Bool") {
    100          
163 47 100       387 $value = defined $no ? 0 : 1;
164             } elsif (defined $equal) {
165 12         101 $value = $val;
166             } else {
167 28         249 $value = shift @argv;
168             }
169              
170 87         325 my ($dummy, $exit) = $v->set_value($value);
171 86 100       943 if (defined $exit) {
172 3         13 return undef, $exit;
173             }
174             } elsif ($arg_only == 0 and $arg =~ /^-(\S+)$/) {
175 16         40 my $short_name = $1;
176 16         42 while (length $short_name > 0) {
177 18         63 my ($s, $remain) = split //, $short_name, 2;
178 18         29 my $name;
179 18         297 foreach my $f ($self->flags->values) {
180 46 100 100     979 if (defined $f->short_name and $f->short_name eq $s) {
181 16         659 $name = $f->name;
182             }
183             }
184 18 100       231 if (not defined $name) {
185 2         41 printf STDERR "%s: error: unknown short flag '-%s', try --help\n", $self->name, $s;
186 2         20 return undef, 1;
187             }
188 16 100       38 delete $required_but_not_found->{$name} if exists $required_but_not_found->{$name};
189 16         242 my $v = $self->flags->get($name);
190              
191 16         93 my $value;
192 16 100       241 if ($v->type eq "Bool") {
193 9         61 $value = 1;
194             } else {
195 7 100       59 if (length $remain > 0) {
196 3         7 $value = $remain;
197 3         4 $remain = "";
198             } else {
199 4         8 $value = shift @argv;
200             }
201             }
202              
203 16         48 my ($dummy, $exit) = $v->set_value($value);
204 16 100       173 if (defined $exit) {
205 1         5 return undef, $exit;
206             }
207 15         67 $short_name = $remain;
208             }
209             } else {
210 83 100       254 if ($arg_index == 0) {
211 67         1128 my $cmd = $self->commands->get($arg);
212 67 100       180 if (defined $cmd) {
213 31 100       467 if ($cmd->name eq "help") {
214 7         146 $self->flags->get("help")->set_value(1)
215             } else {
216 24         162 my @argv_for_command = @argv;
217 24         44 @argv = ();
218              
219 24 100       371 if ($self->flags->get("help")) {
220 13         304 push @argv_for_command, "--help";
221             }
222 24         189 return $cmd->_parse(@argv_for_command);
223             }
224             }
225             }
226              
227 59 100 100     366 if (not ($arg_index == 0 and $arg eq "help")) {
228 52 100       843 if ($arg_index < $self->args->count) {
229 51         989 my ($dummy, $exit) = $self->args->get_by_index($arg_index)->set_value($arg);
230 51 100       410 if (defined $exit) {
231 5         22 return undef, $exit;
232             }
233 46 100       690 if (not $self->args->get_by_index($arg_index)->is_cumulative) {
234 34         845 $arg_index++;
235             }
236             } else {
237 1         21 printf STDERR "%s: error: unexpected %s, try --help\n", $self->name, $arg;
238 1         8 return undef, 1;
239             }
240             }
241             }
242             }
243              
244 114 100       1912 if ($self->flags->get("help")) {
245 40         926 $self->help;
246 40         385 return undef, 0;
247             }
248              
249 74 100       1501 if ($self->flags->get("version")) {
250 1         39 printf STDERR "%s\n", $self->_version;
251 1         66 return undef, 0;
252             }
253              
254 73         1092 foreach my $f ($self->flags->values) {
255 135 100       2067 if (defined $f->value) {
    100          
    100          
    100          
256 45         305 next;
257             } elsif (defined $f->_envar) {
258 2         64 my ($dummy, $exit) = $f->set_value($f->_envar);
259 2 100       11 if (defined $exit) {
260 1         4 return undef, $exit;
261             }
262             } elsif (defined $f->_default) {
263 84 100       4563 if ($f->type =~ /List$/) {
264 2         15 foreach my $default (@{$f->_default}) {
  2         26  
265 3         17 my ($dummy, $exit) = $f->set_value($default);
266 3 100       21 if (defined $exit) {
267 1         3 return undef, $exit;
268             }
269             }
270             } else {
271 82         1916 my ($dummy, $exit) = $f->set_value($f->_default);
272 82 100       783 if (defined $exit) {
273 1         5 return undef, $exit;
274             }
275             }
276             } elsif ($f->type =~ /List$/) {
277 2         126 $f->value([]);
278             }
279             }
280 70         1236 for (my $i = 0; $i < $self->args->count; $i++) {
281 51         990 my $arg = $self->args->get_by_index($i);
282 51 100       918 if (defined $arg->value) {
    100          
    100          
    100          
283 36         692 next;
284             } elsif (defined $arg->_envar) {
285 3         148 my ($dummy, $exit) = $arg->set_value($arg->_envar);
286 3 100       49 if (defined $exit) {
287 1         5 return undef, $exit;
288             }
289             } elsif (defined $arg->_default) {
290 6 100       303 if ($arg->type =~ /List$/) {
291 2         15 foreach my $default (@{$arg->_default}) {
  2         29  
292 3         16 my ($dummy, $exit) = $arg->set_value($default);
293 3 100       32 if (defined $exit) {
294 1         3 return undef, $exit;
295             }
296             }
297             } else {
298 4         78 my ($dummy, $exit) = $arg->set_value($arg->_default);
299 4 100       85 if (defined $exit) {
300 1         4 return undef, $exit;
301             }
302             }
303             } elsif ($arg->type =~ /List$/) {
304 2         150 $arg->value([]);
305             }
306             }
307              
308 67         365 foreach my $r (values %$required_but_not_found) {
309 2         49 printf STDERR "%s: error: required flag --%s not provided, try --help\n", $self->name, $r->name;
310 2         124 return undef, 1;
311             }
312 65         1079 for (my $i = 0; $i < $self->args->count; $i++) {
313 48         932 my $arg = $self->args->get_by_index($i);
314 48 100 100     942 if ($arg->_required and not $arg->_defined) {
315 2         76 printf STDERR "%s: error: required arg '%s' not provided, try --help\n", $self->name, $arg->name;
316 2         131 return undef, 1;
317             }
318             }
319              
320 63         547 return $self;
321             }
322              
323             sub version {
324 2     2 1 114 my $self = shift;
325 2         5 my ($version) = @_;
326              
327 2         38 my $f = $self->flags->add(
328             name => 'version',
329             description => 'Show application version.',
330             )->bool();
331 2         50 $self->_version($version);
332             }
333              
334             sub help_short {
335 23     23 1 35 my $self = shift;
336 23         333 my @help = ($self->name);
337              
338 23         77 push @help, "[]";
339              
340 23 100       379 if ($self->commands->count > 1) {
341 6         50 push @help, "";
342              
343 6         12 my $has_args = 0;
344 6         96 foreach my $cmd ($self->commands->get_all) {
345 17 100       300 if ($cmd->args->count > 0) {
346 2         16 $has_args = 1;
347             }
348             }
349              
350 6         15 push @help, "[ ...]";
351             } else {
352 17         244 foreach my $arg ($self->args->get_all) {
353 8         152 push @help, sprintf "<%s>", $arg->name;
354             }
355             }
356              
357 23         859 return join " ", @help;
358             }
359              
360             sub help {
361 23     23 1 35 my $self = shift;
362 23         55 printf "usage: %s\n", $self->help_short;
363 23         290 printf "\n";
364              
365 23 100       571 if ($self->description ne "") {
366 1         22 printf "%s\n", $self->description;
367 1         25 printf "\n";
368             }
369              
370 23         368 printf "%s\n", $self->flags->help;
371              
372 23 100       533 if ($self->commands->count > 1) {
373 6         131 printf "%s\n", $self->commands->help;
374             } else {
375 17 100       320 if ($self->args->count > 0) {
376 5         87 printf "%s\n", $self->args->help;
377             }
378             }
379             }
380              
381              
382             1;
383             __END__