File Coverage

blib/lib/Module/CPANTS/Kwalitee/Uses.pm
Criterion Covered Total %
statement 121 139 87.0
branch 34 56 60.7
condition 10 20 50.0
subroutine 12 14 85.7
pod 3 3 100.0
total 180 232 77.5


line stmt bran cond sub pod time code
1             package Module::CPANTS::Kwalitee::Uses;
2 7     7   4196 use warnings;
  7         18  
  7         258  
3 7     7   44 use strict;
  7         15  
  7         175  
4 7     7   53 use File::Spec::Functions qw(catfile);
  7         14  
  7         360  
5 7     7   4931 use Perl::PrereqScanner::NotQuiteLite 0.9901;
  7         179982  
  7         352  
6 7     7   72 use List::Util 1.33 qw/none/;
  7         179  
  7         582  
7 7     7   55 use version;
  7         16  
  7         54  
8              
9             our $VERSION = '1.00';
10             $VERSION =~ s/_//; ## no critic
11              
12             # These equivalents should be reasonably well-known and, preferably,
13             # well-documented. Don't add obscure modules used by only one person
14             # or a few people, to keep the list relatively small and to encourage
15             # people to use a better equivalent.
16             # "use_(strict|warnings)" should fail if someone feels the need
17             # to add "use $1;" in the modules.
18             our @STRICT_EQUIV = qw( strict );
19             our @WARNINGS_EQUIV = qw( warnings warnings::compat );
20             our @STRICT_WARNINGS_EQUIV = qw(
21             common::sense
22             Any::Moose
23             Catmandu::Sane Coat
24             Dancer
25             Mo Mu
26             Modern::Perl
27             Moo Moo::Role
28             Moose Moose::Role Moose::Exporter
29             Moose::Util::TypeConstraints Moose::Util::MetaRole
30             MooseX::Declare MooseX::Role::Parameterized MooseX::Types
31             Mouse Mouse::Role
32             perl5 perl5i::1 perl5i::2 perl5i::latest
33             Pegex::Base
34             Role::Tiny
35             strictures
36             );
37             # These modules require a flag to enforce strictness.
38             push @STRICT_WARNINGS_EQUIV, qw(
39             Mojo::Base
40             Spiffy
41             );
42              
43 42     42 1 130 sub order { 100 }
44              
45             ##################################################################
46             # Analyse
47             ##################################################################
48              
49             sub analyse {
50 11     11 1 44 my $class = shift;
51 11         29 my $me = shift;
52            
53 11         253 my $distdir = $me->distdir;
54 11         234 my $modules = $me->d->{modules};
55 11         221 my $files = $me->d->{files_hash};
56              
57             # NOTE: all files in xt/ should be ignored because they are
58             # for authors only and their dependencies may not be (and
59             # often are not) listed in meta files.
60 11         93 my @test_files = grep {m!^t\b.*\.t!} sort keys %$files;
  19         140  
61 11         230 $me->d->{test_files} = \@test_files;
62              
63             my %test_modules = map {
64 0         0 my $m = $_;
65 0         0 $m =~ s|\.pm$||;
66 0         0 $m =~ s|/|::|g;
67 0         0 ($m => $_)
68 11         134 } grep {m|^t\b.*\.pm$|} keys %$files;
  19         159  
69              
70 11         43 my %skip=map {$_->{module}=>1 } @$modules;
  9         79  
71              
72             # d->{versions} (from SiteKwalitee) knows inner packages as well
73 11 50       320 if (my $versions = $me->d->{versions}) {
74 0         0 for my $file (keys %$versions) {
75 0         0 for my $module (keys %{$versions->{$file}}) {
  0         0  
76 0         0 $skip{$module} = 1;
77             }
78             }
79             }
80              
81 11         138 my %uses;
82              
83 11         224 my $scanner = Perl::PrereqScanner::NotQuiteLite->new(
84             parsers => [':bundled'],
85             suggests => 1,
86             recommends => 1,
87             quick => 1,
88             );
89            
90             # modules
91 11         147082 my @module_files = map {$_->{file}} grep {!$_->{not_exists}} @$modules;
  9         62  
  9         51  
92              
93             # Makefile.PL runs other Makefile.PL files at configure time (except ones under t)
94             # Build.PL runs other *.PL files at build time
95 11 50       33 my @configure_files = grep {/(?:^Build|\bMakefile)\.PL$/ && !/^t[\\\/]/} @{$me->d->{files_array} || []};
  19 50       253  
  11         288  
96 11         67 my %configure_files_map = map {$_ => 1} @configure_files;
  0         0  
97              
98             # Other *.PL files (including lib/Build.PL) would (probably) be run at bulid time
99 11 50 33     30 my @build_files = grep {/\.PL$/ && !/^t[\\\/]/ && !$configure_files_map{$_}} @{$me->d->{files_array} || []};
  19 50       172  
  11         240  
100              
101 11         124 $uses{runtime} = $class->_scan($scanner, $files, $distdir, \@module_files);
102 11         90 $uses{configure} = $class->_scan($scanner, $files, $distdir, \@configure_files);
103 11         53 $uses{build} = $class->_scan($scanner, $files, $distdir, \@build_files);
104 11         50 $uses{test} = $class->_scan($scanner, $files, $distdir, \@test_files);
105              
106             # See also .pm files under t (only) if they are used in .t files
107 11         77 my $test_requirements = $uses{test}{requires}->as_string_hash;
108 11         173 my @test_pmfiles;
109 11         57 for my $module (keys %$test_requirements) {
110 0 0       0 push @test_pmfiles, $test_modules{$module} if $test_modules{$module};
111             }
112 11         44 my $additional_test_requirements = $class->_scan($scanner, $files, $distdir, \@test_pmfiles);
113 11         85 for my $relationship (keys %$additional_test_requirements) {
114             $uses{test}{$relationship} = ($uses{test}{$relationship})
115             ? $uses{test}{$relationship}->add_requirements($additional_test_requirements->{$relationship})
116 44 50       541 : $additional_test_requirements->{$relationship};
117             }
118              
119 11         148 for my $phase (keys %uses) {
120 44         69 for my $relationship (keys %{$uses{$phase}}) {
  44         121  
121 176         370 my $requirements = $uses{$phase}{$relationship}->as_string_hash;
122 176         1554 for my $requirement (keys %$requirements) {
123 2 0 33     29 if (
      33        
      33        
124             $skip{$requirement}
125             or $requirement =~ /^(?:inc|t)::/
126             or ($phase eq 'test' and $test_modules{$requirement})
127             ) {
128 0         0 delete $requirements->{$requirement};
129             }
130             }
131 176 100       309 if (%$requirements) {
132 2         12 $uses{$phase}{$relationship} = $requirements;
133             } else {
134 174         422 delete $uses{$phase}{$relationship};
135             }
136             }
137 44 100       74 delete $uses{$phase} unless %{$uses{$phase}};
  44         136  
138             }
139              
140 11         322 $me->d->{uses} = \%uses;
141 11         702 return;
142             }
143              
144             sub _scan {
145 55     55   161 my ($class, $scanner, $files_hash, $distdir, $files) = @_;
146              
147 55         197 my @methods = qw/requires recommends suggests noes/;
148 55         114 my %reqs = map {$_ => CPAN::Meta::Requirements->new} @methods;
  220         2529  
149 55         787 for my $file (@$files) {
150 9         72 my $ctx = $scanner->scan_file("$distdir/$file");
151              
152             # There may be broken files (intentionally, or unintentionally, esp in tests)
153 9 50       19446 if (@{$ctx->{errors} || []}) {
  9 50       57  
154 0         0 $files_hash->{$file}{scan_error} = 1;
155             }
156              
157 9 50       47 if ($ctx->{perl6}) {
158 0         0 $files_hash->{$file}{perl6} = 1;
159 0         0 next;
160             }
161 9         29 for my $method (@methods) {
162 36         375 my $requirements = $ctx->$method;
163 36         618 my $hash = $requirements->as_string_hash;
164 36 100       943 next unless %$hash;
165 2         8 $files_hash->{$file}{$method} = $hash;
166 2         8 $reqs{$method} = $reqs{$method}->add_requirements($requirements);
167             }
168             }
169 55         300 return \%reqs;
170             }
171              
172             ##################################################################
173             # Kwalitee Indicators
174             ##################################################################
175              
176             sub kwalitee_indicators {
177             return [
178             {
179             name => 'use_strict',
180             error => q{This distribution does not 'use strict;' (or its equivalents) in all of its modules. Note that this is not about the actual strictness of the modules. It's bad if nobody can tell whether the modules are strictly written or not, without reading the source code of your favorite clever module that actually enforces strictness. In other words, it's bad if someone feels the need to add 'use strict' to your modules.},
181             remedy => q{Add 'use strict' (or its equivalents) to all modules, or convince us that your favorite module is well-known enough and people can easily see the modules are strictly written.},
182             ignorable => 1,
183             code => sub {
184 11     11   79 my $d = shift;
185 11   50     43 my $files = $d->{files_hash} || {};
186              
187 11         268 my $perl_version_with_implicit_stricture = version->new('5.011')->numify;
188 11         46 my @no_strict;
189              
190 11         41 for my $file (keys %$files) {
191 19 100       96 next unless exists $files->{$file}{module};
192 9 50       31 next if $files->{$file}{unreadable};
193 9 50       30 next if $files->{$file}{perl6};
194 9 50       35 next if $file =~ /\.pod$/;
195 9         23 my $module = $files->{$file}{module};
196 9   100     61 my $requires = $files->{$file}{requires} || {};
197 9         25 my $required_perl = $requires->{perl};
198 9 100       25 if (defined $required_perl) {
199 2         6 $required_perl =~ s/_//; # tweak 5.008_001 and the likes for silence
200 2 50       31 next if version->parse($required_perl)->numify >= $perl_version_with_implicit_stricture;
201             }
202              
203             # There are lots of acceptable strict alternatives
204 7 50       125 push @no_strict, $module if none {exists $requires->{$_}} (@STRICT_EQUIV, @STRICT_WARNINGS_EQUIV);
  210         335  
205             }
206 11 100       38 if (@no_strict) {
207 7         38 $d->{error}{use_strict} = join ", ", sort @no_strict;
208 7         31 return 0;
209             }
210 4         15 return 1;
211             },
212             details => sub {
213 0     0   0 my $d = shift;
214 0         0 return "The following modules don't use strict (or equivalents): " . $d->{error}{use_strict};
215             },
216             },
217             {
218             name => 'use_warnings',
219             error => q{This distribution does not 'use warnings;' (or its equivalents) in all of its modules. Note that this is not about that your modules actually warn when something bad happens. It's bad if nobody can tell if a module warns or not, without reading the source code of your favorite module that actually enforces warnings. In other words, it's bad if someone feels the need to add 'use warnings' to your modules.},
220             is_extra => 1,
221             ignorable => 1,
222             remedy => q{Add 'use warnings' (or its equivalents) to all modules (this will require perl > 5.6), or convince us that your favorite module is well-known enough and people can easily see the modules warn when something bad happens.},
223             code => sub {
224 11     11   80 my $d = shift;
225 11   50     46 my $files = $d->{files_hash} || {};
226              
227 11         25 my @no_warnings;
228 11         40 for my $file (keys %$files) {
229 19 100       53 next unless exists $files->{$file}{module};
230 9 50       51 next if $files->{$file}{unreadable};
231 9 50       34 next if $files->{$file}{perl6};
232 9 50       49 next if $file =~ /\.pod$/;
233 9         25 my $module = $files->{$file}{module};
234 9   100     51 my $requires = $files->{$file}{requires} || {};
235 9 50       106 push @no_warnings, $module if none {exists $requires->{$_}} (@WARNINGS_EQUIV, @STRICT_WARNINGS_EQUIV);
  279         426  
236             }
237 11 100       41 if (@no_warnings) {
238 9         43 $d->{error}{use_warnings} = join ", ", sort @no_warnings;
239 9         38 return 0;
240             }
241 2         7 return 1;
242             },
243             details => sub {
244 0     0   0 my $d = shift;
245 0         0 return "The following modules don't use warnings (or equivalents): " . $d->{error}{use_warnings};
246             },
247             },
248 8     8 1 295 ];
249             }
250              
251              
252             q{Favourite record of the moment:
253             Fat Freddys Drop: Based on a true story};
254              
255             __END__