File Coverage

blib/lib/Devel/Examine/Subs/Engine.pm
Criterion Covered Total %
statement 218 218 100.0
branch 82 94 87.2
condition 12 17 70.5
subroutine 30 30 100.0
pod 8 9 88.8
total 350 368 95.1


line stmt bran cond sub pod time code
1             package Devel::Examine::Subs::Engine;
2 57     57   22581 use 5.008;
  57         187  
3 57     57   287 use strict;
  57         104  
  57         1373  
4 57     57   288 use warnings;
  57         107  
  57         3302  
5              
6             our $VERSION = '1.61';
7              
8 57     57   305 use Carp;
  57         107  
  57         3575  
9 57     57   1266 use Data::Dumper;
  57         10259  
  57         2278  
10 57     57   3229 use Devel::Examine::Subs;
  57         1309  
  57         4943  
11 57     57   30300 use Devel::Examine::Subs::Sub;
  57         197  
  57         1550  
12 57     57   39940 use File::Copy;
  57         122082  
  57         6360  
13              
14             BEGIN {
15              
16             # we need to do some trickery for DTS due to circular referencing,
17             # which broke CPAN installs.
18              
19 57     57   118 eval {
20 57         19427 require Devel::Trace::Subs;
21             };
22              
23 57         218 eval {
24 57         310 import Devel::Trace::Subs qw(trace);
25             };
26              
27 57 50       329 if (! defined &trace){
28 57     8   120216 *trace = sub {};
29             }
30             };
31              
32             sub new {
33            
34 195 100   195 0 2268 trace() if $ENV{TRACE};
35              
36 194         399 my $self = {};
37 194         462 bless $self, shift;
38              
39 194         730 $self->{engines} = $self->_dt;
40              
41 194         541 return $self;
42             }
43             sub _dt {
44            
45 199 100   199   1710 trace() if $ENV{TRACE};
46              
47 198         353 my $self = shift;
48              
49 198         2502 my $dt = {
50             all => \&all,
51             has => \&has,
52             missing => \&missing,
53             lines => \&lines,
54             objects => \&objects,
55             search_replace => \&search_replace,
56             inject_after => \&inject_after,
57             dt_test => \&dt_test,
58             _test => \&_test,
59             _test_bad => \&_test_bad,
60             };
61              
62 198         843 return $dt;
63             }
64             sub exists {
65            
66 190 100   190 1 1617 trace() if $ENV{TRACE};
67              
68 189         327 my $self = shift;
69 189         314 my $string = shift;
70              
71 189 100       649 if (exists $self->{engines}{$string}){
72 187         827 return 1;
73             }
74             else {
75 2         14 return 0;
76             }
77             }
78             sub _test {
79            
80 5 100   5   936 trace() if $ENV{TRACE};
81              
82             return sub {
83 4 50   4   1554 trace() if $ENV{TRACE};
84 4         16 return {a => 1};
85 4         29 };
86             }
87             sub all {
88            
89 90 100   90 1 1180 trace() if $ENV{TRACE};
90              
91             return sub {
92            
93 88 50   88   268 trace() if $ENV{TRACE};
94              
95 88         144 my $p = shift;
96 88         145 my $struct = shift;
97              
98 88         214 my $file = $p->{file};
99              
100 88         129 my @subs;
101              
102 88         155 for my $name (@{ $p->{order} }){
  88         263  
103 421         540 push @subs, grep {$name eq $_} keys %{ $struct->{$file}{subs} };
  3677         6431  
  421         1399  
104             }
105              
106 88         278 return \@subs;
107 89         637 };
108             }
109             sub has {
110            
111 46 100   46 1 1068 trace() if $ENV{TRACE};
112              
113             return sub {
114            
115 44 100   44   129 trace() if $ENV{TRACE};
116            
117 44         67 my $p = shift;
118 44         77 my $struct = shift;
119              
120 44 50       124 return [] if ! $struct;
121              
122 44         179 my $file = (keys %$struct)[0];
123              
124 44         80 my @has = keys %{$struct->{$file}{subs}};
  44         221  
125              
126 44   50     219 return \@has || [];
127 45         279 };
128             }
129             sub missing {
130            
131 13 100   13 1 486 trace() if $ENV{TRACE};
132              
133             return sub {
134            
135 11 50   11   30 trace() if $ENV{TRACE};
136              
137 11         17 my $p = shift;
138 11         16 my $struct = shift;
139              
140 11         21 my $file = $p->{file};
141 11         19 my $search = $p->{search};
142              
143 11 100 100     53 if ($search && ! $p->{regex}){
144 1         3 $search = "\Q$search";
145             }
146            
147 11 100       31 return [] if not $search;
148              
149 9         12 my @missing;
150              
151 9         28 for my $file (keys %$struct){
152 9         17 for my $sub (keys %{$struct->{$file}{subs}}){
  9         45  
153 99         118 my @code = @{$struct->{$file}{subs}{$sub}{code}};
  99         302  
154              
155 99         135 my @clean;
156              
157 99         161 for (@code){
158 495 100       1194 push @clean, $_ if $_;
159             }
160              
161 99 100       146 if (! grep {/$search/ and $_} @clean){
  477 100       1702  
162 69         212 push @missing, $sub;
163             }
164             }
165             }
166 9         29 return \@missing;
167 12         94 };
168             }
169             sub lines {
170            
171 9 100   9 1 957 trace() if $ENV{TRACE};
172              
173             return sub {
174            
175 7 50   7   24 trace() if $ENV{TRACE};
176            
177 7         13 my $p = shift;
178 7         13 my $struct = shift;
179              
180 7         11 my %return;
181              
182 7         24 for my $file (keys %$struct){
183 7         13 for my $sub (keys %{$struct->{$file}{subs}}){
  7         28  
184 47         84 my $line_num = $struct->{$file}{subs}{$sub}{start};
185 47         287 my @code = @{$struct->{$file}{subs}{$sub}{code}};
  47         119  
186 47         89 for my $line (@code){
187 135         160 $line_num++;
188 135         142 push @{$return{$sub}}, {$line_num => $line};
  135         450  
189             }
190             }
191             }
192 7         24 return \%return;
193 8         68 };
194             }
195             sub objects {
196            
197 20 100   20 1 973 trace() if $ENV{TRACE};
198              
199             # uses 'subs' post_processor
200              
201             return sub {
202            
203 18 50   18   53 trace() if $ENV{TRACE};
204              
205 18         29 my $p = shift;
206 18         29 my $struct = shift;
207              
208              
209 18 50       72 return if not ref($struct) eq 'ARRAY';
210              
211 18         38 my $file = $p->{file};
212              
213 18         28 my $lines;
214              
215 18         29 my ($des_sub, %obj_hash, @obj_array);
216              
217 18         41 for my $sub (@$struct){
218              
219             $des_sub
220 174         593 = Devel::Examine::Subs::Sub->new($sub, $sub->{name});
221              
222 174 100       372 if ($p->{objects_in_hash}){
223 69         166 $obj_hash{$sub->{name}} = $des_sub;
224             }
225             else {
226 105         205 push @obj_array, $des_sub;
227             }
228             }
229              
230 18 100       45 if ($p->{objects_in_hash}){
231 10         38 return \%obj_hash;
232             }
233             else {
234 8         33 return \@obj_array;
235             }
236 19         133 };
237             }
238             sub search_replace {
239              
240 8 100   8 1 954 trace() if $ENV{TRACE};
241              
242             return sub {
243              
244 6 50   6   18 trace() if $ENV{TRACE};
245              
246 6         11 my $p = shift;
247 6         10 my $struct = shift;
248              
249 6         12 my $file = $p->{file};
250 6         23 my $exec = $p->{exec};
251              
252 6         9 my @file_contents;
253              
254 6 100       18 if ($p->{file_contents}) {
255 5         10 @file_contents = @{ $p->{file_contents} };
  5         51  
256             }
257              
258 6 100       21 if (! $file){
259 1         173 croak "\nDevel::Examine::Subs::Engine::search_replace " .
260             "speaking:\n" .
261             "can't use search_replace engine without specifying a " .
262             "file\n\n";
263             }
264              
265 5 100 66     31 if (! $exec || ref($exec) ne 'CODE'){
266 2         426 croak "\nDevel::Examine::Subs::Engine::search_replace " .
267             " speaking:\n" .
268             "can't use search_replace engine without specifying" .
269             "a substitution regex code reference\n\n";
270             }
271              
272 3         6 my @changed_lines;
273            
274 3         8 for my $sub (@$struct){
275              
276 33         225 my $start_line = $sub->start;
277 33         88 my $end_line = $sub->end;
278              
279 33         38 my $line_num = 0;
280              
281 33         51 for my $line (@file_contents){
282              
283 1080         1099 $line_num++;
284              
285 1080 100       2030 if ($line_num < $start_line){
286 885         1106 next;
287             }
288 195 100       406 if ($line_num > $end_line){
289 30         51 last;
290             }
291              
292 165         212 my $orig = $line;
293              
294 165         328 my $replaced = $exec->($line);
295              
296 165 100       761 if ($replaced) {
297 15         44 push @changed_lines, [$orig, $line];
298             }
299             }
300             }
301              
302 3         8 $p->{write_file_contents} = \@file_contents;
303              
304 3         10 return \@changed_lines;
305 7         60 };
306             }
307             sub inject_after {
308            
309 12 100   12 1 943 trace() if $ENV{TRACE};
310              
311             return sub {
312            
313 10 50   10   29 trace() if $ENV{TRACE};
314              
315 10         13 my $p = shift;
316 10         15 my $struct = shift;
317              
318 10         25 my $search = $p->{search};
319              
320 10 100 100     128 if ($search && !$p->{regex}) {
321 1         3 $search = "\Q$search";
322             }
323              
324 10         42 my $code = $p->{code};
325              
326 10 100       124 if (!$search) {
327 1         181 croak "\nDevel::Examine::Subs::Engine::inject_after speaking:\n" .
328             "can't use inject_after engine without specifying a " .
329             "search term\n\n";
330             }
331 9 100       22 if (!$code) {
332 1         241 croak "\nDevel::Examine::Subs::Engine::inject_after speaking:\n" .
333             "can't use inject_after engine without code to inject\n\n";
334              
335             }
336              
337 8         18 my $file = $p->{file};
338 8         11 my @file_contents = @{$p->{file_contents}};
  8         64  
339              
340 8         11 my @processed;
341              
342 8         15 my $added_lines = 0;
343              
344 8         10 my @subs;
345              
346 8         19 for my $sub (@$struct) {
347 20         62 push @subs, $sub->name;
348             }
349              
350 8         60 my $des = Devel::Examine::Subs->new(file => $p->{file});
351 8         44 my $subs_hash = $des->objects(objects_in_hash => 1, include => \@subs);
352              
353             my @sorted_subs = sort {
354 8         50 $subs_hash->{$a}->start <=> $subs_hash->{$b}->start
  25         69  
355             } keys %$subs_hash;
356              
357 8         25 for (@sorted_subs){
358              
359 20         38 my $sub = $subs_hash->{$_};
360              
361 20 100       51 my $num_injects = defined $p->{injects} ? $p->{injects} : 1;
362              
363 20         72 push @processed, $sub->name;
364              
365 20         60 my $start_line = $sub->start;
366 20         56 my $end_line = $sub->end;
367              
368 20         29 $start_line += $added_lines;
369 20         22 $end_line += $added_lines;
370              
371 20         22 my $line_num = 0;
372 20         29 my $new_lines = 0; # don't search added lines
373              
374 20         31 for my $line (@file_contents){
375 754         723 $line_num++;
376 754 100       1380 if ($line_num < $start_line){
377 670         825 next;
378             }
379 84 100       139 if ($line_num > $end_line){
380 1         4 last;
381             }
382              
383 83 100 66     337 if ($line =~ /$search/ && ! $new_lines){
384              
385 24         31 my $location = $line_num;
386              
387 24         31 my $indent = '';
388              
389 24 50       57 if (! $p->{no_indent}){
390 24 50 33     132 if ($line =~ /^(\s+)/ && $1){
391 24         46 $indent = $1;
392             }
393             }
394 24         46 for (@$code){
395 39         102 splice @file_contents, $location++, 0, $indent . $_;
396 39         50 $new_lines++;
397 39         59 $added_lines++;
398             }
399              
400             # stop injecting after N search finds
401              
402 24         26 $num_injects--;
403 24 100       54 if ($num_injects == 0){
404 19         42 last;
405             }
406              
407             }
408 64 100       153 $new_lines-- if $new_lines != 0;
409             }
410             }
411 8         23 $p->{write_file_contents} = \@file_contents;
412 8         185 return \@processed;
413 11         108 };
414             }
415 1     1   5 sub _vim_placeholder {1;}
416             1;
417              
418             __END__