File Coverage

lib/CPAN/Meta/Prereqs/Diff.pm
Criterion Covered Total %
statement 88 89 98.8
branch 21 24 87.5
condition 11 15 73.3
subroutine 19 19 100.0
pod 1 1 100.0
total 140 148 94.5


line stmt bran cond sub pod time code
1 4     4   49401 use 5.006; # our
  4         11  
2 4     4   14 use strict;
  4         5  
  4         78  
3 4     4   13 use warnings;
  4         4  
  4         260  
4              
5             package CPAN::Meta::Prereqs::Diff;
6              
7             our $VERSION = '0.001003';
8              
9             # ABSTRACT: Compare dependencies between releases using CPAN::Meta.
10              
11             our $AUTHORITY = 'cpan:KENTNL'; # AUTHORITY
12              
13 4     4   2191 use Moo 1.000008 qw( has );
  4         43806  
  4         23  
14 4     4   4572 use Scalar::Util qw( blessed );
  4         5  
  4         287  
15 4     4   1517 use CPAN::Meta::Prereqs::Diff::Addition;
  4         9  
  4         130  
16 4     4   1729 use CPAN::Meta::Prereqs::Diff::Removal;
  4         9  
  4         141  
17 4     4   1885 use CPAN::Meta::Prereqs::Diff::Change;
  4         9  
  4         153  
18 4     4   2074 use CPAN::Meta::Prereqs::Diff::Upgrade;
  4         9  
  4         131  
19 4     4   1785 use CPAN::Meta::Prereqs::Diff::Downgrade;
  4         8  
  4         3205  
20              
21              
22              
23              
24              
25              
26              
27              
28             has 'new_prereqs' => ( is => ro =>, required => 1 );
29              
30              
31              
32              
33              
34              
35              
36              
37             has 'old_prereqs' => ( is => ro =>, required => 1 );
38              
39             has '_real_old_prereqs' => (
40             is => ro =>,
41             lazy => 1,
42 10     10   1073 builder => sub { return $_[0]->_get_prereqs( $_[0]->old_prereqs ) },
43             );
44             has '_real_new_prereqs' => (
45             is => ro =>,
46             lazy => 1,
47 9     9   1132 builder => sub { return $_[0]->_get_prereqs( $_[0]->new_prereqs ) },
48             );
49              
50             sub _dep_add {
51 16     16   23 my ( undef, $phase, $type, $module, $requirement ) = @_;
52 16         220 return CPAN::Meta::Prereqs::Diff::Addition->new(
53             phase => $phase,
54             type => $type,
55             module => $module,
56             requirement => $requirement,
57             );
58             }
59              
60             sub _dep_remove {
61 5     5   9 my ( undef, $phase, $type, $module, $requirement ) = @_;
62 5         67 return CPAN::Meta::Prereqs::Diff::Removal->new(
63             phase => $phase,
64             type => $type,
65             module => $module,
66             requirement => $requirement,
67             );
68             }
69              
70             ## no critic (Subroutines::ProhibitManyArgs)
71             sub _dep_change {
72 5     5   13 my ( undef, $phase, $type, $module, $old_requirement, $new_requirement ) = @_;
73 5 100 66     1044 if ( $old_requirement =~ /[<>=, ]/msx or $new_requirement =~ /[<>=, ]/msx ) {
74 1         20 return CPAN::Meta::Prereqs::Diff::Change->new(
75             phase => $phase,
76             type => $type,
77             module => $module,
78             old_requirement => $old_requirement,
79             new_requirement => $new_requirement,
80             );
81             }
82 4         32 require version;
83 4 100       62 if ( version->parse($old_requirement) > version->parse($new_requirement) ) {
84 3         62 return CPAN::Meta::Prereqs::Diff::Downgrade->new(
85             phase => $phase,
86             type => $type,
87             module => $module,
88             old_requirement => $old_requirement,
89             new_requirement => $new_requirement,
90             );
91             }
92 1 50       9 if ( version->parse($old_requirement) < version->parse($new_requirement) ) {
93 1         16 return CPAN::Meta::Prereqs::Diff::Upgrade->new(
94             phase => $phase,
95             type => $type,
96             module => $module,
97             old_requirement => $old_requirement,
98             new_requirement => $new_requirement,
99             );
100             }
101 0         0 return;
102             }
103              
104             sub _get_prereqs {
105 19     19   34 my ( undef, $input_prereqs ) = @_;
106 19 100 100     121 if ( ref $input_prereqs and blessed $input_prereqs ) {
107 4 100       32 return $input_prereqs if $input_prereqs->isa('CPAN::Meta::Prereqs');
108 1 50       4 return $input_prereqs->effective_prereqs if $input_prereqs->isa('CPAN::Meta');
109             }
110 15 100 66     64 if ( ref $input_prereqs and 'HASH' eq ref $input_prereqs ) {
111 14         1177 require CPAN::Meta::Prereqs;
112 14         12698 return CPAN::Meta::Prereqs->new($input_prereqs);
113             }
114 1         5 require Carp;
115 1         2 my $message = <<'EOF';
116             prereqs parameters take either CPAN::Meta::Prereqs, CPAN::Meta,
117             or a valid CPAN::Meta::Prereqs hash structure.
118             EOF
119 1         165 Carp::croak($message);
120             }
121              
122             sub _phase_rel_diff {
123 165     165   168 my ( $self, $phase, $type ) = @_;
124              
125 165         112 my %old_modules = %{ $self->_real_old_prereqs->requirements_for( $phase, $type )->as_string_hash };
  165         2568  
126 164         7238 my %new_modules = %{ $self->_real_new_prereqs->requirements_for( $phase, $type )->as_string_hash };
  164         2447  
127              
128 164         7635 my @all_modules = do {
129 164         272 my %all_modules = map { $_ => 1 } keys %old_modules, keys %new_modules;
  97         99  
130 164         265 sort { $a cmp $b } keys %all_modules;
  97         88  
131             };
132              
133 164         151 my @out_diff;
134              
135 164         219 for my $module (@all_modules) {
136 59 100 66     139 if ( exists $old_modules{$module} and exists $new_modules{$module} ) {
137              
138             # no change
139 38 100       66 next if $old_modules{$module} eq $new_modules{$module};
140              
141             # change
142 5         19 push @out_diff, $self->_dep_change( $phase, $type, $module, $old_modules{$module}, $new_modules{$module} );
143 5         5629 next;
144             }
145 21 100 66     50 if ( exists $old_modules{$module} and not exists $new_modules{$module} ) {
146              
147             # remove
148 5         13 push @out_diff, $self->_dep_remove( $phase, $type, $module, $old_modules{$module} );
149 5         1848 next;
150             }
151              
152             # add
153 16         28 push @out_diff, $self->_dep_add( $phase, $type, $module, $new_modules{$module} );
154 16         1958 next;
155              
156             }
157 164         277 return @out_diff;
158             }
159              
160              
161              
162              
163              
164              
165              
166              
167              
168              
169              
170              
171              
172              
173              
174              
175              
176              
177              
178              
179              
180              
181              
182              
183              
184              
185              
186              
187              
188              
189              
190              
191              
192              
193              
194              
195              
196              
197              
198              
199              
200              
201              
202              
203              
204             sub diff {
205 11     11 1 19146 my ( $self, %options ) = @_;
206 11 100       15 my @phases = @{ exists $options{phases} ? $options{phases} : [qw( configure build runtime test )] };
  11         52  
207 11 50       12 my @types = @{ exists $options{types} ? $options{types} : [qw( requires recommends suggests conflicts )] };
  11         37  
208              
209 11         15 my @out_diff;
210              
211 11         18 for my $phase (@phases) {
212 42         39 for my $type (@types) {
213 165         219 push @out_diff, $self->_phase_rel_diff( $phase, $type );
214             }
215             }
216 10         33 return @out_diff;
217              
218             }
219              
220 4     4   21 no Moo;
  4         3  
  4         25  
221              
222             1;
223              
224             __END__
225              
226             =pod
227              
228             =encoding UTF-8
229              
230             =head1 NAME
231              
232             CPAN::Meta::Prereqs::Diff - Compare dependencies between releases using CPAN::Meta.
233              
234             =head1 VERSION
235              
236             version 0.001003
237              
238             =head1 SYNOPSIS
239              
240             use CPAN::Meta::Prereqs::Diff;
241              
242              
243             my $diff = CPAN::Meta::Prereqs::Diff->new(
244             new_prereqs => CPAN::Meta->load_file('Dist-Foo-1.01/META.json')->effective_prereqs
245             old_prereqs => CPAN::Meta->load_file('Dist-Foo-1.00/META.json')->effective_prereqs
246             );
247             my @changes = $diff->diff(
248             phases => [qw( runtime build configure test )],
249             types => [qw( requires suggests configures conflicts )],
250             );
251              
252             ## Here, the examples with printf are not needed because ->describe exists
253             ## But they're there any way for example reasons.
254              
255             for my $dep (@prereqs) {
256             if ( $dep->is_addition ) {
257             # runtime.requires: + Foo::Bar 0.4
258             printf "%s.%s : + %s %s",
259             $dep->phase, $dep->type, $dep->module, $dep->requirement;
260             next;
261             }
262             if ( $dep->is_removal ) {
263             # runtime.requires: - Foo::Bar 0.4
264             printf "%s.%s : - %s %s",
265             $dep->phase, $dep->type, $dep->module, $dep->requirement;
266             next;
267             }
268             if ( $dep->is_change ) {
269             if ( $dep->is_upgrade ) {
270             # runtime.requires: ↑ Foo::Bar 0.4 → 0.5
271             printf "%s.%s : \x{2191} %s \x{2192} %s",
272             $dep->phase, $dep->type, $dep->module, $dep->old_requirement, $dep->new_requirement;
273             next;
274             }
275             if ( $dep->is_downgrade ) {
276             # runtime.requires: ↓ Foo::Bar 0.5 → 0.4
277             printf "%s.%s : \x{2193} %s %s \x{2192} %s",
278             $dep->phase, $dep->type, $dep->module, $dep->old_requirement, $dep->new_requirement;
279             next;
280             }
281             # changes that can't be easily determined upgrades or downgrades
282             # runtime.requires: ~ Foo::Bar >=0.5, <=0.7 → >=0.4, <=0.8
283             printf "%s.%s : ~ %s %s \x{2192} %s",
284             $dep->phase, $dep->type, $dep->module, $dep->old_requirement, $dep->new_requirement;
285             next;
286             }
287             }
288              
289             =head1 DESCRIPTION
290              
291             This module allows relatively straight forward routines for comparing and itemizing
292             two sets of C<CPAN::Meta> prerequisites, plucking out kinds of changes that are interesting.
293              
294             =head1 METHODS
295              
296             =head2 C<diff>
297              
298             my @out = $diff->diff( %options );
299              
300             Returns a list of C<Objects> that C<do> L<< C<CPAN::Meta::Prereqs::Diff::Role::Change>|CPAN::Meta::Prereqs::Diff::Role::Change >>, describing the changes between C<old_prereqs> and C<new_prereqs>
301              
302             =over 4
303              
304             =item * L<< C<Addition>|CPAN::Meta::Prereqs::Diff::Addition >>
305              
306             =item * L<< C<Change>|CPAN::Meta::Prereqs::Diff::Change >>
307              
308             =item * L<< C<Upgrade>|CPAN::Meta::Prereqs::Diff::Upgrade >>
309              
310             =item * L<< C<Downgrade>|CPAN::Meta::Prereqs::Diff::Downgrade >>
311              
312             =item * L<< C<Removal>|CPAN::Meta::Prereqs::Diff::Removal >>
313              
314             =back
315              
316             =head3 C<diff.%options>
317              
318             =head4 C<diff.options.phases>
319              
320             my @out = $diff->diff(
321             phases => [ ... ]
322             );
323              
324             ArrayRef
325             default = [qw( configure build runtime test )]
326             valid options = [qw( configure build runtime test develop )]
327              
328             =head4 C<diff.options.types>
329              
330             my @out = $diff->diff(
331             types => [ ... ]
332             );
333              
334             ArrayRef
335             default = [qw( requires recommends suggests conflicts )]
336             valid options = [qw( requires recommends suggests conflicts )]
337              
338             =head1 ATTRIBUTES
339              
340             =head2 C<new_prereqs>
341              
342             required
343             HashRef | CPAN::Meta::Prereqs | CPAN::Meta
344              
345             =head2 C<old_prereqs>
346              
347             required
348             HashRef | CPAN::Meta::Prereqs | CPAN::Meta
349              
350             =head1 AUTHOR
351              
352             Kent Fredric <kentnl@cpan.org>
353              
354             =head1 COPYRIGHT AND LICENSE
355              
356             This software is copyright (c) 2015 by Kent Fredric <kentfredric@gmail.com>.
357              
358             This is free software; you can redistribute it and/or modify it under
359             the same terms as the Perl 5 programming language system itself.
360              
361             =cut