File Coverage

blib/lib/MooX/Cmd/Role.pm
Criterion Covered Total %
statement 106 107 99.0
branch 36 42 85.7
condition n/a
subroutine 25 26 96.1
pod 2 2 100.0
total 169 177 95.4


line stmt bran cond sub pod time code
1             package MooX::Cmd::Role;
2             # ABSTRACT: MooX cli app commands do this
3             our $VERSION = '1.000';
4 6     6   52606 use strict;
  6         13  
  6         274  
5 6     6   34 use warnings;
  6         12  
  6         327  
6              
7 6     6   39 use Moo::Role;
  6         13  
  6         62  
8              
9 6     6   3806 use Carp;
  6         26  
  6         643  
10 6     6   82 use Module::Runtime qw/ use_module /;
  6         15  
  6         79  
11 6     6   4711 use Regexp::Common;
  6         27848  
  6         29  
12 6     6   1275542 use Text::ParseWords 'shellwords';
  6         15033  
  6         650  
13 6     6   2580 use Module::Pluggable::Object;
  6         37106  
  6         444  
14              
15 6     6   2743 use List::MoreUtils qw/first_index first_result/;
  6         78765  
  6         90  
16 6     6   8630 use Scalar::Util qw/blessed/;
  6         18  
  6         525  
17 6     6   3750 use Params::Util qw/_ARRAY/;
  6         30248  
  6         14702  
18              
19              
20             has 'command_args' => (is => "ro");
21              
22              
23             has 'command_chain' => (is => "ro");
24              
25              
26             has 'command_chain_end' => (is => "lazy");
27              
28 22     22   802 sub _build_command_chain_end { $_[0]->command_chain->[-1] }
29              
30              
31             has 'command_name' => (is => "ro");
32              
33              
34             has 'command_commands' => (is => "lazy");
35              
36             sub _build_command_commands
37             {
38 44     44   202 my ($class, $params) = @_;
39 44 100       484 defined $params->{command_base} or $params->{command_base} = $class->_build_command_base($params);
40 44         192 my $base = $params->{command_base};
41              
42             # I have no clue why 'only' and 'except' seems to not fulfill what I need or are bugged in M::P - Getty
43             my @cmd_plugins = grep {
44 44         1581 my $plug_class = _mkcommand($_, $base);
  63         146538  
45 63         280 index($plug_class, ":") == -1;
46             } Module::Pluggable::Object->new(
47             search_path => $base,
48             require => 0,
49             )->plugins;
50              
51 44         6118 my %cmds = map { _mkcommand($_, $base) => $_ } @cmd_plugins;
  55         170  
52 44 50       235 scalar keys %cmds == scalar @cmd_plugins
53             or croak "Can't compute unambiguous list of commands from '" . join("', '", @cmd_plugins) . "'";
54              
55 44         341 \%cmds;
56             }
57              
58              
59             has command_base => (is => "lazy");
60              
61 42     42   344 sub _build_command_base { $_[0] . '::Cmd'; }
62              
63              
64             has command_execute_method_name => (is => "lazy");
65              
66 17     17   146 sub _build_command_execute_method_name { "execute" }
67              
68              
69             has command_execute_return_method_name => (is => "lazy");
70              
71 29     29   894 sub _build_command_execute_return_method_name { "execute_return" }
72              
73              
74             has command_creation_method_name => (is => "lazy");
75              
76 2     2   10 sub _build_command_creation_method_name { "new_with_cmd" }
77              
78              
79             has command_creation_chain_methods => (is => "lazy");
80              
81 39     39   227 sub _build_command_creation_chain_methods { ['new_with_options', 'new'] }
82              
83              
84             has command_execute_from_new => (is => "lazy");
85              
86 0     0   0 sub _build_command_execute_from_new { 0 }
87              
88              
89 2     2 1 12 sub new_with_cmd { goto &_initialize_from_cmd; }
90              
91             sub _mkcommand
92             {
93 141     141   512 my ($package, $base) = @_;
94 141         289 my $bwc = "${base}::";
95 141         284 my $len_bwc = length($bwc);
96 141 50       560 index($package, $bwc) == 0 and substr($package, 0, $len_bwc, "");
97 141         708 lc($package);
98             }
99              
100             my @private_init_params =
101             qw(command_base command_execute_method_name command_execute_return_method_name command_creation_chain_methods command_execute_method_name);
102              
103             my $required_method = sub {
104             my ($tgt, $method) = @_;
105             $tgt->can($method) or croak("You need an '$method' in " . (blessed $tgt || $tgt));
106             };
107              
108             my $call_required_method = sub {
109             my ($tgt, $method, @args) = @_;
110             my $m = $required_method->($tgt, $method);
111             return $m->($tgt, @args);
112             };
113              
114             my $call_optional_method = sub {
115             my ($tgt, $method, @args) = @_;
116             my $m = $tgt->can($method) or return;
117             return $m->($tgt, @args);
118             };
119              
120             my $call_indirect_method = sub {
121             my ($tgt, $name_getter, @args) = @_;
122             my $g = $call_required_method->($tgt, $name_getter);
123             my $m = $required_method->($tgt, $g);
124             return $m->($tgt, @args);
125             };
126              
127             ## no critic qw(ProhibitExcessComplexity)
128             sub _initialize_from_cmd
129             {
130 45     45   395 my ($class, %params) = @_;
131              
132 45         622 my @args = shellwords(join ' ', map { quotemeta } @ARGV);
  34         835  
133              
134 45         8933 my (@used_args, $cmd, $cmd_name, $cmd_name_index);
135              
136 45         266 my %cmd_create_params = %params;
137 45         334 delete @cmd_create_params{qw(command_commands), @private_init_params};
138              
139 45 100       1331 defined $params{command_commands} or $params{command_commands} = $class->_build_command_commands(\%params);
140 45 100   26   946 if (($cmd_name_index = first_index { $cmd = $params{command_commands}->{$_} } @args) >= 0)
  26         239  
141             {
142 23         104 @used_args = splice @args, 0, $cmd_name_index;
143 23         3030 shift @args; # be careful about relics
144 23         178 $cmd_name = _mkcommand($cmd, $params{command_base});
145              
146 23         380 use_module($cmd);
147             defined $cmd_create_params{command_execute_method_name}
148             or $cmd_create_params{command_execute_method_name} =
149 23 50       39997 $call_optional_method->($cmd, "_build_command_execute_method_name", \%cmd_create_params);
150             defined $cmd_create_params{command_execute_method_name}
151 23 100       240 or $cmd_create_params{command_execute_method_name} = "execute";
152 23         193 $required_method->($cmd, $cmd_create_params{command_execute_method_name});
153             }
154             else
155             {
156 22         73 @used_args = @args;
157 22         49 @args = ();
158             }
159              
160             defined $params{command_creation_chain_methods}
161 44 100       581 or $params{command_creation_chain_methods} = $class->_build_command_creation_chain_methods(\%params);
162             my @creation_chain =
163             _ARRAY($params{command_creation_chain_methods})
164 39         184 ? @{$params{command_creation_chain_methods}}
165 44 100       401 : ($params{command_creation_chain_methods});
166 44 100   83   501 (my $creation_method = first_result { defined $_ and $class->can($_) } @creation_chain)
  83 100       1920  
167             or croak "Can't find a creation method on $class";
168              
169             ## no critic qw(RequireLocalizedPunctuationVars)
170 41         219 @ARGV = @used_args;
171 41         148 $params{command_args} = [@args];
172 41         158 $params{command_name} = $cmd_name;
173 41 100       218 defined $params{command_chain} or $params{command_chain} = [];
174 41         1392 my $self = $creation_method->($class, %params);
175 41         363295 push @{$self->command_chain}, $self;
  41         299  
176              
177 41 100       158 if ($cmd)
178             {
179 22         72 @ARGV = @args;
180 22         63 my ($creation_method, $creation_method_name, $cmd_plugin);
181 22 100       711 $cmd->can("_build_command_creation_method_name")
182             and $creation_method_name = $cmd->_build_command_creation_method_name(\%params);
183 22 100       161 $creation_method_name and $creation_method = $cmd->can($creation_method_name);
184 22 100       101 if ($creation_method)
185             {
186 16         73 @cmd_create_params{qw(command_chain)} = @$self{qw(command_chain)};
187 16         84 $cmd_plugin = $creation_method->($cmd, %cmd_create_params);
188             $self->{$self->command_execute_return_method_name} =
189 14         43 [@{$call_indirect_method->($cmd_plugin, "command_execute_return_method_name")}];
  14         48  
190             }
191             else
192             {
193 6 50   12   91 ($creation_method = first_result { defined $_ and $cmd->can($_) } @creation_chain)
  12 50       197  
194             or croak "Can't find a creation method on " . $cmd;
195 6         87 $cmd_plugin = $creation_method->($cmd);
196 6         1616 push @{$self->command_chain}, $cmd_plugin;
  6         41  
197              
198 6         37 my $cemn = $cmd_plugin->can("command_execute_method_name");
199 6 50       298 my $exec_fun = $cemn ? $cemn->() : $self->command_execute_method_name();
200             $self->command_execute_from_new
201 6 100       485 and $self->{$self->command_execute_return_method_name} =
202             [$call_required_method->($cmd_plugin, $exec_fun, \@ARGV, $self->command_chain)];
203             }
204             }
205             else
206             {
207             $self->command_execute_from_new
208 19 100       621 and $self->{$self->command_execute_return_method_name} =
209             [$call_indirect_method->($self, "command_execute_method_name", \@ARGV, $self->command_chain)];
210             }
211              
212 39         657 return $self;
213             }
214              
215              
216             # XXX should be an r/w attribute - can be renamed on loading ...
217 38     38 1 488 sub execute_return { $_[0]->{execute_return} }
218              
219             1;
220              
221             __END__