File Coverage

blib/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   75512 use 5.006;
  4         11  
2 4     4   733 use strict;
  4         701  
  4         108  
3 4     4   26 use warnings;
  4         6  
  4         249  
4              
5             package CPAN::Changes::Group::Dependencies::Stats;
6              
7             our $VERSION = '0.002008';
8              
9             # ABSTRACT: Create a Dependencies::Stats section detailing summarized differences
10              
11             our $AUTHORITY = 'cpan:KENTNL'; # AUTHORITY
12              
13 4     4   1834 use Moo qw( extends has );
  4         37614  
  4         20  
14 4     4   4196 use Carp qw( croak );
  4         679  
  4         180  
15 4     4   1603 use CPAN::Changes 0.30;
  4         64002  
  4         128  
16 4     4   29 use CPAN::Changes::Group;
  4         7  
  4         73  
17 4     4   1922 use CPAN::Meta::Prereqs::Diff;
  4         135431  
  4         128  
18 4     4   1598 use MooX::Lsub qw( lsub );
  4         10822  
  4         19  
19 4     4   3212 use charnames qw( :full );
  4         90835  
  4         22  
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   1260 lsub prelude => sub { [] };
31 2     2   548 lsub new_prereqs => sub { croak 'Required attribute <new_prereqs> was not provided' };
32 1     1   409 lsub old_prereqs => sub { croak 'Required attribute <old_prereqs> was not provided' };
33 26     26   500 lsub symbol_Added => sub { q[+] };
34 1     1   319 lsub symbol_Upgrade => sub { qq[\N{UPWARDS ARROW}] };
35 1     1   316 lsub symbol_Downgrade => sub { qq[\N{DOWNWARDS ARROW}] };
36 27     27   520 lsub symbol_Removed => sub { q[-] };
37 1     1   338 lsub symbol_Changed => sub { q[~] };
38              
39             lsub prereqs_diff => sub {
40 58     58   1112 my ($self) = @_;
41 58         673 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   1139 my ($self) = @_;
49 58         752 my (@diffs) = $self->prereqs_diff->diff(
50             phases => [qw( configure build runtime test develop )],
51             types => [qw( requires recommends suggests conflicts )],
52             );
53 55         140264 return \@diffs;
54             };
55              
56 4     4   38295 no Moo;
  4         6  
  4         25  
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   160 my ( $self, $phase, $rel, $phases ) = @_;
77 180 50       242 return unless exists $phases->{$phase};
78 180 100       300 return unless exists $phases->{$phase}->{$rel};
79              
80 117         93 my $stash = $phases->{$phase}->{$rel};
81              
82 117         75 my @parts;
83 117         105 for my $type (qw( Added Upgrade Downgrade Removed Changed )) {
84 585 100       1079 next if 1 > $stash->{$type};
85 117 50       371 next unless my $method = $self->can( 'symbol_' . $type );
86 117         1718 push @parts, $self->$method() . $stash->{$type};
87             }
88 117 50       159 return unless @parts;
89 117         308 return join q[ ], @parts;
90             }
91              
92             sub _phase_changes {
93 60     60   63 my ( $self, $phase, $phases ) = @_;
94              
95 60         40 my @out;
96             my @extra;
97              
98 60 100       79 if ( my $recommends = $self->_phase_rel_changes( $phase, 'recommends', $phases ) ) {
99 37         48 push @extra, 'recommends: ' . $recommends;
100             }
101 60 100       73 if ( my $suggested = $self->_phase_rel_changes( $phase, 'suggests', $phases ) ) {
102 39         54 push @extra, 'suggests: ' . $suggested;
103             }
104              
105 60 100       79 if ( my $required = $self->_phase_rel_changes( $phase, 'requires', $phases ) ) {
106 41         42 push @out, $required;
107             }
108 60 100       77 if (@extra) {
109 49         146 push @out, sprintf '(%s)', join q[, ], @extra;
110             }
111 60 50       77 if (@out) {
112 60         224 return sprintf '%s: %s', $phase, join q[ ], @out;
113             }
114 0         0 return;
115             }
116              
117             sub _phase_rel_stats {
118 58     58   56 my ($self) = @_;
119 58         55 my $phases = {};
120              
121 58         52 for my $diff ( @{ $self->_diff_items } ) {
  58         741  
122 117         289 my $phase_m = $diff->phase;
123              
124 117         122 my $rel = $diff->type;
125              
126 117 100       195 if ( not exists $phases->{$phase_m} ) {
127 60         101 $phases->{$phase_m} = {};
128             }
129 117 50       172 if ( not exists $phases->{$phase_m}->{$rel} ) {
130 117         274 $phases->{$phase_m}->{$rel} = { Added => 0, Upgrade => 0, Downgrade => 0, Removed => 0, Changed => 0 };
131             }
132 117         111 my $stash = $phases->{$phase_m}->{$rel};
133              
134 117 100       193 $stash->{Added}++ if $diff->is_addition;
135 117 100       375 $stash->{Removed}++ if $diff->is_removal;
136 117 100       346 if ( $diff->is_change ) {
137 5 100       22 $stash->{Upgrade}++ if $diff->is_upgrade;
138 5 100       21 $stash->{Downgrade}++ if $diff->is_downgrade;
139 5 100 66     20 if ( not $diff->is_upgrade and not $diff->is_downgrade ) {
140 1         8 $stash->{Changed}++;
141             }
142             }
143             }
144 55         158 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 42704 my ($self) = @_;
188 58         58 my @changes = @{ $self->prelude };
  58         743  
189              
190 58         109 my $phases = $self->_phase_rel_stats;
191              
192 55         48 for my $phase ( sort keys %{$phases} ) {
  55         123  
193 60         100 push @changes, $self->_phase_changes( $phase, $phases );
194             }
195 55         307 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.002008
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) 2017 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