File Coverage

lib/CPAN/Meta/Prereqs/Diff.pm
Criterion Covered Total %
statement 95 96 98.9
branch 21 24 87.5
condition 12 15 80.0
subroutine 21 21 100.0
pod 1 1 100.0
total 150 157 95.5


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