File Coverage

blib/lib/File/Rules.pm
Criterion Covered Total %
statement 100 121 82.6
branch 41 92 44.5
condition 11 22 50.0
subroutine 15 16 93.7
pod 6 6 100.0
total 173 257 67.3


line stmt bran cond sub pod time code
1             package File::Rules;
2              
3 2     2   120515 use warnings;
  2         6  
  2         77  
4 2     2   13 use strict;
  2         4  
  2         83  
5 2     2   12 use Carp;
  2         8  
  2         182  
6 2     2   12 use File::Spec;
  2         5  
  2         66  
7 2     2   2161 use Data::Dump qw( dump );
  2         36121  
  2         190  
8 2     2   10607 use Path::Class;
  2         247880  
  2         3898  
9              
10             our $VERSION = '0.02';
11              
12             sub new {
13 6     6 1 10822 my $class = shift;
14 6 50       25 my $rules = ref( $_[0] ) ? shift : [@_];
15 6         29 my $self = bless { _rules => [] }, $class;
16 6         25 $self->add($_) for @$rules;
17 6         34 return $self;
18             }
19              
20             my $debug = $ENV{PERL_DEBUG} || 0;
21              
22             my $FileRuleRegEx
23             = qr/^(filename|pathname|dirname|directory)\ +(contains|is|regex)\ +(.+)/io;
24              
25             sub add {
26 6     6 1 9 my $self = shift;
27 6 50       18 my $str = shift or croak "rule string required";
28              
29             # parse
30 6         77 my ( $type, $action, $re ) = ( $str =~ m/$FileRuleRegEx/ );
31 6 50 33     41 if ( !$type or !$action or !$re ) {
      33        
32 0         0 croak "Bad syntax in FileRule: $str";
33             }
34 6 100 100     35 if ( $action eq 'regex' or $type eq 'directory' ) {
35 2         215 eval "\$re = qr$re"; # TODO dangerous?
36             }
37              
38             # unclear from swish-e docs whether this is true or not,
39             # but we are conservative.
40 6 50 66     31 if ( $type eq 'directory' and $action ne 'contains' ) {
41 0         0 croak "Rule for 'directory' may only have 'contains' action.";
42             }
43              
44 6         22 my $rule = {
45             type => $type,
46             action => $action,
47             re => $re,
48             };
49              
50 6         9 push @{ $self->{_rules} }, $rule;
  6         23  
51              
52 6         18 return $rule;
53             }
54              
55             sub rules {
56 0     0 1 0 my $self = shift;
57 0 0       0 if (@_) {
58 0 0       0 $self->{_rules} = ref( $_[0] ) ? shift : [@_];
59             }
60 0         0 return $self->{_rules};
61             }
62              
63             sub match {
64 6     6 1 10 my $self = shift;
65 6 50       17 my $file = shift or croak "file required";
66 6 100       127 if ( -d $file ) {
67 3         25 return $self->match_dir( $file, { strict => 1 } );
68             }
69             else {
70 3         29 return $self->match_file( $file, { strict => 1 } );
71             }
72             }
73              
74             sub match_dir {
75 3     3 1 4 my $self = shift;
76 3 50       9 my $dir = shift or croak "dir required";
77 3   50     7 my $opts = shift || {};
78              
79 3 50 33     50 if ( $opts->{strict} and !-d $dir ) {
80 0         0 return 0;
81             }
82              
83 3         5 my $rules = $self->{_rules};
84              
85 3 50       8 $debug and warn "match_dir $dir: " . dump($rules) . "\n";
86              
87 3         6 for my $rule (@$rules) {
88 3 50       10 next if $rule->{type} eq 'filename';
89 3         8 my $method = '_apply_' . $rule->{type} . '_rule';
90 3 50       15 return 1 if $self->$method( $dir, $rule, 1 );
91             }
92              
93 0         0 return 0;
94             }
95              
96             sub match_file {
97 3     3 1 5 my $self = shift;
98 3 50       9 my $file = shift or croak "file required";
99 3   50     8 my $opts = shift || {};
100              
101 3 50 33     61 if ( $opts->{strict} and -d $file ) {
102 0         0 return 0;
103             }
104              
105 3         6 my $rules = $self->{_rules};
106              
107 3 50       11 $debug and warn "match_file $file: " . dump($rules) . "\n";
108              
109 3         7 for my $rule (@$rules) {
110 3         9 my $method = '_apply_' . $rule->{type} . '_rule';
111 3 50       14 return 1 if $self->$method( $file, $rule );
112             }
113              
114 0         0 return 0;
115             }
116              
117             sub _apply_filename_rule {
118 1     1   2 my ( $self, $file, $rule ) = @_;
119 1         2 my $match = 0;
120 1         30 my ( $volume, $dirname, $filename ) = File::Spec->splitpath($file);
121              
122 1 50       5 $debug and warn dump($rule) . "\n";
123 1 50       3 $debug and warn "dirname=$dirname filename=$filename\n";
124              
125 1 50       6 if ( $rule->{action} eq 'is' ) {
    0          
    0          
126 1 50       4 $match = $rule->{re} eq $filename ? 1 : 0;
127             }
128             elsif ( $rule->{action} eq 'contains' ) {
129 0 0       0 if ( $filename =~ m{$rule->{re}} ) {
130 0         0 $match = 1;
131             }
132             }
133             elsif ( $rule->{action} eq 'regex' ) {
134 0         0 my $regex = $rule->{re};
135 0 0       0 if ( $filename =~ m{$regex} ) {
136 0         0 $match = 1;
137             }
138             }
139              
140             $debug
141 1 50       23 and warn "_apply_filename_rule for $file returns $match : "
142             . dump($rule) . "\n";
143              
144 1         31 return $match;
145             }
146              
147             sub _apply_dirname_rule {
148 2     2   5 my ( $self, $file, $rule, $is_dir ) = @_;
149 2         4 my $match = 0;
150 2         25 my ( $volume, $dirname, $filename ) = File::Spec->splitpath($file);
151              
152 2 50       6 $debug and warn dump($rule) . "\n";
153 2 50       6 $debug and warn "dirname=$dirname filename=$filename\n";
154              
155 2 100       13 if ( $rule->{action} eq 'is' ) {
    50          
    50          
156 1 50       10 $match = grep { $rule->{re} eq $_ }
  3         9  
157             File::Spec->splitdir( $is_dir ? $file : $dirname );
158             }
159             elsif ( $rule->{action} eq 'contains' ) {
160 0 0       0 if ( $dirname =~ m{$rule->{re}} ) {
161 0         0 $match = 1;
162             }
163             }
164             elsif ( $rule->{action} eq 'regex' ) {
165 1         2 my $regex = $rule->{re};
166 1 50       7 if ( $dirname =~ m{$regex} ) {
167 1         2 $match = 1;
168             }
169             }
170              
171             $debug
172 2 50       6 and warn "_apply_dirname_rule for $file returns $match : "
173             . dump($rule) . "\n";
174              
175 2         16 return $match;
176             }
177              
178             sub _apply_pathname_rule {
179 2     2   5 my ( $self, $file, $rule ) = @_;
180 2         4 my $match = 0;
181              
182 2         1245 my ( $volume, $dirname, $filename ) = File::Spec->splitpath($file);
183              
184 2 50       10 $debug and warn dump($rule) . "\n";
185 2 50       5 $debug and warn "dirname=$dirname filename=$filename\n";
186              
187 2 50       14 if ( $rule->{action} eq 'is' ) {
    50          
    0          
188 0         0 $match = $rule->{re} eq $file;
189             }
190             elsif ( $rule->{action} eq 'contains' ) {
191 2 50       35 if ( $file =~ m{$rule->{re}} ) {
192 2         5 $match = 1;
193             }
194             }
195             elsif ( $rule->{action} eq 'regex' ) {
196 0         0 my $regex = $rule->{re};
197 0 0       0 if ( $file =~ m{$regex} ) {
198 0         0 $match = 1;
199             }
200             }
201              
202             $debug
203 2 50       6 and warn "_apply_pathname_rule for $file returns $match : "
204             . dump($rule) . "\n";
205              
206 2         19 return $match;
207             }
208              
209             sub _apply_directory_rule {
210 1     1   2 my ( $self, $dir, $rule ) = @_;
211 1         3 my $match = 0;
212 1         2 my $re = $rule->{re};
213 1         9 $dir = Path::Class::Dir->new($dir);
214 1         193 while ( my $file = $dir->next ) {
215 3 100       848 if ( $file =~ m/$re/ ) {
216 1         32 $match = $file;
217 1         3 last;
218             }
219             }
220              
221             $debug
222 1 50       5 and warn "_apply_directory_rule for $dir returns $match : "
223             . dump($rule) . "\n";
224              
225 1         6 return $match;
226             }
227              
228             1;
229              
230             __END__