File Coverage

lib/CPAN/Changes/Group/Dependencies/Stats.pm
Criterion Covered Total %
statement 100 101 99.0
branch 31 36 86.1
condition 2 3 66.6
subroutine 27 27 100.0
pod 2 2 100.0
total 162 169 95.8


line stmt bran cond sub pod time code
1 5     5   122386 use 5.006;
  5         15  
  5         163  
2 5     5   19 use strict;
  5         7  
  5         125  
3 5     5   36 use warnings;
  5         5  
  5         340  
4              
5             package CPAN::Changes::Group::Dependencies::Stats;
6              
7             our $VERSION = '0.002006';
8              
9             # ABSTRACT: Create a Dependencies::Stats section detailing summarized differences
10              
11             our $AUTHORITY = 'cpan:KENTNL'; # AUTHORITY
12              
13 5     5   2300 use Moo qw( extends has );
  5         56725  
  5         21  
14 5     5   6378 use Carp qw( croak );
  5         7  
  5         262  
15 5     5   1859 use CPAN::Changes 0.30;
  5         71458  
  5         134  
16 5     5   32 use CPAN::Changes::Group;
  5         7  
  5         97  
17 5     5   2361 use CPAN::Meta::Prereqs::Diff;
  5         257543  
  5         169  
18 5     5   2096 use MooX::Lsub qw( lsub );
  5         22267  
  5         23  
19 5     5   63774 use charnames qw( :full );
  5         113120  
  5         27  
20              
21             extends 'CPAN::Changes::Group';
22              
23              
24              
25              
26              
27              
28              
29 1     1   362 lsub name => sub { 'Dependencies::Stats' };
30 59     59   1858 lsub prelude => sub { [] };
31 2     2   935 lsub new_prereqs => sub { croak 'Required attribute <new_prereqs> was not provided' };
32 1     1   474 lsub old_prereqs => sub { croak 'Required attribute <old_prereqs> was not provided' };
33 27     27   845 lsub symbol_Added => sub { q[+] };
34 1     1   325 lsub symbol_Upgrade => sub { qq[\N{UPWARDS ARROW}] };
35 1     1   323 lsub symbol_Downgrade => sub { qq[\N{DOWNWARDS ARROW}] };
36 27     27   530 lsub symbol_Removed => sub { q[-] };
37 1     1   351 lsub symbol_Changed => sub { q[~] };
38              
39             lsub prereqs_diff => sub {
40 60     60   1761 my ($self) = @_;
41 60         781 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 60     60   2041 my ($self) = @_;
49 60         833 my (@diffs) = $self->prereqs_diff->diff(
50             phases => [qw( configure build runtime test develop )],
51             types => [qw( requires recommends suggests conflicts )],
52             );
53 57         173009 return \@diffs;
54             };
55              
56 5     5   45474 no Moo;
  5         9  
  5         29  
57              
58              
59              
60              
61              
62              
63              
64              
65              
66              
67              
68              
69              
70             sub has_changes {
71 2     2 1 1463 my ($self) = @_;
72 2         3 return @{ $self->_diff_items } > 0;
  2         23  
73             }
74              
75             sub _phase_rel_changes {
76 183     183   178 my ( $self, $phase, $rel, $phases ) = @_;
77 183 50       267 return unless exists $phases->{$phase};
78 183 100       379 return unless exists $phases->{$phase}->{$rel};
79              
80 118         112 my $stash = $phases->{$phase}->{$rel};
81              
82 118         94 my @parts;
83 118         124 for my $type (qw( Added Upgrade Downgrade Removed Changed )) {
84 590 100       1227 next if 1 > $stash->{$type};
85 118 50       375 next unless my $method = $self->can( 'symbol_' . $type );
86 118         1917 push @parts, $self->$method() . $stash->{$type};
87             }
88 118 50       193 return unless @parts;
89 118         326 return join q[ ], @parts;
90             }
91              
92             sub _phase_changes {
93 61     61   65 my ( $self, $phase, $phases ) = @_;
94              
95 61         46 my @out;
96             my @extra;
97              
98 61 100       103 if ( my $recommends = $self->_phase_rel_changes( $phase, 'recommends', $phases ) ) {
99 37         48 push @extra, 'recommends: ' . $recommends;
100             }
101 61 100       85 if ( my $suggested = $self->_phase_rel_changes( $phase, 'suggests', $phases ) ) {
102 39         45 push @extra, 'suggests: ' . $suggested;
103             }
104              
105 61 100       86 if ( my $required = $self->_phase_rel_changes( $phase, 'requires', $phases ) ) {
106 42         43 push @out, $required;
107             }
108 61 100       94 if (@extra) {
109 49         144 push @out, sprintf '(%s)', join q[, ], @extra;
110             }
111 61 50       107 if (@out) {
112 61         215 return sprintf '%s: %s', $phase, join q[ ], @out;
113             }
114 0         0 return;
115             }
116              
117             sub _phase_rel_stats {
118 59     59   57 my ($self) = @_;
119 59         70 my $phases = {};
120              
121 59         56 for my $diff ( @{ $self->_diff_items } ) {
  59         888  
122 118         372 my $phase_m = $diff->phase;
123              
124 118         132 my $rel = $diff->type;
125              
126 118 100       196 if ( not exists $phases->{$phase_m} ) {
127 61         93 $phases->{$phase_m} = {};
128             }
129 118 50       215 if ( not exists $phases->{$phase_m}->{$rel} ) {
130 118         306 $phases->{$phase_m}->{$rel} = { Added => 0, Upgrade => 0, Downgrade => 0, Removed => 0, Changed => 0 };
131             }
132 118         139 my $stash = $phases->{$phase_m}->{$rel};
133              
134 118 100       262 $stash->{Added}++ if $diff->is_addition;
135 118 100       400 $stash->{Removed}++ if $diff->is_removal;
136 118 100       377 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     19 if ( not $diff->is_upgrade and not $diff->is_downgrade ) {
140 1         13 $stash->{Changed}++;
141             }
142             }
143             }
144 56         205 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 59     59 1 56616 my ($self) = @_;
188 59         78 my @changes = @{ $self->prelude };
  59         852  
189              
190 59         110 my $phases = $self->_phase_rel_stats;
191              
192 56         52 for my $phase ( sort keys %{$phases} ) {
  56         128  
193 61         103 push @changes, $self->_phase_changes( $phase, $phases );
194             }
195 56         379 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.002006
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