File Coverage

blib/lib/Module/CPANTS/Kwalitee/FindModules.pm
Criterion Covered Total %
statement 70 118 59.3
branch 33 74 44.5
condition 4 15 26.6
subroutine 8 10 80.0
pod 3 3 100.0
total 118 220 53.6


line stmt bran cond sub pod time code
1             package Module::CPANTS::Kwalitee::FindModules;
2 7     7   40526 use warnings;
  7         37  
  7         323  
3 7     7   50 use strict;
  7         19  
  7         239  
4 7     7   409 use File::Spec::Functions qw(catfile);
  7         686  
  7         10901  
5              
6             our $VERSION = '1.01';
7             $VERSION =~ s/_//; ## no critic
8              
9 49     49 1 163 sub order { 30 }
10              
11             ##################################################################
12             # Analyse
13             ##################################################################
14              
15             sub analyse {
16 11     11 1 30 my $class = shift;
17 11         19 my $me = shift;
18 11   50     228 my $files = $me->d->{files_array} || [];
19              
20 11 50 66     226 if ($me->d->{meta_yml} && $me->d->{meta_yml}{provides}) {
21 0         0 my $provides = $me->d->{meta_yml}{provides};
22 0         0 for my $module (sort keys %$provides) {
23 0         0 my $data = $provides->{$module};
24 0 0       0 next unless ref $data eq ref {}; # ignore wrong format
25 0   0     0 my $file = $data->{file} || '';
26 0         0 my $found = {
27             module => $module,
28             file => $file,
29             in_basedir => 0,
30             in_lib => 0,
31             };
32 0         0 my $loc;
33 0 0       0 if ($file =~ /^lib\W/) {
    0          
34 0         0 $found->{in_lib} = 1;
35             }
36             elsif ($file !~ /\//) {
37 0         0 $found->{in_basedir} = 1;
38             }
39              
40 0         0 push @{$me->d->{modules}}, $found;
  0         0  
41 0 0       0 if (exists $me->d->{files_hash}{$file}) {
42 0         0 (my $path_part = $module) =~ s|::|/|g;
43 0 0       0 if ($file =~ /\b$path_part\.pm$/) {
    0          
44 0         0 $me->d->{files_hash}{$file}{module} = $module;
45             } elsif ("$path_part.pm" =~ /\b$file$/) {
46 0   0     0 $me->d->{files_hash}{$file}{module} ||= $module;
47             }
48             } else {
49 0         0 $found->{not_exists} = 1;
50             }
51             }
52             }
53             else {
54 11         161 my %in_basedir = map {$_ => 1} grep {/^[^\/]+\.pm$/} @$files;
  3         21  
  19         122  
55              
56 11         59 foreach my $file (@$files) {
57 19 100       97 next unless $file =~ /\.pm$/;
58 9 50       33 next if $file =~ m{^x?t/};
59 9 50       28 next if $file =~ m{^test/};
60 9 50       51 next if $file =~ m/^(bin|scripts?|ex|eg|examples?|samples?|demos?)\/\w/i;
61 9 50       29 next if $file =~ m{^inc/}; # skip Module::Install stuff
62 9 50       43 next if $file =~ m{^(local|perl5|fatlib)/};
63              
64             # proper file in lib/
65 9 100       52 if ($file =~ m|^lib/(.*)\.pm$|) {
66 6         29 my $module = $1;
67 6         37 $module =~ s|/|::|g;
68 6         11 push (@{$me->d->{modules}}, {
  6         108  
69             module => $module,
70             file => $file,
71             in_basedir => 0,
72             in_lib => 1,
73             });
74 6         161 $me->d->{files_hash}{$file}{module} = $module;
75             }
76             else {
77             # open file and find first package
78 3         32 my ($basename) = $file =~ /(\w+)\.pm/;
79 3         9 my $module;
80 3         6 my $max_lines_to_look_at = 666;
81 3 50       83 open (my $fh, "<", catfile($me->distdir, $file)) or die "__PACKAGE__: Cannot open $file to find package declaration: $!";
82 3         183 while (my $line = <$fh>) {
83 3 50       15 next if $line =~ /^\s*#/; # ignore comments
84 3 50       49 if ($line =~ /^\s*package\s*(.*?)\s*;/) {
85 3         14 $module = $1;
86 3 50 33     39 last if $basename and $module =~ /\b$basename$/;
87             }
88 0 0       0 last if $line =~ /^__(DATA|END)__/;
89 0         0 $max_lines_to_look_at--;
90 0 0       0 last unless $max_lines_to_look_at;
91             }
92             # try to guess from filename
93 3 50       11 unless ($module) {
94 0         0 $file =~ m|(.*)\.pm$|;
95 0         0 $module = $1;
96 0         0 $module =~ s|^[a-z]+/||; # remove lowercase prefixes which most likely are not part of the distname (but something like 'src/')
97 0         0 $module =~ s|/|::|g;
98             }
99 3 50       10 if ($module) {
100 3         68 push(@{$me->d->{modules}}, {
101             module => $module,
102             file => $file,
103 3 50       4 in_basedir => $in_basedir{$file} ? 1 : 0,
104             in_lib => 0,
105             });
106 3         106 $me->d->{files_hash}{$file}{module} = $module;
107             }
108             }
109             }
110             }
111              
112 11         128 for my $file (keys %{$me->d->{files_hash}}) {
  11         198  
113 19 50       142 next unless $file =~ /^inc\/(.+)\.pm/;
114 0         0 my $module = $1;
115 0         0 $module =~ s|/|::|g;
116 0   0     0 push @{$me->d->{included_modules} ||= []}, $module;
  0         0  
117             }
118              
119 11 100       192 if (exists $me->d->{modules}) {
120 9         54 $me->d->{modules} = [sort {$a->{module} cmp $b->{module}} @{$me->d->{modules}}];
  0         0  
  9         155  
121             }
122 11 50       240 if (exists $me->d->{included_modules}) {
123 0         0 $me->d->{included_modules} = [sort @{$me->d->{included_modules}}];
  0         0  
124             }
125              
126 11         83 return 1;
127             }
128              
129              
130              
131             ##################################################################
132             # Kwalitee Indicators
133             ##################################################################
134              
135             sub kwalitee_indicators {
136             return [
137             {
138             name => 'proper_libs',
139             error => q{There is more than one .pm file in the base dir, or the .pm files are not in lib/ directory.},
140             remedy => q{Move your *.pm files in a directory named 'lib'. The directory structure should look like 'lib/Your/Module.pm' for a module named 'Your::Module'. If you need to provide additional files, e.g. for testing, that should not be considered for Kwalitee, then you should look at the 'provides' map in META.yml to limit the files scanned; or use the 'no_index' map to exclude parts of the distribution.},
141             is_extra => 1,
142             code => sub {
143 11     11   77 my $d = shift;
144 11 100       23 my @modules = @{$d->{modules} || []};
  11         68  
145 11 100       51 return 1 unless @modules;
146              
147 9         23 my @not_in_lib = grep { !$_->{in_lib} } @modules;
  9         42  
148 9 100       31 return 1 unless @not_in_lib;
149              
150 3         8 my @in_basedir = grep { $_->{in_basedir} } @not_in_lib;
  3         8  
151 3 50       14 return 1 if @in_basedir == 1;
152              
153 0         0 $d->{error}{proper_libs} = join ', ', map {$_->{file}} @not_in_lib;
  0         0  
154              
155 0         0 return 0;
156             },
157             details => sub {
158 0     0   0 my $d = shift;
159 0 0       0 my @modules = @{$d->{modules} || []};
  0         0  
160 0 0       0 return "No modules were found" unless @modules;
161 0         0 return "The following files were found: ".$d->{error}{proper_libs};
162             },
163             },
164             {
165             name => 'no_missing_files_in_provides',
166             error => q{Provides field in the META.yml lists a file that does not found in the distribution.},
167             remedy => q{Use authoring tool like Dist::Zilla, Milla, and Minilla to generate correct provides.},
168             is_extra => 1,
169             code => sub {
170 11     11   72 my $d = shift;
171 11 100       18 my @modules = @{$d->{modules} || []};
  11         75  
172 11 100       35 return 1 unless @modules;
173              
174 9 50       30 if (my @not_exists = grep { $_->{not_exists} } @modules) {
  9         75  
175 0         0 $d->{error}{no_missing_files_in_provides} = join ', ', map {$_->{file}} @not_exists;
  0         0  
176 0         0 return 0;
177             }
178 9         31 return 1;
179             },
180             details => sub {
181 0     0   0 my $d = shift;
182 0 0       0 my @modules = @{$d->{modules} || []};
  0         0  
183 0 0       0 return "No modules were found" unless @modules;
184 0         0 return "The following files were missing: ".$d->{error}{no_missing_files_in_provides};
185             },
186             },
187 8     8 1 213 ];
188             }
189              
190              
191             q{Favourite record of the moment:
192             Fat Freddys Drop: Based on a true story};
193              
194              
195             __END__