File Coverage

lib/CPAN/Changes/Group/Dependencies/Stats.pm
Criterion Covered Total %
statement 95 100 95.0
branch 31 36 86.1
condition 2 3 66.6
subroutine 25 27 92.5
pod 2 2 100.0
total 155 168 92.2


line stmt bran cond sub pod time code
1 4     4   85439 use 5.006;
  4         14  
2 4     4   21 use strict;
  4         8  
  4         114  
3 4     4   28 use warnings;
  4         4  
  4         2093  
4              
5             package CPAN::Changes::Group::Dependencies::Stats;
6              
7             our $VERSION = '0.002007';
8              
9             # ABSTRACT: Create a Dependencies::Stats section detailing summarized differences
10              
11             our $AUTHORITY = 'cpan:KENTNL'; # AUTHORITY
12              
13 4     4   2527 use Moo qw( extends has );
  4         51559  
  4         26  
14 4     4   5321 use Carp qw( croak );
  4         7  
  4         232  
15 4     4   2335 use CPAN::Changes 0.30;
  4         87408  
  4         172  
16 4     4   40 use CPAN::Changes::Group;
  4         9  
  4         130  
17 4     4   2755 use CPAN::Meta::Prereqs::Diff;
  4         173125  
  4         174  
18 4     4   2405 use MooX::Lsub qw( lsub );
  4         23776  
  4         25  
19 4     4   4574 use charnames qw( :full );
  4         126806  
  4         28  
20              
21             extends 'CPAN::Changes::Group';
22              
23              
24              
25              
26              
27              
28              
29 0     0   0 lsub name => sub { 'Dependencies::Stats' };
30 58     58   1566 lsub prelude => sub { [] };
31 2     2   641 lsub new_prereqs => sub { croak 'Required attribute <new_prereqs> was not provided' };
32 1     1   497 lsub old_prereqs => sub { croak 'Required attribute <old_prereqs> was not provided' };
33 26     26   715 lsub symbol_Added => sub { q[+] };
34 1     1   327 lsub symbol_Upgrade => sub { qq[\N{UPWARDS ARROW}] };
35 1     1   340 lsub symbol_Downgrade => sub { qq[\N{DOWNWARDS ARROW}] };
36 27     27   681 lsub symbol_Removed => sub { q[-] };
37 1     1   385 lsub symbol_Changed => sub { q[~] };
38              
39             lsub prereqs_diff => sub {
40 58     58   1451 my ($self) = @_;
41 58         976 return CPAN::Meta::Prereqs::Diff->new(
42             new_prereqs => $self->new_prereqs,
43             old_prereqs => $self->old_prereqs,
44             );
45             };
46              
47             lsub _diff_items => sub {
48 58     58   1417 my ($self) = @_;
49 58         1039 my (@diffs) = $self->prereqs_diff->diff(
50             phases => [qw( configure build runtime test develop )],
51             types => [qw( requires recommends suggests conflicts )],
52             );
53 55         192687 return \@diffs;
54             };
55              
56 4     4   48003 no Moo;
  4         9  
  4         30  
57              
58              
59              
60              
61              
62              
63              
64              
65              
66              
67              
68              
69              
70             sub has_changes {
71 0     0 1 0 my ($self) = @_;
72 0         0 return @{ $self->_diff_items } > 0;
  0         0  
73             }
74              
75             sub _phase_rel_changes {
76 180     180   338 my ( $self, $phase, $rel, $phases ) = @_;
77 180 50       329 return unless exists $phases->{$phase};
78 180 100       446 return unless exists $phases->{$phase}->{$rel};
79              
80 117         196 my $stash = $phases->{$phase}->{$rel};
81              
82 117         105 my @parts;
83 117         176 for my $type (qw( Added Upgrade Downgrade Removed Changed )) {
84 585 100       1417 next if 1 > $stash->{$type};
85 117 50       494 next unless my $method = $self->can( 'symbol_' . $type );
86 117         2506 push @parts, $self->$method() . $stash->{$type};
87             }
88 117 50       232 return unless @parts;
89 117         444 return join q[ ], @parts;
90             }
91              
92             sub _phase_changes {
93 60     60   80 my ( $self, $phase, $phases ) = @_;
94              
95 60         62 my @out;
96             my @extra;
97              
98 60 100       125 if ( my $recommends = $self->_phase_rel_changes( $phase, 'recommends', $phases ) ) {
99 37         78 push @extra, 'recommends: ' . $recommends;
100             }
101 60 100       93 if ( my $suggested = $self->_phase_rel_changes( $phase, 'suggests', $phases ) ) {
102 39         73 push @extra, 'suggests: ' . $suggested;
103             }
104              
105 60 100       99 if ( my $required = $self->_phase_rel_changes( $phase, 'requires', $phases ) ) {
106 41         63 push @out, $required;
107             }
108 60 100       108 if (@extra) {
109 49         184 push @out, sprintf '(%s)', join q[, ], @extra;
110             }
111 60 50       116 if (@out) {
112 60         281 return sprintf '%s: %s', $phase, join q[ ], @out;
113             }
114 0         0 return;
115             }
116              
117             sub _phase_rel_stats {
118 58     58   82 my ($self) = @_;
119 58         82 my $phases = {};
120              
121 58         68 for my $diff ( @{ $self->_diff_items } ) {
  58         1071  
122 117         404 my $phase_m = $diff->phase;
123              
124 117         170 my $rel = $diff->type;
125              
126 117 100       296 if ( not exists $phases->{$phase_m} ) {
127 60         129 $phases->{$phase_m} = {};
128             }
129 117 50       236 if ( not exists $phases->{$phase_m}->{$rel} ) {
130 117         410 $phases->{$phase_m}->{$rel} = { Added => 0, Upgrade => 0, Downgrade => 0, Removed => 0, Changed => 0 };
131             }
132 117         157 my $stash = $phases->{$phase_m}->{$rel};
133              
134 117 100       393 $stash->{Added}++ if $diff->is_addition;
135 117 100       490 $stash->{Removed}++ if $diff->is_removal;
136 117 100       523 if ( $diff->is_change ) {
137 5 100       23 $stash->{Upgrade}++ if $diff->is_upgrade;
138 5 100       28 $stash->{Downgrade}++ if $diff->is_downgrade;
139 5 100 66     19 if ( not $diff->is_upgrade and not $diff->is_downgrade ) {
140 1         10 $stash->{Changed}++;
141             }
142             }
143             }
144 55         257 return $phases;
145             }
146              
147              
148              
149              
150              
151              
152              
153              
154              
155              
156              
157              
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             sub changes {
187 58     58 1 75753 my ($self) = @_;
188 58         82 my @changes = @{ $self->prelude };
  58         1123  
189              
190 58         165 my $phases = $self->_phase_rel_stats;
191              
192 55         65 for my $phase ( sort keys %{$phases} ) {
  55         192  
193 60         164 push @changes, $self->_phase_changes( $phase, $phases );
194             }
195 55         490 return \@changes;
196             }
197              
198             1;
199              
200             __END__
201              
202             =pod
203              
204             =encoding utf-8
205              
206             =head1 NAME
207              
208             CPAN::Changes::Group::Dependencies::Stats - Create a Dependencies::Stats section detailing summarized differences
209              
210             =head1 VERSION
211              
212             version 0.002007
213              
214             =head1 SYNOPSIS
215              
216             use CPAN::Changes::Release 0.29;
217             use CPAN::Changes::Group::Dependencies::Stats;
218              
219             my $s = CPAN::Changes::Group::Dependencies::Stats->new(
220             prelude => [ 'Change statistics since 1.00' ],
221             new_prereqs => CPAN::Meta->load_file('Dist-Foo-1.01/META.json')->effective_prereqs,
222             old_prereqs => CPAN::Meta->load_file('Dist-Foo-1.00/META.json')->effective_prereqs,
223             );
224              
225             # Currently slightly complicated due to groups themselves
226             # not presently being pluggable.
227             my $rel = CPAN::Changes::Release->new( version => '1.01' );
228             $rel->attach( $s ) if $s->has_changes;
229             $rel->serialize();
230              
231             # RESULT
232             #
233             # [ Dependencies::Stats ]
234             # - Change statistics since 1.00
235             # - build: -1 (recommends: -1)
236             # - configure: +1 -1 (recommends: +1 -1)
237             # - develop: +5 -5 (suggests: +2 -1)
238             # - test: (recommends: +1 ↑1)
239              
240             =head1 DESCRIPTION
241              
242             This module is a utility tool that produces short, summarized details about changes in dependencies between two sets
243             of prerequisites such that one can visually identify at a glance the general nature of the dependency changes without
244             being swamped by the specifics, only looking into the specifics when the summary indicates it is warranted.
245              
246             This aims to be a utility to assist downstream in quickly assessing effort when performing manual updates.
247              
248             =head1 METHODS
249              
250             =head2 C<has_changes>
251              
252             Returns whether this group has any interesting changes or not.
253              
254             if ( $group->has_changes ) {
255             $release->attach_group( $group );
256             } else {
257             $release->delete_group( $group->name );
258             }
259              
260             =head2 C<changes>
261              
262             Returns a list of change entries.
263              
264             my $changes = $object->changes;
265             say $_ for @{$changes};
266              
267             Format:
268              
269             %phase: %requiredstats (%optlabel: %optstats, ...)
270              
271             C<%phase> is one of C<configure>, C<build>, C<runtime>, C<develop>, C<test>
272              
273             C<%optlabel> is one of C<recommends>, C<suggests>
274              
275             C<%requiredstats> and C<%optstats> are strings of stat changes:
276              
277             %symbol%number %symbol%number ...
278              
279             C<%symbol> is:
280              
281             + a dependency previously unseen in this phase/rel was added.
282             ↑ a dependency in this phase/rel had its version requirement increased.
283             ↓ a dependency in this phase/rel had its version requirement decreased.
284             - this phase/rel had a dependency removed
285             ~ a dependency type where either side was a complex version requirement changed in some way.
286              
287             For instance, this L<diff|https://metacpan.org/diff/file?target=ETHER/Moose-2.1210/META.json&source=ETHER/Moose-2.1005/META.json> would display as:
288              
289             [ Dependencies::Stats ]
290             - configure: +2
291             - develop: +12 ↑3 -2 (suggests: +58)
292             - runtime: +3
293             - test: +1 ↓1 -1 (recommends: +2)
294              
295             Which is far less scary ☺
296              
297             =for Pod::Coverage FOREIGNBUILDARGS
298              
299             =head1 AUTHOR
300              
301             Kent Fredric <kentnl@cpan.org>
302              
303             =head1 COPYRIGHT AND LICENSE
304              
305             This software is copyright (c) 2015 by Kent Fredric <kentfredric@gmail.com>.
306              
307             This is free software; you can redistribute it and/or modify it under
308             the same terms as the Perl 5 programming language system itself.
309              
310             =cut