File Coverage

blib/lib/CLI/Driver/Action.pm
Criterion Covered Total %
statement 142 213 66.6
branch 37 82 45.1
condition 1 6 16.6
subroutine 31 34 91.1
pod n/a
total 211 335 62.9


line stmt bran cond sub pod time code
1             package CLI::Driver::Action;
2              
3 18     18   123 use Modern::Perl;
  18         40  
  18         199  
4 18     18   3065 use Moose;
  18         37  
  18         159  
5 18     18   118608 use namespace::autoclean;
  18         45  
  18         179  
6 18     18   1545 use Kavorka '-all';
  18         36  
  18         140  
7 18     18   2938369 use Data::Printer alias => 'pdump';
  18         44  
  18         187  
8 18     18   10327 use CLI::Driver::Deprecated;
  18         73  
  18         921  
9 18     18   10295 use CLI::Driver::Class;
  18         71  
  18         916  
10 18     18   10360 use CLI::Driver::Method;
  18         67  
  18         889  
11 18     18   10144 use CLI::Driver::Help;
  18         76  
  18         908  
12 18     18   11719 use Module::Load;
  18         24550  
  18         129  
13 18     18   1180 use File::Basename;
  18         43  
  18         2029  
14 18     18   8755 use YAML::Syck;
  18         40852  
  18         3344  
15              
16             with 'CLI::Driver::CommonRole';
17              
18             ###############################
19             ###### PUBLIC ATTRIBUTES ######
20             ###############################
21              
22             has href => (
23             is => 'rw',
24             isa => 'HashRef',
25             required => 1
26             );
27              
28             has name => ( is => 'rw', isa => 'Str' );
29             has desc => ( is => 'rw', isa => 'Str' );
30              
31             has deprecated => (
32             is => 'rw',
33             isa => 'CLI::Driver::Deprecated',
34             default => sub { CLI::Driver::Deprecated->new },
35             );
36              
37             # DEPRECATED in favor of 'deprecated'
38             has is_deprecated => (
39             is => 'rw',
40             isa => 'Bool',
41             default => 0,
42             );
43              
44             has class => ( is => 'rw', isa => 'CLI::Driver::Class' );
45             has 'method' => ( is => 'rw', isa => 'CLI::Driver::Method' );
46             has 'help' => ( is => 'rw', isa => 'CLI::Driver::Help' );
47             has 'use_argv_map' => ( is => 'rw', isa => 'Bool' );
48              
49             ##############################################################
50             # PUBLIC METHODS
51             ##############################################################
52              
53 18 50   18   24821 method parse {
  18     272   60  
  18         2670  
  272         672  
  272         381  
54              
55 272 50       685 $self->_handle_class or return 0;
56 272 50       735 $self->_handle_method or return 0;
57 272         913 $self->_handle_deprecation;
58 272         782 $self->_handle_desc;
59 272         797 $self->_handle_help;
60              
61 272         807 return 1;
62             }
63              
64 18 0   18   18024 method usage {
  18     0   46  
  18         15760  
  0         0  
  0         0  
65              
66 0         0 printf "\nusage: %s %s [opts] [-?] [--dump]\n\n", $0, $self->name;
67 0 0       0 printf "description: %s\n\n", $self->desc if $self->desc;
68              
69 0         0 my $help = $self->help;
70              
71 0         0 my @opts;
72 0         0 push @opts, @{ $self->class->attr };
  0         0  
73 0         0 push @opts, @{ $self->method->args };
  0         0  
74              
75             #
76             # handle required
77             #
78 0         0 my %opts;
79 0         0 foreach my $opt (@opts) {
80              
81 0 0       0 if ( $opt->required ) {
82 0         0 $opts{ $opt->cli_arg } = $opt;
83             }
84             }
85              
86 0         0 foreach my $arg ( sort { uc($a) cmp uc($b) } keys %opts ) {
  0         0  
87              
88 0         0 my $opt = $opts{$arg};
89 0         0 printf "\t%s\n", $opt->get_usage($arg);
90 0 0       0 printf "\t\t%s\n", $help->get_usage($arg) if $help->has_help($arg);
91             }
92              
93             #
94             # handle optional
95             #
96 0         0 %opts = ();
97 0         0 foreach my $opt (@opts) {
98              
99 0 0 0     0 if ( $opt->is_optional and !$opt->is_flag ) {
100 0         0 $opts{ $opt->cli_arg } = $opt;
101             }
102             }
103              
104 0         0 foreach my $arg ( sort { uc($a) cmp uc($b) } keys %opts ) {
  0         0  
105              
106 0         0 my $opt = $opts{$arg};
107 0         0 printf "\t[ %s ]\n", $opt->get_usage($arg);
108 0 0       0 printf "\t\t%s\n", $help->get_usage($arg) if $help->has_help($arg);
109             }
110              
111             #
112             # handle flags
113             #
114 0         0 %opts = ();
115 0         0 foreach my $opt (@opts) {
116              
117 0 0       0 if ( $opt->is_flag ) {
118 0         0 $opts{ $opt->cli_arg } = $opt;
119             }
120             }
121              
122 0         0 foreach my $arg ( sort { uc($a) cmp uc($b) } keys %opts ) {
  0         0  
123              
124 0         0 my $opt = $opts{$arg};
125 0         0 printf "\t[ %s ]\n", $opt->get_usage($arg);
126 0 0       0 printf "\t\t%s\n", $help->get_usage($arg) if $help->has_help($arg);
127             }
128              
129             #
130             # handle examples
131             #
132 0 0       0 if ( $help->has_examples ) {
133              
134 0         0 my $cmd = sprintf "%s %s", basename($0), $self->name;
135              
136 0         0 print "\n";
137 0         0 print "Examples:\n";
138 0         0 foreach my $eg ( @{ $help->examples } ) {
  0         0  
139 0         0 printf "\t%s %s\n", $cmd, $eg;
140             }
141             }
142              
143             #########################################################################
144              
145 0         0 print "\n";
146 0         0 exit 1;
147             }
148              
149 18 50   18   18993 method _new_class {
  18     31   41  
  18         5360  
  31         382  
  31         87  
150              
151 31         1057 my $class = $self->class;
152 31         786 my $class_name = $class->name;
153 31         184 my %attr = $class->get_signature;
154              
155 29         215 load $class_name;
156 29 100       721278 my $obj =
157             $class_name->new( %attr, use_argv_map => $self->use_argv_map ? 1 : 0 );
158              
159             #
160             # validate required class attributes were provided
161             #
162 29         19207 my @soft_req = $class->find_req_attrs( hard => 0, soft => 1 );
163              
164 29         89 foreach my $opt (@soft_req) {
165              
166 2         45 my $attr = $opt->method_arg;
167              
168 2 100       36 if ( !defined $obj->$attr ) {
169 1         257 confess "failed to determine $attr";
170             }
171             }
172              
173 28         152 return $obj;
174             }
175              
176 18 50   18   17228 method do {
  18     31   39  
  18         5169  
  31         21253  
  31         69  
177              
178             #
179             # this creates an instance of the user class defined in the yaml
180             #
181 31         143 my $obj = $self->_new_class;
182              
183             #
184             # prepare the method args from @ARGV or %ARGV
185             #
186 28         782 my $method = $self->method;
187 28         764 my $method_name = $method->name;
188 28         158 my %sig = $method->get_signature;
189              
190 25 100       675 if ( $self->use_argv_map ) {
191 1 50       7 if ( keys %ARGV ) {
192 0         0 my @argv = %ARGV;
193 0         0 $self->die("extra args detected: @argv");
194             }
195             }
196             else {
197 24 100       104 if (@ARGV) {
198 1         9 $self->die("extra args detected: @ARGV");
199             }
200             }
201              
202             #
203             # finally invoke the actual method
204             #
205 24         190 return $obj->$method_name(%sig);
206             }
207              
208 18 0   18   17800 method to_yaml {
  18     0   60  
  18         1907  
  0         0  
  0         0  
209              
210 0         0 $YAML::Syck::ImplicitTyping = 1;
211 0         0 $YAML::Syck::Headless = 1;
212 0         0 $YAML::Syck::SortKeys = 1;
213            
214 0         0 return YAML::Syck::Dump( $self->href );
215             }
216              
217             ##############################################################
218             # PRIVATE METHODS
219             ##############################################################
220              
221 18 50   18   20773 method _handle_deprecation {
  18     272   47  
  18         6908  
  272         658  
  272         387  
222              
223 272         6571 my $href = $self->href;
224              
225             #
226             # is_deprecated: <bool>
227             #
228 272         432 my $has_is_deprecated = 0;
229 272 50       674 if ( defined $href->{is_deprecated} ) {
230              
231 0         0 $has_is_deprecated = 1;
232 0         0 my $bool = $self->str_to_bool( $href->{is_deprecated} );
233 0         0 $self->is_deprecated($bool);
234             }
235              
236             #
237             # deprecated:
238             # status: <bool>
239             #
240 272         442 my $has_deprecated = 0;
241 272 100       634 if ( defined $href->{deprecated} ) {
242              
243 17         45 $has_deprecated = 1;
244 17         491 my $depr = $self->deprecated;
245 17 50       137 if ( !$depr->parse( href => $href->{deprecated} ) ) {
246 0         0 $self->warn(
247             sprintf( "%s: failed to parse 'deprecated' section",
248             $self->name )
249             );
250             }
251             }
252              
253             #
254             # sync them up
255             #
256 272 50 33     1171 if ( $has_is_deprecated and $has_deprecated ) {
    50          
    100          
257              
258             # these should match
259 0 0       0 if ( $self->is_deprecated != $self->deprecated->status ) {
260 0         0 $self->warn( sprintf( "%s: deprecation mismatch", $self->name ) );
261             }
262             }
263             elsif ($has_is_deprecated) {
264 0         0 $self->deprecated->status( $self->is_deprecated );
265             }
266             elsif ($has_deprecated) {
267 17         488 $self->is_deprecated( $self->deprecated->status );
268             }
269             }
270              
271 18 50   18   19241 method _handle_class {
  18     272   51  
  18         3907  
  272         592  
  272         401  
272              
273 272         6927 my $href = $self->href;
274              
275 272 50       730 if ( $href->{class} ) {
276              
277 272 100       6457 my $class = CLI::Driver::Class->new(
278             use_argv_map => $self->use_argv_map ? 1 : 0 );
279 272         1001 my $success = $class->parse( href => $href->{class} );
280 272 50       609 if ( !$success ) {
281 0         0 return 0;
282             }
283              
284 272         6873 $self->class($class);
285 272         802 return 1;
286             }
287              
288 0         0 return 0;
289             }
290              
291 18 50   18   19304 method _handle_method {
  18     272   42  
  18         3829  
  272         680  
  272         377  
292              
293 272         6247 my $href = $self->href;
294              
295 272 50       729 if ( $href->{method} ) {
296              
297 272 100       6250 my $method = CLI::Driver::Method->new(
298             use_argv_map => $self->use_argv_map ? 1 : 0 );
299 272         973 my $success = $method->parse( href => $href->{method} );
300 272 50       590 if ( !$success ) {
301 0         0 return 0;
302             }
303              
304 272         7009 $self->method($method);
305 272         743 return 1;
306             }
307              
308 0         0 return 0;
309             }
310              
311 18 50   18   18530 method _handle_desc {
  18     272   47  
  18         2300  
  272         620  
  272         398  
312              
313 272         6421 my $href = $self->href;
314              
315 272 100       725 if ( $href->{desc} ) {
316 255         5677 $self->desc( $href->{desc} );
317             }
318             }
319              
320 18 50   18   18517 method _handle_help {
  18     272   45  
  18         2424  
  272         651  
  272         414  
321              
322 272         6096 my $href = $self->href;
323              
324 272         6456 my $help = CLI::Driver::Help->new;
325 272         1464 $help->parse( href => $href->{help} );
326 272         7424 $self->help($help);
327             }
328              
329 18 0   18   19725 method _get_deprecated_msg {
  18     0   65  
  18         3899  
  0            
  0            
330              
331 0           my $msg = "DEPRECATED";
332 0 0         if ( $self->deprecated->replaced_by ) {
333 0           $msg .= " by " . $self->deprecated->replaced_by;
334             }
335              
336 0           return sprintf "(%s)", $msg;
337             }
338              
339             __PACKAGE__->meta->make_immutable;
340              
341             1;