File Coverage

blib/lib/File/Find/Match.pm
Criterion Covered Total %
statement 78 87 89.6
branch 34 38 89.4
condition 4 4 100.0
subroutine 14 16 87.5
pod 2 3 66.6
total 132 148 89.1


line stmt bran cond sub pod time code
1             package File::Find::Match;
2 3     3   91300 use 5.008;
  3         15  
  3         132  
3 3     3   20 use strict;
  3         6  
  3         122  
4 3     3   32 use warnings;
  3         5  
  3         126  
5 3     3   18 use base 'Exporter';
  3         5  
  3         352  
6 3     3   17 use File::Basename ();
  3         6  
  3         60  
7 3     3   16 use Carp;
  3         5  
  3         309  
8              
9             use constant {
10 3         3851 RULE_PREDICATE => 0,
11             RULE_ACTION => 1,
12            
13             # Author's birth year: 1985. :)
14             IGNORE => \19,
15             MATCH => \85,
16 3     3   17 };
  3         4  
17              
18              
19             our $VERSION = '1.0';
20             our @EXPORT = qw( IGNORE MATCH );
21             our @EXPORT_OK = @EXPORT;
22             our %EXPORT_TAGS = (
23             constants => [ @EXPORT ],
24             all => [ @EXPORT ],
25             );
26              
27             sub new {
28 6     6 1 4586 my ($this) = shift;
29 6         21 my $self = bless {}, $this;
30              
31 6         22 $self->_rules(@_);
32              
33 4         9 return $self;
34             }
35              
36             sub _rules {
37 6     6   14 my $self = shift;
38            
39 6         26 while (@_) {
40 15         23 my ($predicate, $action) = (shift, shift);
41 15 100       179 croak "Undefined action!" unless defined $action;
42 14         40 my $act = $self->_make_action($action);
43 13 100       33 if ($predicate eq 'default') {
44 1         3 $self->{default} = $action;
45 1         4 next;
46             }
47 12         26 my $pred = $self->_make_predicate($predicate);
48            
49 12         17 push @{ $self->{rules} }, [$pred, $action];
  12         61  
50             }
51              
52 4         9 return $self;
53             }
54              
55             sub rule {
56 0     0 0 0 my $self = shift;
57 0         0 warn "rules() and rule() are deprecated! Please pass rules to new() from now on.\n";
58 0         0 $self->_rules(@_);
59             }
60             *rules = \&rule;
61              
62              
63             sub find {
64 2     2 1 56 my ($self, @files) = @_;
65 2         4 my @rules = @{ $self->{rules} };
  2         8  
66              
67 2 100       8 if (exists $self->{default}) {
68 1     24   6 push @rules, [ sub { 1 }, $self->{default} ];
  24         59  
69             }
70              
71 2 100       7 unless (@files) {
72 1         3 @files = ('.');
73             }
74              
75 2         8 FILE: while (@files) {
76 95         147 my $path = shift @files;
77            
78 95         149 RULE: foreach my $rule (@rules) {
79 493 100       4218 if ($rule->[RULE_PREDICATE]->($path)) {
80 95   100     224 my $v = $rule->[RULE_ACTION]->($path) || 0;
81 95 100       930 if (ref $v) {
82 71 100       168 next FILE if $v == IGNORE;
83 69 100       240 last RULE if $v == MATCH;
84             }
85             }
86             }
87            
88 93 100       1223 if (-d $path) {
89 33         43 my $dir;
90 33         679 opendir $dir, $path;
91            
92             # read all files from $dir
93             # skip . and ..
94             # prepend $path/ to the file name.
95             # append to @files.
96 33         634 push @files, map { "$path/$_" } grep(!/^\.\.?$/, readdir $dir);
  93         220  
97            
98 33         444 closedir $dir;
99             }
100             }
101             }
102              
103             # Take a predicate and return a coderef.
104             sub _make_predicate {
105 22     22   1735 my ($self, $pred) = @_;
106 22   100     71 my $ref = ref($pred) || '';
107            
108 22 100       233 croak "Undefined predicate!" unless defined $pred;
109            
110             # If it is a qr// Regexp object,
111             # the predicate is the truth of the regex.
112 21 100       71 if ($ref eq 'Regexp') {
    100          
    100          
113 10     341   50 return sub { $_[0] =~ $pred };
  341         1373  
114             }
115             # If it's a sub, just return it.
116             elsif ($ref eq 'CODE') {
117 3         7 return $pred;
118             }
119             elsif (not $ref) {
120 7 100       25 if ($pred eq 'dir') {
    50          
121 1         163 warn "the predicate 'dir' is deprecated.\n";
122 1         4 $pred = '-d';
123             } elsif ($pred eq 'file') {
124 0         0 warn "the predicate 'file' is deprecated.\n";
125 0         0 $pred = '-f';
126             }
127 7         693 my $code = eval "sub { package main; \$_ = shift; $pred }";
128 7 100       29 if ($@) {
129 1         11 die $@;
130             }
131 6         20 return $code;
132             }
133             # All other values are illegal.
134             else {
135 1         106 croak "Predicate must be a string, code reference, or regexp reference.";
136             }
137             }
138              
139             # Take an action and return a coderef.
140             sub _make_action {
141 14     14   20 my ($self, $act) = @_;
142            
143 14 50       53 if (UNIVERSAL::isa($act, 'UNIVERSAL')) {
    100          
144             # it's an object. Does it support action?
145 0 0       0 if ($act->can('action')) {
146 0     0   0 return sub { $act->action(shift) };
  0         0  
147             } else {
148 0         0 croak "Action object must support action() method!"
149             }
150             } elsif (ref($act) eq 'CODE') {
151 13         21 return $act;
152             } else {
153 1         323 croak "Action must be a coderef or an object.";
154             }
155             }
156              
157             1;
158             __END__