File Coverage

blib/lib/File/CodeSearch/RegexBuilder.pm
Criterion Covered Total %
statement 96 96 100.0
branch 46 46 100.0
condition 3 3 100.0
subroutine 13 13 100.0
pod 6 6 100.0
total 164 164 100.0


line stmt bran cond sub pod time code
1             package File::CodeSearch::RegexBuilder;
2              
3             # Created on: 2009-08-07 18:41:21
4             # Create by: Ivan Wills
5             # $Id$
6             # $Revision$, $HeadURL$, $Date$
7             # $Revision$, $Source$, $Date$
8              
9 5     5   74656 use Moose;
  5         413134  
  5         27  
10 5     5   31284 use warnings;
  5         12  
  5         158  
11 5     5   557 use version;
  5         1733  
  5         26  
12 5     5   331 use Carp;
  5         11  
  5         302  
13 5     5   2307 use List::MoreUtils qw/any/;
  5         47636  
  5         33  
14 5     5   4614 use English qw/ -no_match_vars /;
  5         2965  
  5         34  
15              
16             our $VERSION = version->new('0.7.6');
17              
18             has regex => (
19             is => 'rw',
20             );
21             has re => (
22             is => 'ro',
23             isa => 'ArrayRef',
24             );
25             has whole => (
26             is => 'ro',
27             isa => 'Bool',
28             );
29             has all => (
30             is => 'ro',
31             isa => 'Bool',
32             );
33             has words => (
34             is => 'ro',
35             isa => 'Bool',
36             );
37             has ignore_case => (
38             is => 'ro',
39             isa => 'Bool',
40             );
41             has files => (
42             is => 'rw',
43             isa => 'HashRef',
44             default => sub{{}},
45             );
46             has current_file => (
47             is => 'rw',
48             );
49             has current_count => (
50             is => 'rw',
51             isa => 'Int',
52             default => 0,
53             );
54             has sub_matches => (
55             is => 'rw',
56             isa => 'ArrayRef[Str]',
57             default => sub{[]},
58             );
59             has sub_match => (
60             is => 'rw',
61             isa => 'Bool',
62             );
63             has sub_not_matches => (
64             is => 'rw',
65             isa => 'ArrayRef[Str]',
66             default => sub{[]},
67             );
68             has sub_not_match => (
69             is => 'rw',
70             isa => 'Bool',
71             );
72             has last => (
73             is => 'rw',
74             isa => 'ArrayRef[Str]',
75             );
76             has lasts => (
77             is => 'rw',
78             isa => 'HashRef[Str]',
79             default => sub{{}},
80             );
81             has smart => (
82             is => 'rw',
83             isa => 'Bool',
84             );
85              
86             sub make_regex {
87 4562     4562 1 23628 my ($self) = @_;
88 4562 100       108931 return $self->regex if ref $self->regex eq 'Regexp';
89              
90 33         49 my $re;
91 33         776 my $words = $self->re;
92              
93 33         50 my $start = shift @{ $words };
  33         61  
94 33 100       96 return $self->regex(qr//) if !defined $start;
95              
96 32 100   93   165 if (!any {$start eq $_} qw/n b ss/) {
  93         150  
97 29         42 unshift @{ $words }, $start;
  29         64  
98 29         49 undef $start;
99             }
100              
101 32 100       817 if ($self->whole) {
102 5         8 @{$words} = map { "\\b$_\\b" } @{$words};
  5         10  
  8         21  
  5         9  
103             }
104              
105 32 100       752 if ($self->all) {
    100          
106 4 100       9 if (@{ $words } == 2 ) {
  4         12  
107 3         11 $re = "$words->[0].*$words->[1]|$words->[1].*$words->[0]";
108             }
109             else {
110 1         3 $re = join ' ', @$words;
111             }
112             }
113             elsif ( $self->words ) {
114 2         4 $re = join '.*', @{ $words };
  2         5  
115             }
116             else {
117 26         62 $re = join ' ', @{ $words };
  26         65  
118             }
119              
120 32 100       783 if ($self->ignore_case) {
121 1         4 $re = "(?i:$re)";
122             }
123              
124             $re =
125 32 100       90 !defined $start ? $re
    100          
    100          
126             : $start eq 'n' ? "function(?:&?\\s+|\\s+&?\\s*)$re|$re\\s+=\\s+function"
127             : $start eq 'b' ? "sub\\s+$re"
128             : "class\\s+$re";
129              
130 32         1083 return $self->regex(qr/$re/);
131             }
132              
133             sub match {
134 4530     4530 1 11808 my ($self, $line) = @_;
135 4530         8345 my $re = $self->make_regex;
136              
137 4530         10177 $self->check_sub_matches($line);
138 4530         10205 $self->check_lasts($line);
139              
140 4530         14622 my ($match) = $line =~ /($re)/;
141              
142 4530 100       8273 if (defined $match) {
143 3323         82643 $self->current_count( $self->current_count + 1 );
144             }
145              
146 4530         15142 return $match;
147             }
148              
149             sub check_sub_matches {
150 4535     4535 1 9759 my ($self, $line) = @_;
151 4535         107665 my $matches = $self->sub_matches;
152 4535         5737 my $match = 0;
153 4535         109625 my $not_matches = $self->sub_not_matches;
154 4535         5989 my $not_match = 0;
155              
156 4535 100       106331 return if $self->sub_match;
157 4534 100       110508 return if $self->sub_not_match;
158              
159 4533         8420 for my $match_re (@$matches) {
160 3         21 $match = $line =~ /$match_re/;
161 3 100       8 last if $match;
162             }
163              
164 4533         107855 $self->sub_match($match);
165              
166 4533         6873 for my $not_match_re (@$not_matches) {
167 3         12 $not_match = $line =~ /$not_match_re/;
168 3 100       8 last if $not_match;
169             }
170              
171 4533         113120 $self->sub_not_match($not_match);
172              
173 4533         6183 return;
174             }
175              
176             sub check_lasts {
177 4530     4530 1 6925 my ($self, $line) = @_;
178              
179 4530 100       108864 if ($self->last) {
180 12         17 for my $last (@{ $self->last }) {
  12         282  
181 18 100       177 my ($match) =
    100          
    100          
182             $last eq 'function' ? $line =~ /function \s+ (?: & \s*)? ([\w-]+)/xms
183             : $last eq 'class' ? $line =~ /class \s+ ([\w-]+)/xms
184             : $last eq 'sub' ? $line =~ /sub \s+ ([\w-]+)/xms
185             : $line =~ /$last \s+ ([\w-]+)/xms;
186 18 100       173 $self->lasts->{$last} = $match if $match;
187             }
188             }
189              
190 4530         6220 return;
191             }
192              
193             sub get_last_found {
194 5     5 1 15 my ($self) = @_;
195 5         7 my $out = '';
196              
197 5 100       6 return '' if ! %{$self->lasts};
  5         120  
198              
199 4         15 for my $last (sort keys %{$self->lasts} ) {
  4         92  
200 6         139 $out .= "$last " . $self->lasts->{$last} . "\n";
201             }
202              
203 4         20 return $out;
204             }
205              
206             sub reset_file {
207 28     28 1 1005 my ($self, $file) = @_;
208 28 100 100     729 if ( $self->current_count() && $self->current_file ) {
209 22         588 $self->files->{$self->current_file} = $self->current_count;
210             }
211              
212 28         741 $self->sub_match(0);
213 28         738 $self->sub_not_match(0);
214 28         836 $self->current_count(0);
215 28         750 $self->current_file($file);
216 28         730 $self->lasts({});
217              
218 28         60 return;
219             }
220              
221              
222             1;
223              
224             __END__
225              
226             =head1 NAME
227              
228             File::CodeSearch::RegexBuilder - Takes in various options and builds a regular expression to check lines of a file
229              
230             =head1 VERSION
231              
232             This documentation refers to File::CodeSearch::RegexBuilder version 0.7.6.
233              
234             =head1 SYNOPSIS
235              
236             use File::CodeSearch::RegexBuilder;
237              
238             # Brief but working code example(s) here showing the most common usage(s)
239             # This section will be as far as many users bother reading, so make it as
240             # educational and exemplary as possible.
241              
242             =head1 DESCRIPTION
243              
244             =head1 ATTRIBUTES
245              
246             =over 4
247              
248             =item C<regex>
249              
250             The compiled regex
251              
252             =item C<re (ArrayRef)>
253              
254             The strings to compile the regular expression from
255              
256             =item C<whole (Bool)>
257              
258             Makes sure each element of C<re> is matched as a whole word
259              
260             =item C<all (Bool)>
261              
262             Makes sure that the elements of C<re> are matched in any order (currently only two elements supported)
263              
264             =item C<words (Bool)>
265              
266             Match each word separated by arbitrary number of characters (default separation is one space)
267              
268             =item C<ignore_case (Bool)>
269              
270             Ignore case in the final regex
271              
272             =item C<files (HashRef)>
273              
274             Stores a count of matches in each file
275              
276             =item C<current_file>
277              
278             Reference to the current file being searched
279              
280             =item C<current_count (Int)>
281              
282             The number of matches found in the currently searched file
283              
284             =item C<sub_matches (ArrayRef[Str])>
285              
286             Terms to search on that the file should also contain to be considered to have matched
287              
288             =item C<sub_match (Bool)>
289              
290             Stores if a sub match has been found
291              
292             =item C<sub_not_matches (ArrayRef[Str])>
293              
294             Terms to search on that the file should not contain to be considered to have matched
295              
296             =item C<sub_not_match (Bool)>
297              
298             Stores if a not sub match has been found
299              
300             =item C<last (ArrayRef[Str])>
301              
302             A list of types to keep track of for context of a match (eg the last function, class or sub)
303              
304             =item C<lasts (HashRef[Str])>
305              
306             The current state of requested "last" types
307              
308             =item C<smart (Bool)>
309              
310             Create smart regular expression
311              
312             =back
313              
314             =head1 SUBROUTINES/METHODS
315              
316             =head2 C<make_regex ()>
317              
318             =head2 C<match ($line)>
319              
320             =head2 C<sub_matches ($line)>
321              
322             =head2 C<reset_file ( $file )>
323              
324             Resets file based counters and adds $file as the new file being processed
325              
326             =head2 C<check_sub_matches ( $line )>
327              
328             Checks that $line matches any specified sub matches
329              
330             =head2 C<check_lasts ( $line )>
331              
332             Checks if the line matches a block start signature eg checks if we are starting
333             a sub, function or class so that any matches in that block can be identified as
334             coming from there.
335              
336             =head2 C<get_last_found ()>
337              
338             Returns the last match block
339              
340             =head1 DIAGNOSTICS
341              
342             =head1 CONFIGURATION AND ENVIRONMENT
343              
344             =head1 DEPENDENCIES
345              
346             =head1 INCOMPATIBILITIES
347              
348             =head1 BUGS AND LIMITATIONS
349              
350             There are no known bugs in this module.
351              
352             Please report problems to Ivan Wills (ivan.wills@gmail.com).
353              
354             Patches are welcome.
355              
356             =head1 AUTHOR
357              
358             Ivan Wills - (ivan.wills@gmail.com)
359              
360             =head1 LICENSE AND COPYRIGHT
361              
362             Copyright (c) 2009 Ivan Wills (14 Mullion Close, Hornsby Heights, NSW Australia 2077).
363             All rights reserved.
364              
365             This module is free software; you can redistribute it and/or modify it under
366             the same terms as Perl itself. See L<perlartistic>. This program is
367             distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
368             without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
369             PARTICULAR PURPOSE.
370              
371             =cut