File Coverage

blib/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   40787 use 5.006; # our
  4         9  
2 4     4   13 use strict;
  4         4  
  4         81  
3 4     4   11 use warnings;
  4         4  
  4         243  
4              
5             package CPAN::Meta::Prereqs::Diff;
6              
7             our $VERSION = '0.001004';
8              
9             # ABSTRACT: Compare dependencies between releases using CPAN::Meta.
10              
11             our $AUTHORITY = 'cpan:KENTNL'; # AUTHORITY
12              
13 4     4   1796 use Moo 1.000008 qw( has );
  4         38380  
  4         21  
14 4     4   4395 use Scalar::Util qw( blessed );
  4         5  
  4         273  
15 4     4   1350 use CPAN::Meta::Prereqs::Diff::Addition;
  4         9  
  4         105  
16 4     4   1396 use CPAN::Meta::Prereqs::Diff::Removal;
  4         6  
  4         98  
17 4     4   1349 use CPAN::Meta::Prereqs::Diff::Change;
  4         7  
  4         93  
18 4     4   1340 use CPAN::Meta::Prereqs::Diff::Upgrade;
  4         6  
  4         88  
19 4     4   1343 use CPAN::Meta::Prereqs::Diff::Downgrade;
  4         5  
  4         2538  
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   1001 builder => sub { return $_[0]->_get_prereqs( $_[0]->old_prereqs ) },
43             );
44             has '_real_new_prereqs' => (
45             is => ro =>,
46             lazy => 1,
47 9     9   1028 builder => sub { return $_[0]->_get_prereqs( $_[0]->new_prereqs ) },
48             );
49              
50             sub _dep_add {
51 16     16   22 my ( undef, $phase, $type, $module, $requirement ) = @_;
52 16         201 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   10 my ( undef, $phase, $type, $module, $requirement ) = @_;
62 5         58 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   10 my ( undef, $phase, $type, $module, $old_requirement, $new_requirement ) = @_;
73 5 100 66     27 if ( $old_requirement =~ /[<>=, ]/msx or $new_requirement =~ /[<>=, ]/msx ) {
74 1         16 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         21 require version;
83 4 100       45 if ( version->parse($old_requirement) > version->parse($new_requirement) ) {
84 3         53 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         14 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   31 my ( undef, $input_prereqs ) = @_;
106 19 100 100     106 if ( ref $input_prereqs and blessed $input_prereqs ) {
107 4 100       33 return $input_prereqs if $input_prereqs->isa('CPAN::Meta::Prereqs');
108 1 50       7 return $input_prereqs->effective_prereqs if $input_prereqs->isa('CPAN::Meta');
109             }
110 15 100 66     59 if ( ref $input_prereqs and 'HASH' eq ref $input_prereqs ) {
111 14         1184 require CPAN::Meta::Prereqs;
112 14         11237 return CPAN::Meta::Prereqs->new($input_prereqs);
113             }
114 1         8 require Carp;
115 1         3 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         197 Carp::croak($message);
120             }
121              
122             sub _phase_rel_diff {
123 165     165   156 my ( $self, $phase, $type ) = @_;
124              
125 165         112 my %old_modules = %{ $self->_real_old_prereqs->requirements_for( $phase, $type )->as_string_hash };
  165         2301  
126 164         6349 my %new_modules = %{ $self->_real_new_prereqs->requirements_for( $phase, $type )->as_string_hash };
  164         2216  
127              
128 164         6851 my @all_modules = do {
129 164         239 my %all_modules = map { $_ => 1 } keys %old_modules, keys %new_modules;
  97         99  
130 164         246 sort { $a cmp $b } keys %all_modules;
  106         82  
131             };
132              
133 164         174 my @out_diff;
134              
135 164         192 for my $module (@all_modules) {
136 59 100 66     156 if ( exists $old_modules{$module} and exists $new_modules{$module} ) {
137              
138             # no change
139 38 100       59 next if $old_modules{$module} eq $new_modules{$module};
140              
141             # change
142 5         14 push @out_diff, $self->_dep_change( $phase, $type, $module, $old_modules{$module}, $new_modules{$module} );
143 5         4959 next;
144             }
145 21 100 66     48 if ( exists $old_modules{$module} and not exists $new_modules{$module} ) {
146              
147             # remove
148 5         12 push @out_diff, $self->_dep_remove( $phase, $type, $module, $old_modules{$module} );
149 5         1653 next;
150             }
151              
152             # add
153 16         29 push @out_diff, $self->_dep_add( $phase, $type, $module, $new_modules{$module} );
154 16         1851 next;
155              
156             }
157 164         282 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 8425 my ( $self, %options ) = @_;
206 11 100       15 my @phases = @{ exists $options{phases} ? $options{phases} : [qw( configure build runtime test )] };
  11         48  
207 11 50       15 my @types = @{ exists $options{types} ? $options{types} : [qw( requires recommends suggests conflicts )] };
  11         34  
208              
209 11         12 my @out_diff;
210              
211 11         21 for my $phase (@phases) {
212 42         41 for my $type (@types) {
213 165         204 push @out_diff, $self->_phase_rel_diff( $phase, $type );
214             }
215             }
216 10         31 return @out_diff;
217              
218             }
219              
220 4     4   19 no Moo;
  4         4  
  4         21  
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.001004
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) 2017 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