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   143 use Modern::Perl;
  18         42  
  18         248  
4 18     18   3235 use Moose;
  18         38  
  18         177  
5 18     18   130285 use namespace::autoclean;
  18         46  
  18         194  
6 18     18   1707 use Kavorka '-all';
  18         42  
  18         159  
7 18     18   3251294 use Data::Printer alias => 'pdump';
  18         52  
  18         218  
8 18     18   11634 use CLI::Driver::Deprecated;
  18         80  
  18         911  
9 18     18   11635 use CLI::Driver::Class;
  18         77  
  18         942  
10 18     18   11555 use CLI::Driver::Method;
  18         77  
  18         947  
11 18     18   10924 use CLI::Driver::Help;
  18         74  
  18         957  
12 18     18   13022 use Module::Load;
  18         27557  
  18         152  
13 18     18   1446 use File::Basename;
  18         45  
  18         2247  
14 18     18   10125 use YAML::Syck;
  18         45967  
  18         3894  
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   28206 method parse {
  18     272   71  
  18         3078  
  272         748  
  272         475  
54              
55 272 50       763 $self->_handle_class or return 0;
56 272 50       823 $self->_handle_method or return 0;
57 272         974 $self->_handle_deprecation;
58 272         874 $self->_handle_desc;
59 272         886 $self->_handle_help;
60              
61 272         917 return 1;
62             }
63              
64 18 0   18   20051 method usage {
  18     0   58  
  18         17722  
  0         0  
  0         0  
65              
66 0         0 printf "\nusage: %s %s [opts] [-?]\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   22385 method _new_class {
  18     31   48  
  18         6105  
  31         418  
  31         73  
150              
151 31         1099 my $class = $self->class;
152 31         817 my $class_name = $class->name;
153 31         165 my %attr = $class->get_signature;
154              
155 29         233 load $class_name;
156 29 100       792077 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         19237 my @soft_req = $class->find_req_attrs( hard => 0, soft => 1 );
163              
164 29         91 foreach my $opt (@soft_req) {
165              
166 2         55 my $attr = $opt->method_arg;
167              
168 2 100       41 if ( !defined $obj->$attr ) {
169 1         283 confess "failed to determine $attr";
170             }
171             }
172              
173 28         163 return $obj;
174             }
175              
176 18 50   18   19377 method do {
  18     31   49  
  18         5785  
  31         20321  
  31         78  
177              
178             #
179             # this creates an instance of the user class defined in the yaml
180             #
181 31         129 my $obj = $self->_new_class;
182              
183             #
184             # prepare the method args from @ARGV or %ARGV
185             #
186 28         876 my $method = $self->method;
187 28         780 my $method_name = $method->name;
188 28         154 my %sig = $method->get_signature;
189              
190 25 100       770 if ( $self->use_argv_map ) {
191 1 50       6 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       96 if (@ARGV) {
198 1         10 $self->die("extra args detected: @ARGV");
199             }
200             }
201              
202             #
203             # finally invoke the actual method
204             #
205 24         183 return $obj->$method_name(%sig);
206             }
207              
208 18 0   18   19769 method to_yaml {
  18     0   46  
  18         2158  
  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   22302 method _handle_deprecation {
  18     272   53  
  18         8067  
  272         740  
  272         424  
222              
223 272         6751 my $href = $self->href;
224              
225             #
226             # is_deprecated: <bool>
227             #
228 272         487 my $has_is_deprecated = 0;
229 272 50       716 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         426 my $has_deprecated = 0;
241 272 100       650 if ( defined $href->{deprecated} ) {
242              
243 17         55 $has_deprecated = 1;
244 17         571 my $depr = $self->deprecated;
245 17 50       141 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     1196 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         566 $self->is_deprecated( $self->deprecated->status );
268             }
269             }
270              
271 18 50   18   21012 method _handle_class {
  18     272   67  
  18         4416  
  272         633  
  272         384  
272              
273 272         7584 my $href = $self->href;
274              
275 272 50       795 if ( $href->{class} ) {
276              
277 272 100       6870 my $class = CLI::Driver::Class->new(
278             use_argv_map => $self->use_argv_map ? 1 : 0 );
279 272         1055 my $success = $class->parse( href => $href->{class} );
280 272 50       638 if ( !$success ) {
281 0         0 return 0;
282             }
283              
284 272         7537 $self->class($class);
285 272         860 return 1;
286             }
287              
288 0         0 return 0;
289             }
290              
291 18 50   18   21036 method _handle_method {
  18     272   51  
  18         4224  
  272         783  
  272         470  
292              
293 272         6750 my $href = $self->href;
294              
295 272 50       798 if ( $href->{method} ) {
296              
297 272 100       6736 my $method = CLI::Driver::Method->new(
298             use_argv_map => $self->use_argv_map ? 1 : 0 );
299 272         1055 my $success = $method->parse( href => $href->{method} );
300 272 50       710 if ( !$success ) {
301 0         0 return 0;
302             }
303              
304 272         7771 $self->method($method);
305 272         801 return 1;
306             }
307              
308 0         0 return 0;
309             }
310              
311 18 50   18   20286 method _handle_desc {
  18     272   46  
  18         2537  
  272         641  
  272         387  
312              
313 272         6587 my $href = $self->href;
314              
315 272 100       829 if ( $href->{desc} ) {
316 255         6397 $self->desc( $href->{desc} );
317             }
318             }
319              
320 18 50   18   20719 method _handle_help {
  18     272   50  
  18         2615  
  272         686  
  272         403  
321              
322 272         6703 my $href = $self->href;
323              
324 272         6934 my $help = CLI::Driver::Help->new;
325 272         1541 $help->parse( href => $href->{help} );
326 272         7986 $self->help($help);
327             }
328              
329 18 0   18   21632 method _get_deprecated_msg {
  18     0   63  
  18         4571  
  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;