File Coverage

lib/App/GitFind/FileProcessor.pm
Criterion Covered Total %
statement 20 78 25.6
branch 0 24 0.0
condition 0 3 0.0
subroutine 7 18 38.8
pod 7 7 100.0
total 34 130 26.1


line stmt bran cond sub pod time code
1             package App::GitFind::FileProcessor;
2              
3 2     2   1100 use 5.010;
  2         6  
4 2     2   8 use strict;
  2         3  
  2         340  
5 2     2   12 use warnings;
  2         4  
  2         87  
6              
7             our $VERSION = '0.000002';
8              
9 2     2   10 use parent 'App::GitFind::Class';
  2         9  
  2         11  
10 2     2   134 use Class::Tiny qw(expr searchbase);
  2         4  
  2         11  
11              
12             # Imports
13 2     2   534 use App::GitFind::Base;
  2         4  
  2         256  
14             #use App::GitFind::Actions qw(argdetails);
15             #use App::GitFind::FileStatLs ();
16 2     2   12 use File::Spec; # TODO use facilities from A::GF::PathClassMicro instead?
  2         3  
  2         1879  
17             #use Git::Raw;
18              
19             # === Documentation === {{{1
20              
21             =head1 NAME
22              
23             App::GitFind::FileProcessor - Test a file against a set of criteria
24              
25             =head1 SYNOPSIS
26              
27             my $hrArgs = App::GitFind::cmdline::Parse(\@ARGV);
28             my $runner = App::GitFind::FileProcessor->new(-expr => $hrArgs->{expr});
29             $runner->process($some_entry_or_other);
30              
31             =cut
32              
33             # }}}1
34             # === Main interpreter === {{{1
35              
36             =head2 process
37              
38             Process a single file, represented as an L<App::GitFind::Entry> instance.
39             Returns the Boolean result of the expression. Note that the specific
40             exit codes from C<-exec> and similar actions are lost. Usage:
41              
42             $runner->process([-entry=>]$entry);
43              
44             =cut
45              
46             sub process {
47 0     0 1   my ($self, %args) = getparameters('self',[qw(entry)], @_);
48 0           @_ = ($self, $args{entry}, $self->expr);
49 0           goto &_process;
50             } #process()
51              
52             # Internal: $self->_process($entry, $expr). Called recursively to
53             # handle subexpressions.
54             sub _process {
55 0     0     my ($self, $entry, $expr) = @_;
56 0           my $func; # What will handle the expression
57             my @arg; # Args to $func
58              
59 0     0     vlog { Processing => ddc($expr) } 3;
  0            
60              
61 0 0         die "Invalid expression: " . ddc($expr) unless ref $expr eq 'HASH';
62              
63 0 0         if($expr->{code}) { # Basic elements
64 0           $func = $expr->{code};
65 0           @arg = $entry;
66 0 0         push @arg, @{$expr->{params}} if $expr->{params};
  0            
67              
68             } else { # SEQ, AND, OR, NOT
69             die "Logical expression has more than one key: " . ddc($expr)
70 0 0         if scalar keys %{$expr} > 1;
  0            
71 0           my $operation = (keys %{$expr})[0];
  0            
72 0           $func = $self->can("process_$operation");
73             # TODO remove the can() check once everything is implemented
74 0           @arg = ($entry, $expr->{$operation});
75             }
76              
77 0 0         die "I don't know how to process the expression: " . ddc($expr)
78             unless $func;
79              
80 0           return $self->$func(@arg);
81             } #_process()
82              
83             =head2 callback
84              
85             Returns a callback that will process an entry. Usage:
86              
87             my $callback = $processor->callback([$log]); # Create the callback
88             $callback->($entry); # Invoke the callback
89              
90             The optional C<$log> parameter, if truthy, provides extra debug output.
91              
92             =cut
93              
94             sub callback {
95 0     0 1   my ($self, $log) = @_;
96 0           my $expr = $self->expr;
97 0 0         if($log) {
98             return sub {
99 0     0     my $entry = $_[0];
100 0           vlog { '>>>', $entry->path } 3;
  0            
101 0           my $matched = $self->_process($entry, $expr);
102 0 0         vlog { '<<<', $matched ? 'matched' : 'did not match' } 3;
  0            
103 0           return $matched;
104             }
105              
106 0           } else { # not logging
107             return sub {
108 0     0     return $self->_process(shift, $expr);
109             # Future optimization? Use goto &_process instead?
110             }
111 0           }
112             } #callback
113              
114             # }}}1
115             # === Helpers === {{{1
116              
117             =head2 dot_relative_path
118              
119             Given a path, adds C<./> or C<.\> unless it is an absolute path. This is
120             a hacked workaround for the issue noted in
121             L<https://bitbucket.org/shlomif/perl-file-find-object/issues/3/not-consistently-present-in-returned-paths>.
122              
123             =cut
124              
125             # Make a regex that will match ./ or .\ in a platform-independent way
126             my $_dotslash = File::Spec->catfile('.',''); # platform-independent ./
127             my $_ddotslash = File::Spec->catfile('..',''); # platform-independent ./
128             $_dotslash = qr{^(?:\Q$_dotslash\E|\Q$_ddotslash\E)};
129              
130             sub dot_relative_path {
131 0     0 1   my $path = $_[1]->path; # $_[1] is an Entry
132 0 0         return $path if File::Spec->file_name_is_absolute($path);
133 0 0 0       return $path if $path =~ $_dotslash || $path eq '.';
134 0           return File::Spec->catfile('.',$path);
135             } #dot_relative_path()
136              
137             # }}}1
138             # === Logical operators === {{{1
139              
140             =head2 process_NOT
141              
142             Process a negation of a single expression. Usage:
143              
144             $runner->process_NOT($entry, $expr);
145              
146             Even though the name of the parameter is C<exprs> for consistency with
147             AND, OR, and SEQ, only a single expression is allowed.
148              
149             =cut
150              
151             sub process_NOT {
152 0     0 1   my ($self, $entry, $expr) = @_;
153 0 0         croak "I can't take an array of expressions" if ref $expr eq 'ARRAY';
154              
155 0           return !$self->_process($entry, $expr);
156             } #process_NOT()
157              
158             =head2 process_AND
159              
160             Process a conjunction of expressions. Usage:
161              
162             $runner->process_AND($entry, [$expr1, ...]);
163              
164             =cut
165              
166             sub process_AND {
167 0     0 1   my ($self, $entry, $lrExprs) = @_;
168 0           my $retval;
169              
170 0           for(@$lrExprs) {
171 0           $retval = $self->_process($entry, $_);
172 0 0         last unless $retval; # Short-circuit
173             }
174 0           return $retval;
175             } #process_AND()
176              
177             =head2 process_OR
178              
179             Process a disjunction of expressions. Usage:
180              
181             $runner->process_OR($entry, [$expr1, ...]);
182              
183             =cut
184              
185             sub process_OR {
186 0     0 1   my ($self, $entry, $lrExprs) = @_;
187 0           my $retval;
188              
189 0           for(@$lrExprs) {
190 0           $retval = $self->_process($entry, $_);
191 0 0         last if $retval; # Short-circuit
192             }
193 0           return $retval;
194             } #process_OR()
195              
196             =head2 process_SEQ
197              
198             Process a sequence of expressions. Usage:
199              
200             $runner->process_SEQ($entry, [$expr1, ...]);
201              
202             =cut
203              
204             sub process_SEQ {
205 0     0 1   my ($self, $entry, $lrExprs) = @_;
206 0           my $retval;
207              
208 0           $retval = $self->_process($entry, $_) foreach @{$lrExprs};
  0            
209 0           return $retval;
210             } #process_SEQ()
211              
212             # }}}1
213              
214             1; # End of App::GitFind::FileProcessor
215             __END__
216             # === Rest of the docs === {{{1
217              
218             =head1 AUTHOR
219              
220             Christopher White, C<< <cxw at cpan.org> >>
221              
222             =head1 LICENSE AND COPYRIGHT
223              
224             Copyright 2019 Christopher White.
225             Portions copyright 2019 D3 Engineering, LLC.
226              
227             This program is distributed under the MIT (X11) License:
228             L<http://www.opensource.org/licenses/mit-license.php>
229              
230             Permission is hereby granted, free of charge, to any person
231             obtaining a copy of this software and associated documentation
232             files (the "Software"), to deal in the Software without
233             restriction, including without limitation the rights to use,
234             copy, modify, merge, publish, distribute, sublicense, and/or sell
235             copies of the Software, and to permit persons to whom the
236             Software is furnished to do so, subject to the following
237             conditions:
238              
239             The above copyright notice and this permission notice shall be
240             included in all copies or substantial portions of the Software.
241              
242             THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
243             EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
244             OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
245             NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
246             HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
247             WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
248             FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
249             OTHER DEALINGS IN THE SOFTWARE.
250              
251             =cut
252              
253             # }}}1
254             # vi: set fdm=marker fdl=0: #