File Coverage

blib/lib/Dist/Zilla/Plugin/Prereqs/MatchInstalled.pm
Criterion Covered Total %
statement 76 80 95.0
branch 11 18 61.1
condition 1 2 50.0
subroutine 16 16 100.0
pod 4 4 100.0
total 108 120 90.0


line stmt bran cond sub pod time code
1 2     2   2454739 use 5.008; # 8 = utf8, 6 = pragmas , our, noparam varmethod, 4 = __PACKAGE__
  2         5  
2 2     2   8 use strict;
  2         1  
  2         36  
3 2     2   14 use warnings;
  2         3  
  2         53  
4 2     2   523 use utf8;
  2         10  
  2         12  
5              
6             package Dist::Zilla::Plugin::Prereqs::MatchInstalled;
7              
8             our $VERSION = '1.001003';
9              
10             # ABSTRACT: Depend on versions of modules the same as you have installed
11              
12             our $AUTHORITY = 'cpan:KENTNL'; # AUTHORITY
13              
14 2     2   628 use Moose qw( has around with );
  2         299833  
  2         13  
15 2     2   8150 use MooseX::Types::Moose qw( HashRef ArrayRef Str );
  2         38740  
  2         18  
16 2     2   7605 use Dist::Zilla::Util::ConfigDumper qw( config_dumper );
  2         1650  
  2         7  
17             with 'Dist::Zilla::Role::PrereqSource';
18              
19              
20              
21              
22              
23              
24              
25              
26              
27              
28              
29              
30              
31              
32              
33              
34              
35              
36              
37              
38              
39              
40              
41              
42              
43              
44             has applyto_phase => (
45             is => ro =>,
46             isa => ArrayRef [Str] =>,
47             lazy => 1,
48             default => sub { [qw(build test runtime configure develop)] },
49             );
50              
51              
52              
53              
54              
55              
56              
57              
58              
59              
60              
61              
62              
63              
64             has applyto_relation => (
65             is => 'ro',
66             isa => ArrayRef [Str],
67             lazy => 1,
68             default => sub { [qw(requires recommends suggests)] },
69             );
70              
71              
72              
73              
74              
75              
76              
77              
78              
79              
80              
81              
82              
83             has applyto => (
84             is => ro =>,
85             isa => ArrayRef [Str] =>,
86             lazy => 1,
87             builder => _build_applyto =>,
88             );
89              
90              
91              
92              
93              
94              
95              
96              
97              
98             has _applyto_list => (
99             is => ro =>,
100             isa => ArrayRef [ ArrayRef [Str] ],
101             lazy => 1,
102             builder => _build__applyto_list =>,
103             );
104              
105              
106              
107              
108              
109              
110              
111              
112              
113              
114              
115              
116              
117              
118              
119             has modules => (
120             is => ro =>,
121             isa => ArrayRef [Str],
122             lazy => 1,
123             default => sub { [] },
124             );
125              
126              
127              
128              
129              
130              
131              
132             has _modules_hash => (
133             is => ro =>,
134             isa => HashRef,
135             lazy => 1,
136             builder => _build__modules_hash =>,
137             );
138              
139              
140              
141              
142              
143             sub _build_applyto {
144 1     1   1 my $self = shift;
145 1         2 my @out;
146 1         4 for my $phase ( @{ $self->applyto_phase } ) {
  1         35  
147 5         3 for my $relation ( @{ $self->applyto_relation } ) {
  5         162  
148 15         22 push @out, $phase . q[.] . $relation;
149             }
150             }
151 1         30 return \@out;
152             }
153              
154              
155              
156              
157              
158             sub _build__applyto_list {
159 1     1   1 my $self = shift;
160 1         1 my @out;
161 1         2 for my $type ( @{ $self->applyto } ) {
  1         34  
162 15 50       33 if ( $type =~ /^ ([^.]+) [.] ([^.]+) $/msx ) {
163 15         26 push @out, [ "$1", "$2" ];
164 15         17 next;
165             }
166 0         0 return $self->log_fatal( [ q[<<%s>> does not match << <phase>.<relation> >>], $type ] );
167             }
168 1         34 return \@out;
169             }
170              
171              
172              
173              
174              
175             sub _build__modules_hash {
176 1     1   1 my $self = shift;
177 1         2 return { map { ( $_, 1 ) } @{ $self->modules } };
  1         33  
  1         33  
178             }
179              
180              
181              
182              
183              
184             sub _user_wants_upgrade_on {
185 1     1   2 my ( $self, $module ) = @_;
186 1         41 return exists $self->_modules_hash->{$module};
187             }
188              
189              
190              
191              
192              
193              
194              
195              
196              
197              
198              
199              
200              
201              
202              
203              
204              
205              
206              
207 1     1 1 164 sub mvp_multivalue_args { return qw(applyto applyto_relation applyto_phase modules) }
208              
209              
210              
211              
212              
213              
214              
215 1     1 1 120 sub mvp_aliases { return { 'module' => 'modules' } }
216              
217              
218              
219              
220              
221              
222              
223              
224              
225              
226              
227             sub current_version_of {
228 1     1 1 6 my ( undef, $package ) = @_;
229 1 50       6 if ( 'perl' eq $package ) {
230              
231             # Thats not going to work, Dave.
232 0         0 return $];
233             }
234 1         450 require Module::Data;
235 1         4192 my $module_data = Module::Data->new($package);
236 1 50       1073 return if not $module_data;
237 1 50       4 return if not -e $module_data->path;
238 1 50       7335 return if -d $module_data->path;
239 1         44 return $module_data->_version_emulate;
240             }
241             around dump_config => config_dumper( __PACKAGE__, qw( applyto_phase applyto_relation applyto modules ) );
242              
243              
244              
245              
246              
247              
248              
249              
250             sub register_prereqs {
251 1     1 1 77520 my ($self) = @_;
252 1         30 my $zilla = $self->zilla;
253 1         23 my $prereqs = $zilla->prereqs;
254 1   50     25 my $guts = $prereqs->cpan_meta_prereqs->{prereqs} || {};
255              
256 1         8 my $failmsg = q[];
257 1         3 $failmsg .= q[You asked for the installed version of %s, ];
258 1         2 $failmsg .= q[and it is a dependency but it is apparently not installed];
259 1         1 for my $applyto ( @{ $self->_applyto_list } ) {
  1         34  
260 15         317 my ( $phase, $rel ) = @{$applyto};
  15         19  
261 15 100       27 next if not exists $guts->{$phase};
262 3 100       8 next if not exists $guts->{$phase}->{$rel};
263 1         5 my $reqs = $guts->{$phase}->{$rel}->as_string_hash;
264 1         59 for my $module ( keys %{$reqs} ) {
  1         3  
265 1 50       3 next unless $self->_user_wants_upgrade_on($module);
266 1         4 my $latest = $self->current_version_of($module);
267 1 50       11363 if ( not defined $latest ) {
268 0         0 $self->log( [ $failmsg, $module ] );
269 0         0 next;
270             }
271 1         52 $zilla->register_prereqs( { phase => $phase, type => $rel }, $module, $latest );
272             }
273             }
274 1         4 return $prereqs;
275             }
276             __PACKAGE__->meta->make_immutable;
277 2     2   1363 no Moose;
  2         4  
  2         11  
278              
279             1;
280              
281             __END__
282              
283             =pod
284              
285             =encoding UTF-8
286              
287             =head1 NAME
288              
289             Dist::Zilla::Plugin::Prereqs::MatchInstalled - Depend on versions of modules the same as you have installed
290              
291             =head1 VERSION
292              
293             version 1.001003
294              
295             =head1 SYNOPSIS
296              
297             This is based on the code of
298             L<< C<[Author::KENTNL::Prereqs::Latest::Selective]>|Dist::Zilla::Plugin::Author::KENTNL::Prereqs::Latest::Selective >>,
299             but intended for a wider audience.
300              
301             [Prereqs::MatchInstalled]
302             module = My::Module
303              
304             If you want to automatically add B<all> modules that are C<prereqs>, perhaps instead look at
305             L<< C<[Prereqs::MatchInstalled::All]>|Dist::Zilla::Plugin::Prereqs::MatchInstalled::All >>
306              
307             B<NOTE:> Dependencies will only be upgraded to match the I<Installed> version if they're found elsewhere in the dependency tree.
308              
309             This is designed so that it integrates with other automated version provisioning.
310              
311             If you're hard-coding module dependencies instead, you will want to place this module I<after> other modules that declare
312             dependencies.
313              
314             For instance:
315              
316             [Prereqs]
317             Foo = 0
318              
319             [Prereqs::MatchInstalled]
320             module = Foo
321              
322             ^^ C<Foo> will be upgraded to the version installed.
323              
324             By default, dependencies that match values of C<module> will be upgraded when they are found in:
325              
326             phase: build, test, runtime, configure, develop
327             relation: depends, suggests, recommends
328              
329             To change this behavior, specify one or more of the following parameters:
330              
331             applyto_phase = build
332             applyto_phase = configure
333              
334             applyto_relation = requires
335              
336             etc.
337              
338             For more complex demands, this also works:
339              
340             applyto = build.requires
341             applyto = configure.recommends
342              
343             And that should hopefully be sufficient to cover any conceivable use-case.
344              
345             Also note, we don't do any sort of sanity checking on the module list you provide.
346              
347             For instance,
348              
349             module = strict
350             module = warning
351              
352             Will both upgrade the strict and warnings dependencies on your module, regardless of how daft an idea that may be.
353              
354             And with a little glue
355              
356             module = perl
357              
358             Does what you want, but you probably shouldn't rely on that :).
359              
360             =head1 METHODS
361              
362             =head2 mvp_multivalue_args
363              
364             The following properties can be specified multiple times:
365              
366             =over 4
367              
368             =item * C<applyto>
369              
370             =item * C<applyto_relation>
371              
372             =item * C<applyto_phase>
373              
374             =item * C<modules>
375              
376             =back
377              
378             =head2 C<mvp_aliases>
379              
380             The C<module> is an alias for C<modules>
381              
382             =head2 C<current_version_of>
383              
384             $self->current_version_of($package);
385              
386             Attempts to find the current version of C<$package>.
387              
388             Returns C<undef> if something went wrong.
389              
390             =head2 C<register_prereqs>
391              
392             This is for L<< C<Dist::Zilla::Role::PrereqSource>|Dist::Zilla::Role::PrereqSource >>, which gets new prerequisites
393             from this module.
394              
395             =head1 ATTRIBUTES
396              
397             =head2 C<applyto_phase>
398              
399             Determines which phases will be checked for module dependencies to upgrade.
400              
401             [Prereqs::MatchInstalled]
402             applyto_phase = build
403             applyto_phase = test
404              
405             Defaults to:
406              
407             build test runtime configure develop
408              
409             =head2 C<applyto_relation>
410              
411             Determines which relations will be checked for module dependencies to upgrade.
412              
413             [Prereqs::MatchInstalled]
414             applyto_relation = requires
415              
416             Defaults to:
417              
418             requires suggests recommends
419              
420             =head2 C<applyto>
421              
422             Determines the total list of C<phase>/C<relation> combinations which will be checked for dependencies to upgrade.
423              
424             If not specified, is built from L<< C<applyto_phase>|/applyto_phase >> and L<< C<applyto_relation>|/applyto_relation >>
425              
426             [Prereqs::MatchInstalled]
427             applyto = runtime.requires
428             applyto = configure.requires
429              
430             =head2 C<modules>
431              
432             Contains the list of modules that will be searched for in the existing C<Prereqs> stash to upgrade.
433              
434             [Prereqs::MatchInstalled]
435             module = Foo
436             module = Bar
437             modules = Baz ; this is the same as the previous 2
438              
439             If you want to automatically add B<all> modules that are C<prereqs>, perhaps instead look at
440             L<< C<[Prereqs::MatchInstalled::All]>|Dist::Zilla::Plugin::Prereqs::MatchInstalled::All >>
441              
442             =head1 PRIVATE ATTRIBUTES
443              
444             =head2 C<_applyto_list>
445              
446             B<Internal.>
447              
448             Contains the contents of L<< C<applyto>|/applyto >> represented as an C<ArrayRef[ArrayRef[Str]]>
449              
450             =head2 C<_modules_hash>
451              
452             Contains a copy of L<< C<modules>|/modules >> as a hash for easy look-up.
453              
454             =head1 PRIVATE METHODS
455              
456             =head2 _build_applyto
457              
458             =head2 _build_applyto_list
459              
460             =head2 _build__modules_hash
461              
462             =head2 _user_wants_upgrade_on
463              
464             =begin MetaPOD::JSON v1.1.0
465              
466             {
467             "namespace":"Dist::Zilla::Plugin::Prereqs::MatchInstalled",
468             "interface":"class",
469             "inherits":"Moose::Object",
470             "does":["Dist::Zilla::Role::PrereqSource","Dist::Zilla::Role::Plugin","Dist::Zilla::Role::ConfigDumper"]
471             }
472              
473              
474             =end MetaPOD::JSON
475              
476             =head1 AUTHOR
477              
478             Kent Fredric <kentnl@cpan.org>
479              
480             =head1 COPYRIGHT AND LICENSE
481              
482             This software is copyright (c) 2017 by Kent Fredric <kentfredric@gmail.com>.
483              
484             This is free software; you can redistribute it and/or modify it under
485             the same terms as the Perl 5 programming language system itself.
486              
487             =cut