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   1445 use 5.14.0;
  2         9  
2 2     2   13 use strict;
  2         3  
  2         45  
3 2     2   10 use warnings;
  2         4  
  2         122  
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.1411';
10              
11 2     2   14 use Moose::Role;
  2         4  
  2         15  
12 2     2   10537 use namespace::autoclean;
  2         5  
  2         13  
13 2     2   129 use Types::Standard qw/ArrayRef InstanceOf/;
  2         5  
  2         16  
14 2     2   1448 use PerlX::Maybe qw/maybe provided/;
  2         6  
  2         15  
15 2     2   133 use Safe::Isa qw/$_can/;
  2         5  
  2         216  
16 2     2   15 use List::Util qw/none/;
  2         9  
  2         128  
17 2     2   1030 use Dist::Iller::Plugin;
  2         9  
  2         5552  
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 17 my $self = shift;
57 8         24 my $yaml = shift;
58              
59 8 50       24 return if !defined $yaml;
60              
61 8         24 foreach my $item (@$yaml) {
62 103 100       240 $self->parse_config($item) if exists $item->{'+config'}; # is in ::DocType
63 103 100       375 $self->parse_plugin($item) if exists $item->{'+plugin'};
64 103 100       349 $self->parse_remove($item) if exists $item->{'+remove_plugin'};
65 103 100       211 $self->parse_replace($item) if exists $item->{'+replace_plugin'};
66 103 100       204 $self->parse_extend($item) if exists $item->{'+extend_plugin'};
67 103 100       254 $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         125 my $plugin = shift;
74              
75 95         199 my $plugin_name = delete $plugin->{'+plugin'};
76              
77 95 100       247 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         268 maybe prereqs => delete $plugin->{'+prereqs'},
86             parameters => $self->set_values_from_config($plugin),
87             });
88             }
89              
90             sub parse_replace {
91 2     2 0 30 my $self = shift;
92 2         5 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         9 $self->insert_plugin($plugin_name, $plugin, after => 0, replace => 1);
109             }
110              
111             sub parse_extend {
112 1     1 0 2 my $self = shift;
113 1         3 my $extender = shift;
114              
115 1 50       2 return if !$self->check_conditionals($extender);
116              
117 1         4 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         8 $self->extend_plugin($plugin_name, $plugin, remove => delete $extender->{'+remove'});
125             }
126              
127             sub parse_add {
128 2     2 0 6 my $self = shift;
129 2         3 my $adder = shift;
130              
131 2 50       9 return if !$self->check_conditionals($adder);
132              
133 2         5 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         8 my $after = delete $adder->{'+after'};
145 2         5 my $before = delete $adder->{'+before'};
146              
147 2 100       15 $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       6 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 143 my $self = shift;
160 101         145 my $plugin_data = shift;
161              
162             my $get_type_what = sub {
163 6     6   11 my $from = shift;
164              
165 6 50       13 return () if !defined $from;
166 6 50       18 return () if !length $from;
167 6 50       32 return () if $from !~ m{[^.]\.[^.]};
168 6         32 return split /\./ => $from;
169 101         394 };
170              
171 101 100       346 if(exists $plugin_data->{'+if'}) {
    100          
    100          
172 1         5 my($type, $what) = $get_type_what->($plugin_data->{'+if'});
173 1 50       5 return 0 if !defined $type;
174 1 50 33     24 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         11 my($type, $what) = $get_type_what->($plugin_data->{'+remove_if'});
179              
180 3 50       10 return if !defined $type;
181              
182 3 50 66     128 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       55 return 1 if !$self->config_obj->$_can($what);
188 2         100 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       7 return if !defined $type;
194              
195 2 50 66     77 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       29 return 0 if !$self->config_obj->$_can($what);
201 1         42 return $self->config_obj->$what;
202             }
203             }
204              
205 97         383 return 1;
206             }
207              
208             sub insert_plugin {
209 4     4 0 7 my $self = shift;
210 4         8 my $plugin_name = shift;
211 4         6 my $new_plugin = shift;
212 4         14 my %settings = @_;
213              
214 4   100     16 my $after = $settings{'after'} || 0;
215 4   100     15 my $replace = $settings{'replace'} || 0;
216              
217 4         169 foreach my $index (0 .. $self->count_plugins - 1) {
218 38         1364 my $current_plugin = $self->get_plugin($index);
219              
220 38 100       973 if($current_plugin->plugin_name eq $plugin_name) {
221 4         144 my @all_plugins = $self->all_plugins;
222 4 100       17 splice @all_plugins, ($after ? $index + 1 : $index), ($replace ? 1 : 0), $new_plugin;
    100          
223 4         134 $self->plugins(\@all_plugins);
224              
225 4 100       11 if($replace) {
226 2         56 say sprintf "[Iller] Replaced [%s] with [%s]", $current_plugin->plugin_name, $new_plugin->plugin_name;
227             }
228             else {
229 2 100       59 say sprintf "[Iller] Inserted [%s] %s [%s]", $new_plugin->plugin_name, ($after ? 'after' : 'before'), $current_plugin->plugin_name;
230             }
231 4         99 last;
232             }
233             }
234             }
235              
236             sub extend_plugin {
237 1     1 0 3 my $self = shift;
238 1         2 my $plugin_name = shift;
239 1         3 my $new_plugin = shift;
240 1         4 my %settings = @_;
241              
242 1         3 my $remove = $settings{'remove'};
243              
244 1 50       18 $remove = $remove ? ref $remove eq 'ARRAY' ? $remove
    50          
245             : [ $remove ]
246             : []
247             ;
248 1 50       43 say sprintf '[Iller] From %s remove %s', $plugin_name, join ', ' => @$remove if scalar @$remove;
249 1         17 say sprintf '[Iller] Extended [%s]', $plugin_name;
250              
251 1         65 foreach my $index (0 .. $self->count_plugins - 1) {
252 8         275 my $current_plugin = $self->get_plugin($index);
253              
254 8 100       203 if($current_plugin->plugin_name eq $plugin_name) {
255 1         4 foreach my $param_to_remove (@$remove) {
256 1         41 $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 173 my $self = shift;
283 99         137 my $parameters = shift;
284              
285 99 100       3586 return $parameters if !$self->has_config_obj;
286              
287 32         115 foreach my $param (keys %$parameters) {
288 18 100       57 next if $param =~ m{^\+};
289 16 50       46 next if !defined $parameters->{ $param };
290              
291 16 100       58 $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         44  
295 16         41 $parameters->{ $param }[$i] = $self->set_value_from_config($parameters->{ $param }[$i]);
296             }
297             }
298 32         259 return $parameters;
299             }
300              
301             sub set_value_from_config {
302 117     117 0 174 my $self = shift;
303 117         187 my $value = shift;
304              
305 117 100       230 return $value if !defined $value;
306 116 100       629 return $value if $value !~ m{[^.]\.[^.]};
307 3         26 my($type, $what) = split /\./ => $value;
308 3 50   6   28 return $value if none { $_ eq $type } qw/$env $self/;
  6         23  
309              
310 3 50 33     115 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         110 return $self->config_obj->$what;
315             }
316 1         27 return $value;
317             }
318              
319              
320             sub plugins_to_hash {
321 2     2 0 5 my $self = shift;
322              
323             return [
324             $self->map_plugins(sub {
325 32     32   50 my $plugin = $_;
326 32         48 my $parameters = {};
327 32         1020 $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         825 %{ $parameters },
  32         1318  
336             }
337             })
338 2         88 ];
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.1411, released 2020-01-01.
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) 2021 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