File Coverage

blib/lib/CLI/Driver/Action.pm
Criterion Covered Total %
statement 142 212 66.9
branch 37 82 45.1
condition 1 6 16.6
subroutine 31 34 91.1
pod n/a
total 211 334 63.1


line stmt bran cond sub pod time code
1             package CLI::Driver::Action;
2              
3 18     18   157 use Modern::Perl;
  18         43  
  18         207  
4 18     18   3321 use Moose;
  18         46  
  18         164  
5 18     18   134033 use namespace::autoclean;
  18         52  
  18         206  
6 18     18   1734 use Kavorka '-all';
  18         47  
  18         146  
7 18     18   3299965 use Data::Printer alias => 'pdump';
  18         46  
  18         218  
8 18     18   12061 use CLI::Driver::Deprecated;
  18         81  
  18         966  
9 18     18   11776 use CLI::Driver::Class;
  18         93  
  18         1393  
10 18     18   11784 use CLI::Driver::Method;
  18         75  
  18         977  
11 18     18   11427 use CLI::Driver::Help;
  18         83  
  18         976  
12 18     18   13704 use Module::Load;
  18         28478  
  18         167  
13 18     18   1526 use File::Basename;
  18         48  
  18         2682  
14 18     18   11305 use YAML::Syck;
  18         49347  
  18         4136  
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   29683 method parse {
  18     272   65  
  18         3248  
  272         721  
  272         401  
54            
55 272 50       720 $self->_handle_class or return 0;
56 272 50       796 $self->_handle_method or return 0;
57 272         1058 $self->_handle_deprecation;
58 272         838 $self->_handle_desc;
59 272         897 $self->_handle_help;
60              
61 272         906 return 1;
62             }
63              
64 18 0   18   21535 method usage {
  18     0   70  
  18         19003  
  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   22439 method _new_class {
  18     31   52  
  18         6329  
  31         374  
  31         73  
150              
151 31         1184 my $class = $self->class;
152 31         856 my $class_name = $class->name;
153 31         170 my %attr = $class->get_signature;
154              
155 29         197 load $class_name;
156 29 100       794411 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         20439 my @soft_req = $class->find_req_attrs( hard => 0, soft => 1 );
163              
164 29         89 foreach my $opt (@soft_req) {
165              
166 2         53 my $attr = $opt->method_arg;
167              
168 2 100       40 if ( !defined $obj->$attr ) {
169 1         266 confess "failed to determine $attr";
170             }
171             }
172              
173 28         148 return $obj;
174             }
175              
176 18 50   18   19562 method do {
  18     31   53  
  18         6013  
  31         22250  
  31         77  
177              
178             #
179             # this creates an instance of the user class defined in the yaml
180             #
181 31         139 my $obj = $self->_new_class;
182              
183             #
184             # prepare the method args from @ARGV or %ARGV
185             #
186 28         812 my $method = $self->method;
187 28         849 my $method_name = $method->name;
188 28         168 my %sig = $method->get_signature;
189              
190 25 100       762 if ( $self->use_argv_map ) {
191 1 50       8 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       108 if (@ARGV) {
198 1         9 $self->die("extra args detected: @ARGV");
199             }
200             }
201              
202             #
203             # finally invoke the actual method
204             #
205 24         174 return $obj->$method_name(%sig);
206             }
207              
208 18 0   18   20343 method to_yaml {
  18     0   52  
  18         2110  
  0         0  
  0         0  
209              
210 0         0 $YAML::Syck::Headless = 1;
211 0         0 $YAML::Syck::SortKeys = 1;
212            
213 0         0 return YAML::Syck::Dump( $self->href );
214             }
215              
216             ##############################################################
217             # PRIVATE METHODS
218             ##############################################################
219              
220 18 50   18   22930 method _handle_deprecation {
  18     272   51  
  18         7982  
  272         713  
  272         406  
221              
222 272         6913 my $href = $self->href;
223              
224             #
225             # is_deprecated: <bool>
226             #
227 272         487 my $has_is_deprecated = 0;
228 272 50       772 if ( defined $href->{is_deprecated} ) {
229              
230 0         0 $has_is_deprecated = 1;
231 0         0 my $bool = $self->str_to_bool( $href->{is_deprecated} );
232 0         0 $self->is_deprecated($bool);
233             }
234              
235             #
236             # deprecated:
237             # status: <bool>
238             #
239 272         443 my $has_deprecated = 0;
240 272 100       691 if ( defined $href->{deprecated} ) {
241              
242 17         48 $has_deprecated = 1;
243 17         513 my $depr = $self->deprecated;
244 17 50       156 if ( !$depr->parse( href => $href->{deprecated} ) ) {
245 0         0 $self->warn(
246             sprintf( "%s: failed to parse 'deprecated' section",
247             $self->name )
248             );
249             }
250             }
251              
252             #
253             # sync them up
254             #
255 272 50 33     1333 if ( $has_is_deprecated and $has_deprecated ) {
    50          
    100          
256              
257             # these should match
258 0 0       0 if ( $self->is_deprecated != $self->deprecated->status ) {
259 0         0 $self->warn( sprintf( "%s: deprecation mismatch", $self->name ) );
260             }
261             }
262             elsif ($has_is_deprecated) {
263 0         0 $self->deprecated->status( $self->is_deprecated );
264             }
265             elsif ($has_deprecated) {
266 17         591 $self->is_deprecated( $self->deprecated->status );
267             }
268             }
269              
270 18 50   18   21046 method _handle_class {
  18     272   74  
  18         4496  
  272         592  
  272         396  
271              
272 272         7859 my $href = $self->href;
273              
274 272 50       763 if ( $href->{class} ) {
275              
276 272 100       7260 my $class = CLI::Driver::Class->new(
277             use_argv_map => $self->use_argv_map ? 1 : 0 );
278 272         1045 my $success = $class->parse( href => $href->{class} );
279 272 50       656 if ( !$success ) {
280 0         0 return 0;
281             }
282              
283 272         7912 $self->class($class);
284 272         885 return 1;
285             }
286              
287 0         0 return 0;
288             }
289              
290 18 50   18   22103 method _handle_method {
  18     272   52  
  18         4267  
  272         892  
  272         433  
291              
292 272         7162 my $href = $self->href;
293              
294 272 50       769 if ( $href->{method} ) {
295              
296 272 100       7157 my $method = CLI::Driver::Method->new(
297             use_argv_map => $self->use_argv_map ? 1 : 0 );
298 272         1120 my $success = $method->parse( href => $href->{method} );
299 272 50       715 if ( !$success ) {
300 0         0 return 0;
301             }
302              
303 272         7948 $self->method($method);
304 272         845 return 1;
305             }
306              
307 0         0 return 0;
308             }
309              
310 18 50   18   20900 method _handle_desc {
  18     272   51  
  18         2611  
  272         689  
  272         399  
311              
312 272         6807 my $href = $self->href;
313              
314 272 100       745 if ( $href->{desc} ) {
315 255         6296 $self->desc( $href->{desc} );
316             }
317             }
318              
319 18 50   18   21209 method _handle_help {
  18     272   48  
  18         2812  
  272         741  
  272         399  
320              
321 272         7058 my $href = $self->href;
322              
323 272         7069 my $help = CLI::Driver::Help->new;
324 272         1554 $help->parse( href => $href->{help} );
325 272         8262 $self->help($help);
326             }
327              
328 18 0   18   22170 method _get_deprecated_msg {
  18     0   89  
  18         4441  
  0            
  0            
329              
330 0           my $msg = "DEPRECATED";
331 0 0         if ( $self->deprecated->replaced_by ) {
332 0           $msg .= " by " . $self->deprecated->replaced_by;
333             }
334              
335 0           return sprintf "(%s)", $msg;
336             }
337              
338             __PACKAGE__->meta->make_immutable;
339              
340             1;