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 58     58   15622 use 5.008;
  58         120  
3 58     58   209 use strict;
  58         69  
  58         2272  
4 58     58   175 use warnings;
  58         678  
  58         3838  
5              
6             our $VERSION = '1.69';
7              
8 58     58   195 use Carp;
  58         605  
  58         2753  
9 58     58   758 use Data::Dumper;
  58         6687  
  58         1770  
10 58     58   650 use Devel::Examine::Subs;
  58         73  
  58         1130  
11 58     58   19169 use Devel::Examine::Subs::Sub;
  58         145  
  58         1241  
12 58     58   21261 use File::Copy;
  58         81874  
  58         4897  
13              
14             BEGIN {
15              
16             # we need to do some trickery for DTS due to circular referencing,
17             # which broke CPAN installs.
18              
19 58     58   85 eval {
20 58         8858 require Devel::Trace::Subs;
21             };
22              
23 58         143 eval {
24 58         167 import Devel::Trace::Subs qw(trace);
25             };
26              
27 58 50       202 if (! defined &trace){
28 58     8   76558 *trace = sub {};
29             }
30             };
31              
32             sub new {
33            
34 209 100   209 0 2018 trace() if $ENV{TRACE};
35              
36 208         381 my $self = {};
37 208         363 bless $self, shift;
38              
39 208         626 $self->{engines} = $self->_dt;
40              
41 208         411 return $self;
42             }
43             sub _dt {
44            
45 213 100   213   1313 trace() if $ENV{TRACE};
46              
47 212         258 my $self = shift;
48              
49 212         2115 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 212         600 return $dt;
63             }
64             sub exists {
65            
66 204 100   204 1 1231 trace() if $ENV{TRACE};
67              
68 203         249 my $self = shift;
69 203         259 my $string = shift;
70              
71 203 100       491 if (exists $self->{engines}{$string}){
72 201         639 return 1;
73             }
74             else {
75 2         11 return 0;
76             }
77             }
78             sub _test {
79            
80 5 100   5   740 trace() if $ENV{TRACE};
81              
82             return sub {
83 4 50   4   1816 trace() if $ENV{TRACE};
84 4         15 return {a => 1};
85 4         23 };
86             }
87             sub all {
88            
89 99 100   99 1 956 trace() if $ENV{TRACE};
90              
91             return sub {
92            
93 97 50   97   239 trace() if $ENV{TRACE};
94              
95 97         124 my $p = shift;
96 97         119 my $struct = shift;
97              
98 97         155 my $file = $p->{file};
99              
100 97         113 my @subs;
101              
102 97         85 for my $name (@{ $p->{order} }){
  97         261  
103 513         342 push @subs, grep {$name eq $_} keys %{ $struct->{$file}{subs} };
  5667         4596  
  513         1035  
104             }
105              
106 97         219 return \@subs;
107 98         597 };
108             }
109             sub has {
110            
111 48 100   48 1 842 trace() if $ENV{TRACE};
112              
113             return sub {
114            
115 46 100   46   99 trace() if $ENV{TRACE};
116            
117 46         65 my $p = shift;
118 46         51 my $struct = shift;
119              
120 46 50       85 return [] if ! $struct;
121              
122 46         121 my $file = (keys %$struct)[0];
123              
124 46         60 my @has = keys %{$struct->{$file}{subs}};
  46         177  
125              
126 46   50     161 return \@has || [];
127 47         243 };
128             }
129             sub missing {
130            
131 14 100   14 1 411 trace() if $ENV{TRACE};
132              
133             return sub {
134            
135 12 50   12   33 trace() if $ENV{TRACE};
136              
137 12         12 my $p = shift;
138 12         16 my $struct = shift;
139              
140 12         13 my $file = $p->{file};
141 12         23 my $search = $p->{search};
142              
143 12 100 100     51 if ($search && ! $p->{regex}){
144 1         3 $search = "\Q$search";
145             }
146            
147 12 100       34 return [] if not $search;
148              
149 10         8 my @missing;
150              
151 10         38 for my $file (keys %$struct){
152 10         11 for my $sub (keys %{$struct->{$file}{subs}}){
  10         44  
153 104         75 my @code = @{$struct->{$file}{subs}{$sub}{code}};
  104         181  
154              
155 104         68 my @clean;
156              
157 104         92 for (@code){
158 515 100       629 push @clean, $_ if $_;
159             }
160              
161 104 100       79 if (! grep {/$search/ and $_} @clean){
  497 100       995  
162 69         105 push @missing, $sub;
163             }
164             }
165             }
166 10         20 return \@missing;
167 13         98 };
168             }
169             sub lines {
170            
171 9 100   9 1 829 trace() if $ENV{TRACE};
172              
173             return sub {
174            
175 7 50   7   23 trace() if $ENV{TRACE};
176            
177 7         12 my $p = shift;
178 7         12 my $struct = shift;
179              
180 7         78 my %return;
181              
182 7         22 for my $file (keys %$struct){
183 7         18 for my $sub (keys %{$struct->{$file}{subs}}){
  7         27  
184 47         45 my $line_num = $struct->{$file}{subs}{$sub}{start};
185 47         33 my @code = @{$struct->{$file}{subs}{$sub}{code}};
  47         146  
186 47         46 for my $line (@code){
187 135         81 $line_num++;
188 135         117 push @{$return{$sub}}, {$line_num => $line};
  135         269  
189             }
190             }
191             }
192 7         18 return \%return;
193 8         58 };
194             }
195             sub objects {
196            
197 22 100   22 1 770 trace() if $ENV{TRACE};
198              
199             # uses 'subs' post_processor
200              
201             return sub {
202            
203 20 50   20   46 trace() if $ENV{TRACE};
204              
205 20         33 my $p = shift;
206 20         22 my $struct = shift;
207              
208              
209 20 50       66 return if not ref($struct) eq 'ARRAY';
210              
211 20         41 my $file = $p->{file};
212              
213 20         19 my $lines;
214              
215 20         24 my ($des_sub, %obj_hash, @obj_array);
216              
217 20         38 for my $sub (@$struct){
218              
219             $des_sub
220 183         388 = Devel::Examine::Subs::Sub->new($sub, $sub->{name});
221              
222 183 100       264 if ($p->{objects_in_hash}){
223 70         88 $obj_hash{$sub->{name}} = $des_sub;
224             }
225             else {
226 113         115 push @obj_array, $des_sub;
227             }
228             }
229              
230 20 100       44 if ($p->{objects_in_hash}){
231 10         26 return \%obj_hash;
232             }
233             else {
234 10         33 return \@obj_array;
235             }
236 21         137 };
237             }
238             sub search_replace {
239              
240 8 100   8 1 753 trace() if $ENV{TRACE};
241              
242             return sub {
243              
244 6 50   6   13 trace() if $ENV{TRACE};
245              
246 6         6 my $p = shift;
247 6         7 my $struct = shift;
248              
249 6         8 my $file = $p->{file};
250 6         6 my $exec = $p->{exec};
251              
252 6         5 my @file_contents;
253              
254 6 100       11 if ($p->{file_contents}) {
255 5         6 @file_contents = @{ $p->{file_contents} };
  5         33  
256             }
257              
258 6 100       11 if (! $file){
259 1         168 confess "\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     23 if (! $exec || ref($exec) ne 'CODE'){
266 2         344 confess "\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         4 my @changed_lines;
273            
274 3         6 for my $sub (@$struct){
275              
276 33         54 my $start_line = $sub->start;
277 33         44 my $end_line = $sub->end;
278              
279 33         25 my $line_num = 0;
280              
281 33         32 for my $line (@file_contents){
282              
283 1080         587 $line_num++;
284              
285 1080 100       1370 if ($line_num < $start_line){
286 885         585 next;
287             }
288 195 100       206 if ($line_num > $end_line){
289 30         30 last;
290             }
291              
292 165         106 my $orig = $line;
293              
294 165         175 my $replaced = $exec->($line);
295              
296 165 100       411 if ($replaced) {
297 15         26 push @changed_lines, [$orig, $line];
298             }
299             }
300             }
301              
302 3         6 $p->{write_file_contents} = \@file_contents;
303              
304 3         7 return \@changed_lines;
305 7         43 };
306             }
307             sub inject_after {
308            
309 12 100   12 1 738 trace() if $ENV{TRACE};
310              
311             return sub {
312            
313 10 50   10   25 trace() if $ENV{TRACE};
314              
315 10         12 my $p = shift;
316 10         9 my $struct = shift;
317              
318 10         11 my $search = $p->{search};
319              
320 10 100 100     41 if ($search && !$p->{regex}) {
321 1         3 $search = "\Q$search";
322             }
323              
324 10         13 my $code = $p->{code};
325              
326 10 100       19 if (!$search) {
327 1         206 confess "\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       60 if (!$code) {
332 1         249 confess "\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         12 my $file = $p->{file};
338 8         12 my @file_contents = @{$p->{file_contents}};
  8         47  
339              
340 8         11 my @processed;
341              
342 8         8 my $added_lines = 0;
343              
344 8         8 my @subs;
345              
346 8         14 for my $sub (@$struct) {
347 20         40 push @subs, $sub->name;
348             }
349              
350 8         47 my $des = Devel::Examine::Subs->new(file => $p->{file});
351 8         31 my $subs_hash = $des->objects(objects_in_hash => 1, include => \@subs);
352              
353             my @sorted_subs = sort {
354 8         32 $subs_hash->{$a}->start <=> $subs_hash->{$b}->start
  26         47  
355             } keys %$subs_hash;
356              
357 8         37 for (@sorted_subs){
358              
359 20         27 my $sub = $subs_hash->{$_};
360              
361 20 100       36 my $num_injects = defined $p->{injects} ? $p->{injects} : 1;
362              
363 20         46 push @processed, $sub->name;
364              
365 20         37 my $start_line = $sub->start;
366 20         42 my $end_line = $sub->end;
367              
368 20         19 $start_line += $added_lines;
369 20         13 $end_line += $added_lines;
370              
371 20         22 my $line_num = 0;
372 20         13 my $new_lines = 0; # don't search added lines
373              
374 20         25 for my $line (@file_contents){
375 754         425 $line_num++;
376 754 100       775 if ($line_num < $start_line){
377 670         499 next;
378             }
379 84 100       96 if ($line_num > $end_line){
380 1         3 last;
381             }
382              
383 83 100 66     249 if ($line =~ /$search/ && ! $new_lines){
384              
385 24         21 my $location = $line_num;
386              
387 24         18 my $indent = '';
388              
389 24 50       42 if (! $p->{no_indent}){
390 24 50 33     140 if ($line =~ /^(\s+)/ && $1){
391 24         31 $indent = $1;
392             }
393             }
394 24         35 for (@$code){
395 39         70 splice @file_contents, $location++, 0, $indent . $_;
396 39         33 $new_lines++;
397 39         40 $added_lines++;
398             }
399              
400             # stop injecting after N search finds
401              
402 24         19 $num_injects--;
403 24 100       42 if ($num_injects == 0){
404 19         27 last;
405             }
406              
407             }
408 64 100       91 $new_lines-- if $new_lines != 0;
409             }
410             }
411 8         16 $p->{write_file_contents} = \@file_contents;
412 8         165 return \@processed;
413 11         78 };
414             }
415 1     1   2 sub _vim_placeholder {1;}
416             1;
417              
418             __END__