File Coverage

blib/lib/Dist/Iller/Role/HasPlugins.pm
Criterion Covered Total %
statement 150 167 89.8
branch 74 104 71.1
condition 14 22 63.6
subroutine 25 26 96.1
pod 0 13 0.0
total 263 332 79.2


line stmt bran cond sub pod time code
1 2     2   1472 use 5.10.0;
  2         49  
2 2     2   11 use strict;
  2         5  
  2         48  
3 2     2   17 use warnings;
  2         6  
  2         135  
4              
5             package Dist::Iller::Role::HasPlugins;
6              
7             our $AUTHORITY = 'cpan:CSSON'; # AUTHORITY
8             # ABSTRACT: A role for DocTypes that contains plugins (like dist/weaver)
9             our $VERSION = '0.1409';
10              
11 2     2   15 use Moose::Role;
  2         4  
  2         15  
12 2     2   10689 use namespace::autoclean;
  2         6  
  2         13  
13 2     2   147 use Types::Standard qw/ArrayRef InstanceOf/;
  2         5  
  2         14  
14 2     2   1346 use PerlX::Maybe qw/maybe provided/;
  2         4  
  2         14  
15 2     2   135 use Safe::Isa qw/$_can/;
  2         6  
  2         245  
16 2     2   14 use List::Util qw/none/;
  2         4  
  2         124  
17 2     2   982 use Dist::Iller::Plugin;
  2         8  
  2         6015  
18              
19             # packages_for_plugin should return a CodeRef that in turn returns an ArrayRef of HashRefs, see ::DocType::Dist
20             requires qw/
21             packages_for_plugin
22             /;
23              
24             has plugins => (
25             is => 'rw',
26             isa => ArrayRef[InstanceOf['Dist::Iller::Plugin']],
27             traits => [qw/Array/],
28             default => sub { [] },
29             handles => {
30             add_plugin => 'push',
31             all_plugins => 'elements',
32             filter_plugins => 'grep',
33             find_plugin => 'first',
34             count_plugins => 'count',
35             has_plugins => 'count',
36             get_plugin => 'get',
37             map_plugins => 'map',
38             },
39             );
40              
41             around add_plugin => sub {
42             my $next = shift;
43             my $self = shift;
44             my $plugin_data = shift;
45             my $plugin = (InstanceOf['Dist::Iller::Plugin'])->check($plugin_data) ? $plugin_data : Dist::Iller::Plugin->new($plugin_data);
46              
47             if($self->find_plugin(sub { $_->plugin_name eq $plugin->plugin_name })) {
48             say "[Iller] ! Duplicate plugin found - skips [@{[ $plugin->plugin_name ]}]";
49             return;
50             }
51              
52             $self->$next($plugin);
53             };
54              
55             sub parse_plugins {
56 8     8 0 48 my $self = shift;
57 8         15 my $yaml = shift;
58              
59 8 50       22 return if !defined $yaml;
60              
61 8         19 foreach my $item (@$yaml) {
62 103 100       257 $self->parse_config($item) if exists $item->{'+config'}; # is in ::DocType
63 103 100       393 $self->parse_plugin($item) if exists $item->{'+plugin'};
64 103 100       350 $self->parse_remove($item) if exists $item->{'+remove_plugin'};
65 103 100       201 $self->parse_replace($item) if exists $item->{'+replace_plugin'};
66 103 100       210 $self->parse_extend($item) if exists $item->{'+extend_plugin'};
67 103 100       301 $self->parse_add($item) if exists $item->{'+add_plugin'};
68             }
69             }
70              
71             sub parse_plugin {
72 95     95 0 137 my $self = shift;
73 95         137 my $plugin = shift;
74              
75 95         199 my $plugin_name = delete $plugin->{'+plugin'};
76              
77 95 100       246 return if !$self->check_conditionals($plugin);
78              
79             $self->add_plugin({
80             plugin_name => $self->set_value_from_config($plugin_name),
81             maybe base => delete $plugin->{'+base'},
82             maybe in => delete $plugin->{'+in'},
83             maybe version => delete $plugin->{'+version'},
84             maybe documentation => delete $plugin->{'+documentation'},
85 94         317 maybe prereqs => delete $plugin->{'+prereqs'},
86             parameters => $self->set_values_from_config($plugin),
87             });
88             }
89              
90             sub parse_replace {
91 2     2 0 5 my $self = shift;
92 2         3 my $replacer = shift;
93              
94 2 50       6 return if !$self->check_conditionals($replacer);
95              
96 2         9 my $plugin_name = $self->set_value_from_config(delete $replacer->{'+replace_plugin'});
97 2         8 my $replace_with = $self->set_value_from_config(delete $replacer->{'+with'});
98              
99             my $plugin = Dist::Iller::Plugin->new(
100             plugin_name => $replace_with // $plugin_name,
101             maybe base => delete $replacer->{'+base'},
102             maybe in => delete $replacer->{'+in'},
103             maybe version => delete $replacer->{'+version'},
104 2   66     13 maybe documentation => delete $replacer->{'+documentation'},
105             parameters => $self->set_values_from_config($replacer),
106             );
107              
108 2         11 $self->insert_plugin($plugin_name, $plugin, after => 0, replace => 1);
109             }
110              
111             sub parse_extend {
112 1     1 0 3 my $self = shift;
113 1         2 my $extender = shift;
114              
115 1 50       4 return if !$self->check_conditionals($extender);
116              
117 1         3 my $plugin_name = delete $extender->{'+extend_plugin'};
118              
119 1         5 my $plugin = Dist::Iller::Plugin->new(
120             plugin_name => $self->set_value_from_config($plugin_name),
121             parameters => $self->set_values_from_config($extender),
122             );
123              
124 1         6 $self->extend_plugin($plugin_name, $plugin, remove => delete $extender->{'+remove'});
125             }
126              
127             sub parse_add {
128 2     2 0 4 my $self = shift;
129 2         5 my $adder = shift;
130              
131 2 50       5 return if !$self->check_conditionals($adder);
132              
133 2         7 my $plugin_name = delete $adder->{'+add_plugin'};
134              
135             my $plugin = Dist::Iller::Plugin->new(
136             plugin_name => $self->set_value_from_config($plugin_name),
137             maybe base => delete $adder->{'+base'},
138             maybe in => delete $adder->{'+in'},
139             maybe version => delete $adder->{'+version'},
140 2         8 maybe documentation => delete $adder->{'+documentation'},
141             parameters => $self->set_values_from_config($adder),
142             );
143              
144 2         6 my $after = delete $adder->{'+after'};
145 2         5 my $before = delete $adder->{'+before'};
146              
147 2 100       12 $self->insert_plugin(($after ? $after : $before), $plugin, after => ($after ? 1 : 0), replace => 0);
    100          
148             }
149              
150             sub parse_remove {
151 1     1 0 4 my $self = shift;
152 1         2 my $remover = shift;
153              
154 1 50       14 return if !$self->check_conditionals($remover);
155 0         0 $self->remove_plugin($self->set_value_from_config($remover->{'+remove_plugin'}));
156             }
157              
158             sub check_conditionals {
159 101     101 0 158 my $self = shift;
160 101         139 my $plugin_data = shift;
161              
162             my $get_type_what = sub {
163 6     6   10 my $from = shift;
164              
165 6 50       13 return () if !defined $from;
166 6 50       17 return () if !length $from;
167 6 50       36 return () if $from !~ m{[^.]\.[^.]};
168 6         32 return split /\./ => $from;
169 101         372 };
170              
171 101 100       336 if(exists $plugin_data->{'+if'}) {
    100          
    100          
172 1         5 my($type, $what) = $get_type_what->($plugin_data->{'+if'});
173 1 50       4 return 0 if !defined $type;
174 1 50 33     16 return 0 if $type eq '$env' && !exists $ENV{ uc $what };
175 0 0       0 return $ENV{ uc $what } if $type eq '$env';
176             }
177             elsif(exists $plugin_data->{'+remove_if'}) {
178 3         14 my($type, $what) = $get_type_what->($plugin_data->{'+remove_if'});
179              
180 3 50       10 return if !defined $type;
181              
182 3 50 66     112 if($type eq '$env') {
    100          
183 0 0       0 return 0 if !exists $ENV{ uc $what };
184 0         0 return !$ENV{ uc $what };
185             }
186             elsif($type eq '$self' && $self->has_config_obj) {
187 2 50       61 return 1 if !$self->config_obj->$_can($what);
188 2         106 return !$self->config_obj->$what;
189             }
190             }
191             elsif(exists $plugin_data->{'+add_if'}) {
192 2         9 my($type, $what) = $get_type_what->($plugin_data->{'+add_if'});
193 2 50       13 return if !defined $type;
194              
195 2 50 66     112 if($type eq '$env') {
    100          
196 0 0       0 return 0 if !exists $ENV{ uc $what };
197 0         0 return $ENV{ uc $what };
198             }
199             elsif($type eq '$self' && $self->has_config_obj) {
200 1 50       32 return 0 if !$self->config_obj->$_can($what);
201 1         45 return $self->config_obj->$what;
202             }
203             }
204              
205 97         399 return 1;
206             }
207              
208             sub insert_plugin {
209 4     4 0 8 my $self = shift;
210 4         7 my $plugin_name = shift;
211 4         8 my $new_plugin = shift;
212 4         14 my %settings = @_;
213              
214 4   100     16 my $after = $settings{'after'} || 0;
215 4   100     12 my $replace = $settings{'replace'} || 0;
216              
217 4         162 foreach my $index (0 .. $self->count_plugins - 1) {
218 38         1295 my $current_plugin = $self->get_plugin($index);
219              
220 38 100       1000 if($current_plugin->plugin_name eq $plugin_name) {
221 4         146 my @all_plugins = $self->all_plugins;
222 4 100       23 splice @all_plugins, ($after ? $index + 1 : $index), ($replace ? 1 : 0), $new_plugin;
    100          
223 4         127 $self->plugins(\@all_plugins);
224              
225 4 100       11 if($replace) {
226 2         63 say sprintf "[Iller] Replaced [%s] with [%s]", $current_plugin->plugin_name, $new_plugin->plugin_name;
227             }
228             else {
229 2 100       98 say sprintf "[Iller] Inserted [%s] %s [%s]", $new_plugin->plugin_name, ($after ? 'after' : 'before'), $current_plugin->plugin_name;
230             }
231 4         97 last;
232             }
233             }
234             }
235              
236             sub extend_plugin {
237 1     1 0 4 my $self = shift;
238 1         2 my $plugin_name = shift;
239 1         2 my $new_plugin = shift;
240 1         5 my %settings = @_;
241              
242 1         3 my $remove = $settings{'remove'};
243              
244 1 50       6 $remove = $remove ? ref $remove eq 'ARRAY' ? $remove
    50          
245             : [ $remove ]
246             : []
247             ;
248 1 50       44 say sprintf '[Iller] From %s remove %s', $plugin_name, join ', ' => @$remove if scalar @$remove;
249 1         16 say sprintf '[Iller] Extended [%s]', $plugin_name;
250              
251 1         50 foreach my $index (0 .. $self->count_plugins - 1) {
252 8         399 my $current_plugin = $self->get_plugin($index);
253              
254 8 100       219 if($current_plugin->plugin_name eq $plugin_name) {
255 1         7 foreach my $param_to_remove (@$remove) {
256 1         51 $current_plugin->delete_parameter($param_to_remove);
257             }
258 1         7 $current_plugin->merge_with($new_plugin);
259 1         33 last;
260             }
261             }
262             }
263              
264             sub remove_plugin {
265 0     0 0 0 my $self = shift;
266 0         0 my $remove_name = shift;
267              
268 0         0 foreach my $index (0 .. $self->count_plugins - 1) {
269 0         0 my $current_plugin = $self->get_plugin($index);
270              
271 0 0       0 if($current_plugin->plugin_name eq $remove_name) {
272 0         0 my @all_plugins = $self->all_plugins;
273 0         0 splice @all_plugins, $index, 1;
274 0         0 $self->plugins(\@all_plugins);
275 0         0 say "[Iller] Removed [$remove_name]";
276 0         0 last;
277             }
278             }
279             }
280              
281             sub set_values_from_config {
282 99     99 0 165 my $self = shift;
283 99         136 my $parameters = shift;
284              
285 99 100       3474 return $parameters if !$self->has_config_obj;
286              
287 32         121 foreach my $param (keys %$parameters) {
288 18 100       90 next if $param =~ m{^\+};
289 16 50       39 next if !defined $parameters->{ $param };
290              
291 16 100       63 $parameters->{ $param } = ref $parameters->{ $param } eq 'ARRAY' ? $parameters->{ $param } : [ $parameters->{ $param } ];
292              
293             VALUE:
294 16         26 foreach my $i (0 .. scalar @{ $parameters->{ $param } } - 1) {
  16         46  
295 16         38 $parameters->{ $param }[$i] = $self->set_value_from_config($parameters->{ $param }[$i]);
296             }
297             }
298 32         257 return $parameters;
299             }
300              
301             sub set_value_from_config {
302 117     117 0 193 my $self = shift;
303 117         172 my $value = shift;
304              
305 117 100       233 return $value if !defined $value;
306 116 100       577 return $value if $value !~ m{[^.]\.[^.]};
307 3         16 my($type, $what) = split /\./ => $value;
308 3 50   6   31 return $value if none { $_ eq $type } qw/$env $self/;
  6         17  
309              
310 3 50 33     108 if($type eq '$env' && exists $ENV{ uc $what }) {
    100 66        
311 0         0 return $ENV{ uc $what };
312             }
313             elsif($type eq '$self' && $self->config_obj->$_can($what)) {
314 2         89 return $self->config_obj->$what;
315             }
316 1         27 return $value;
317             }
318              
319              
320             sub plugins_to_hash {
321 2     2 0 6 my $self = shift;
322              
323             return [
324             $self->map_plugins(sub {
325 32     32   45 my $plugin = $_;
326 32         49 my $parameters = {};
327 32         1049 $parameters->{ $_->[0] } = $_->[1] for $plugin->parameters_kv;
328             +{
329             '+plugin' => $plugin->plugin_name,
330             provided $_->has_base, '+base' => $plugin->base,
331             '+in' => $plugin->in,
332             '+version' => $plugin->version,
333             provided $_->has_prereqs, '+prereqs' => $plugin->prereqs_to_array,
334             maybe '+documentation' => $plugin->documentation,
335 32         812 %{ $parameters },
  32         1270  
336             }
337             })
338 2         132 ];
339             }
340              
341             1;
342              
343             __END__
344              
345             =pod
346              
347             =encoding UTF-8
348              
349             =head1 NAME
350              
351             Dist::Iller::Role::HasPlugins - A role for DocTypes that contains plugins (like dist/weaver)
352              
353             =head1 VERSION
354              
355             Version 0.1409, released 2020-12-27.
356              
357             =head1 SOURCE
358              
359             L<https://github.com/Csson/p5-Dist-Iller>
360              
361             =head1 HOMEPAGE
362              
363             L<https://metacpan.org/release/Dist-Iller>
364              
365             =head1 AUTHOR
366              
367             Erik Carlsson <info@code301.com>
368              
369             =head1 COPYRIGHT AND LICENSE
370              
371             This software is copyright (c) 2016 by Erik Carlsson.
372              
373             This is free software; you can redistribute it and/or modify it under
374             the same terms as the Perl 5 programming language system itself.
375              
376             =cut