File Coverage

blib/lib/File/Find/Rule/Perl.pm
Criterion Covered Total %
statement 81 96 84.3
branch 29 40 72.5
condition 10 15 66.6
subroutine 15 20 75.0
pod 0 6 0.0
total 135 177 76.2


line stmt bran cond sub pod time code
1             package File::Find::Rule::Perl;
2              
3             =pod
4              
5             =head1 NAME
6              
7             File::Find::Rule::Perl - Common rules for searching for Perl things
8              
9             =head1 SYNOPSIS
10              
11             use File::Find::Rule ();
12             use File::Find::Rule::Perl ();
13            
14             # Find all Perl files smaller than 10k
15             my @files = File::Find::Rule->perl_file
16             ->size('<10Ki')
17             ->in('dir');
18            
19             # Locate all the modules that PAUSE will index
20             my @mod = File::Find::Rule->no_index
21             ->perl_module
22             ->in('My-Distribution');
23              
24             =head1 DESCRIPTION
25              
26             I write a lot of things that muck with Perl files. And it always annoyed
27             me that finding "perl files" requires a moderately complex
28             L<File::Find::Rule> pattern.
29              
30             B<File::Find::Rule::Perl> provides methods for finding various
31             types Perl-related files, or replicating search queries run on a
32             distribution in various parts of the CPAN ecosystem.
33              
34             =head1 METHODS
35              
36             =cut
37              
38 3     3   140278 use 5.00503;
  3         111  
  3         163  
39 3     3   20 use strict;
  3         5  
  3         116  
40 3     3   17 use Carp;
  3         17  
  3         307  
41 3     3   18 use File::Spec 0.82 ();
  3         76  
  3         57  
42 3     3   16 use File::Spec::Unix ();
  3         7  
  3         80  
43 3     3   2857 use File::Find::Rule 0.20 ();
  3         12687  
  3         85  
44 3     3   3416 use Params::Util 0.38 ();
  3         29856  
  3         104  
45 3     3   19436 use Parse::CPAN::Meta 1.38 ();
  3         8687  
  3         102  
46              
47 3     3   24 use vars qw{$VERSION @ISA @EXPORT};
  3         4  
  3         322  
48             BEGIN {
49 3     3   39 $VERSION = '1.13';
50 3         46 @ISA = 'File::Find::Rule';
51 3         64 @EXPORT = @File::Find::Rule::EXPORT;
52             }
53              
54 3     3   17 use constant FFR => 'File::Find::Rule';
  3         6  
  3         3847  
55              
56              
57              
58              
59              
60             #####################################################################
61             # File::Find::Rule Method Addition
62              
63             =pod
64              
65             =head2 perl_module
66              
67             The C<perl_module> rule locates perl modules. That is, files that
68             are named C<*.pm>.
69              
70             This rule is equivalent to C<-E<gt>>file-E<gt>name( '*.pm' )> and is
71             included primarily for completeness.
72              
73             =cut
74              
75             sub File::Find::Rule::perl_module {
76 0     0 0 0 my $find = $_[0]->_force_object;
77 0         0 return $find->name('*.pm')->file;
78             }
79              
80             =pod
81              
82             =head2 perl_test
83              
84             The C<perl_test> rule locates perl test scripts. That is, files that
85             are named C<*.t>.
86              
87             This rule is equivalent to C<-E<gt>>file-E<gt>name( '*.t' )> and is
88             included primarily for completeness.
89              
90             =cut
91              
92             sub File::Find::Rule::perl_test {
93 0     0 0 0 my $find = $_[0]->_force_object;
94 0         0 return $find->name('*.t')->file;
95             }
96              
97             =pod
98              
99             =head2 perl_installer
100              
101             The C<perl_installer> rule locates perl distribution installers. That is,
102             it locates C<Makefile.PL> and C<Build.PL> files.
103              
104             =cut
105              
106             sub File::Find::Rule::perl_installer {
107 0     0 0 0 my $self = shift()->_force_object;
108 0         0 return $self->file->name( 'Makefile.PL', 'Build.PL' );
109             }
110              
111             =pod
112              
113             =head2 perl_script
114              
115             The C<perl_script> rule locates perl scripts.
116              
117             This is any file that ends in F<.pl>, or any files without extensions
118             that have a perl "hash-bang" line.
119              
120             =cut
121              
122             sub File::Find::Rule::perl_script {
123 0     0 0 0 my $self = shift()->_force_object;
124 0         0 $self->or(
125             FFR->name( '*.pl' )->file,
126             FFR->name( qr/^[^.]+$/ )->file
127             ->exec( \&File::Find::Rule::Perl::_shebang ),
128             );
129             }
130              
131             sub File::Find::Rule::Perl::_shebang {
132 0     0   0 local *SEARCHFILE;
133 0 0       0 open SEARCHFILE, $_ or return !1;
134 0         0 my $first_line = <SEARCHFILE>;
135 0         0 close SEARCHFILE;
136 0 0       0 return !1 unless defined $first_line;
137 0         0 return $first_line =~ /^#!.*\bperl\b/;
138             }
139              
140             =pod
141              
142             =head2 perl_file
143              
144             The C<perl_file> rule locates all files containing Perl code.
145              
146             This includes all the files matching the above C<perl_module>,
147             C<perl_test>, C<perl_installer> and C<perl_script> rules.
148              
149             =cut
150              
151             sub File::Find::Rule::perl_file {
152 2     2 0 3424 my $self = shift()->_force_object;
153 2         24 $self->or(
154             FFR->name('*.pm', '*.t', '*.pl', 'Makefile.PL', 'Build.PL')->file,
155             FFR->name( qr/^[^.]+$/ )->file
156             ->exec( \&File::Find::Rule::Perl::_shebang ),
157             );
158             }
159              
160             =pod
161              
162             =head2 no_index
163              
164             # Provide the rules directly
165             $rule->no_index(
166             directory => [ 'inc', 't', 'examples' ],
167             file => [ 'Foo.pm', 'lib/Foo.pm' ],
168             );
169            
170             # Provide a META.yml to use
171             $rule->no_index( 'META.yml' );
172            
173             # Provide a dist root directory to look for a META.yml in
174             $rule->no_index( 'My-Distribution' );
175            
176             # Automatically pick up a META.yml from the target directory
177             $rule->no_index->in( 'My-Distribution' );
178              
179             The C<no_index> method applies a set of rules as per the no_index section
180             in a C<META.yml> file.
181              
182             =cut
183              
184             # There's probably some bugs in this process somewhere,
185             sub File::Find::Rule::no_index {
186 10     10 0 46136 my $find = shift()->_force_object;
187              
188             # Variables we'll need in the closure
189 10         95 my $rule = undef;
190 10         19 my $root = undef;
191              
192             # Handle the various param options
193 10 100       649 if ( @_ == 0 ) {
    100          
    50          
194             # No params means we auto-calculate
195 5         14 $rule = undef;
196              
197             } elsif ( Params::Util::_HASHLIKE($_[0]) ) {
198 3         14 $rule = _no_index($_[0]);
199              
200             } elsif ( defined Params::Util::_STRING($_[0]) ) {
201 2         5 my $path = shift;
202 2 100       669 if ( -d $path ) {
203             # This is probably a dist directory
204 1         22 my $meta = File::Spec->catfile($path, 'META.yml');
205 1 50       30 $path = $meta if -f $meta;
206             }
207 2 50       26 if ( -f $path ) {
208             # This is a META.yml file
209 2         12 my $meta = Parse::CPAN::Meta::LoadFile($path);
210              
211             # Shortcut if there's nothing to do
212 2         12563 my $no_index = $meta->{no_index};
213 2 50       12 if ( $no_index ) {
214 2         9 $rule = _no_index($no_index);
215             }
216             }
217             } else {
218 0         0 Carp::croak("Invalid or unsupported parameter type");
219             }
220              
221             # Generate the subroutine in advance
222             my $function = sub {
223 408     408   125167 my $shortname = $_[0];
224 408         784 my $fullname = $_[2];
225              
226             # In the automated case the first time we are
227             # called we are passed the META.yml-relative root.
228 408 100       3167 unless ( defined $root ) {
229 10 100       99 if ( File::Spec->file_name_is_absolute($fullname) ) {
230 3         7 $root = $fullname;
231             } else {
232 7         1418 $root = File::Spec->rel2abs(
233             File::Spec->curdir
234             );
235             }
236             }
237 408 100       3481 unless ( defined $rule ) {
238 5         10 $rule = '';
239 5         63 my $meta = File::Spec->catfile( $root, 'META.yml' );
240 5 50       198 if ( -f $meta ) {
241 5         29 my $yaml = Parse::CPAN::Meta::LoadFile($meta);
242 5 50 33     102531 if ( $yaml and $yaml->{no_index} ) {
243 5         25 $rule = _no_index( $yaml->{no_index} );
244             }
245             }
246             }
247              
248             # Shortcut when there is no META.yml
249 408 50       3338 return 0 unless $rule;
250              
251             # Derive the META.yml-relative unix path
252 408 100       19569 my $absname = File::Spec->file_name_is_absolute($fullname)
253             ? $fullname
254             : File::Spec->rel2abs($shortname);
255 408         69749 my $relpath = File::Spec->abs2rel($absname, $root);
256              
257             # Attempt to match a META.yml entry
258 408 100 66     8645 if ( ($rule->{directory}->{$relpath} or $rule->{directory}->{$absname} ) and -d $absname ) {
      66        
259 16         1821 return 1;
260             }
261 392 100 100     13758 if ( ( $rule->{file}->{$relpath} or $rule->{file}->{$absname} ) and -f $absname ) {
      66        
262 2         62 return 1;
263             }
264 390         26195 return 0;
265 10         81 };
266              
267             # Generate the rule
268 10         137 return $find->or(
269             FFR->exec( $function )->prune->discard,
270             FFR->new,
271             );
272             }
273              
274             sub _no_index {
275 10     10   25 my $param = shift;
276              
277             # Index the directory and file entries for faster access
278 2         12 my %file = $param->{file} ? (
279 10 100       61 map { $_ => 1 } @{$param->{file}}
  2         7  
280             ) : ();
281 20         191 my %directory = $param->{directory} ? (
282 10 100       1399 map { $_ => 1 } @{$param->{directory}}
  8         35  
283             ) : ();
284              
285             return {
286 10         153 file => \%file,
287             directory => \%directory,
288             };
289             }
290              
291             1;
292              
293             =pod
294              
295             =head1 SUPPORT
296              
297             Bugs should always be submitted via the CPAN bug tracker
298              
299             L<http://rt.cpan.org/NoAuth/ReportBug.html?Queue=File-Find-Rule-Perl>
300              
301             For other issues, contact the maintainer
302              
303             =head1 AUTHOR
304              
305             Adam Kennedy E<lt>adamk@cpan.orgE<gt>
306              
307             =head1 SEE ALSO
308              
309             L<http://ali.as/>, L<File::Find::Rule>, L<File::Find::Rule::PPI>
310              
311             =head1 COPYRIGHT
312              
313             Copyright 2006 - 2012 Adam Kennedy.
314              
315             This program is free software; you can redistribute
316             it and/or modify it under the same terms as Perl itself.
317              
318             The full text of the license can be found in the
319             LICENSE file included with this module.
320              
321             =cut