File Coverage

blib/lib/Devel/Examine/Subs/Preprocessor.pm
Criterion Covered Total %
statement 146 146 100.0
branch 58 64 90.6
condition 4 6 66.6
subroutine 21 21 100.0
pod 4 6 66.6
total 233 243 95.8


line stmt bran cond sub pod time code
1             package Devel::Examine::Subs::Preprocessor;
2 58     58   858 use 5.008;
  58         125  
3 58     58   190 use strict;
  58         65  
  58         991  
4 58     58   158 use warnings;
  58         57  
  58         1977  
5              
6             our $VERSION = '1.69';
7              
8 58     58   213 use Carp;
  58         82  
  58         2880  
9 58     58   207 use Data::Dumper;
  58         60  
  58         2149  
10 58     58   19557 use Symbol qw(delete_package);
  58         29218  
  58         5768  
11              
12             BEGIN {
13              
14             # we need to do some trickery for DTS due to circular referencing,
15             # which broke CPAN installs.
16              
17 58     58   108 eval {
18 58         8547 require Devel::Trace::Subs;
19             };
20              
21 58         143 eval {
22 58         258 import Devel::Trace::Subs qw(trace);
23             };
24              
25 58 50       262 if (! defined &trace){
26 58     62   9798 *trace = sub {};
27             }
28             };
29              
30             sub new {
31              
32 52 100   52 0 1393 trace() if $ENV{TRACE};
33              
34 51         79 my $self = {};
35 51         68 bless $self, shift;
36              
37 51         53 my $struct = shift;
38              
39 51         100 $self->{pre_procs} = $self->_dt;
40              
41 51         89 return $self;
42             }
43             sub _dt {
44              
45 55 100   55   956 trace() if $ENV{TRACE};
46              
47 54         85 my $self = shift;
48              
49 54         264 my $dt = {
50             module => \&module,
51             inject => \&inject,
52             remove => \&remove,
53             replace => \&replace,
54             _test_bad => \&test_bad,
55             };
56              
57 54         146 return $dt;
58             }
59             sub exists {
60              
61 49 100   49 1 876 trace() if $ENV{TRACE};
62              
63 48         54 my $self = shift;
64 48         53 my $string = shift;
65              
66 48 100       107 if (exists $self->{pre_procs}{$string}){
67 46         120 return 1;
68             }
69             else {
70 2         10 return 0;
71             }
72             }
73             sub module {
74              
75 13 100   13 1 769 trace() if $ENV{TRACE};
76              
77             return sub {
78 11 100   11   30 trace() if $ENV{TRACE};
79              
80 58     58   223 no strict 'refs';
  58         49  
  58         47599  
81              
82 11         9 my $p = shift;
83              
84 11 100 66     38 if (! $p->{module} or $p->{module} eq '') {
85 3         5 return [];
86             }
87              
88 8         26 (my $module_file = $p->{module}) =~ s|::|/|g;
89 8         8 $module_file .= '.pm';
90              
91 8         12 my $module_is_loaded = 0;
92              
93 8 100       18 if (! $INC{$module_file}){
94 4         4 eval {
95 4         749 require "$module_file";
96             };
97              
98 4 100       290 if ($@) {
99 1         11 die "Problem loading $p->{module}: $@";
100             }
101             }
102             else {
103 4         5 $module_is_loaded = 1;
104             }
105              
106 7         15 my $namespace = "$p->{module}::";
107              
108 7         5 my @subs;
109              
110 7         61 for my $sub (keys %$namespace){
111 222 100       127 if (defined &{$namespace . $sub}){
  222         405  
112 187         164 push @subs, $sub;
113             }
114             }
115              
116 7 100       20 if (! $module_is_loaded){
117 3         12 delete_package($p->{module});
118 3         156 delete $INC{$module_file};
119             }
120              
121 7         16 return \@subs;
122 12         67 };
123             }
124             sub inject {
125              
126 8 100   8 1 473 trace() if $ENV{TRACE};
127              
128             return sub {
129              
130 6 50   6   15 trace() if $ENV{TRACE};
131              
132 6         7 my $p = shift;
133              
134 6         6 my @file_contents = @{ $p->{file_contents} };
  6         33  
135              
136             # after line number
137              
138 6         39 my $rw = File::Edit::Portable->new;
139              
140 6 100       39 if (defined $p->{line_num}){
    100          
    50          
141            
142             # inject after line number
143              
144             $rw->splice(
145             file => $p->{file},
146             line => $p->{line_num},
147             insert => $p->{code},
148             copy => $p->{copy},
149 2         10 );
150             }
151             elsif ($p->{inject_use}){
152            
153             # inject a use statement
154              
155 1         4 my $use = qr/use\s+\w+/;
156            
157 1         1 my $index;
158              
159             ($index) = grep {
160 1         3 $file_contents[$_] =~ $use
  51         64  
161             } 0..$#file_contents;
162              
163 1 50       4 if (!$index) {
164             ($index) = grep {
165 1         3 $file_contents[$_] =~ /^package\s+\w+/
  51         42  
166             } 0..$#file_contents;
167 1         2 $index++;
168             }
169              
170 1 50       3 if ($index) {
171             $rw->splice(
172             file => $p->{file},
173             line => $index,
174             insert => $p->{inject_use},
175             copy => $p->{copy},
176 1         5 );
177             }
178             }
179             elsif ($p->{inject_after_sub_def}){
180              
181             # inject code after sub definition
182              
183 3         5 my $code = $p->{inject_after_sub_def};
184              
185 3         3 my @new_file;
186              
187 3         10 my $single_line = qr/
188             sub\s+\w+\s*(?:\(.*?\)\s+)?\{\s*(?!\s*[\S])
189             |
190             sub\s+\{\s*(?!\s*[\S])
191             /x;
192              
193 3         7 my $multi_line = qr/sub\s+\w+\s*(?![\S])/;
194              
195 3         3 my $is_multi = 0;
196              
197 3         5 my $i = -1;
198              
199 3         4 for my $e (@file_contents){
200              
201 81         59 $i++;
202              
203 81         55 my $indent = '';
204              
205 81         51 my $count = $i;
206 81         46 $count++;
207              
208 81         98 while ($count < @file_contents){
209 92 100       148 if ($file_contents[$count] =~ /^(\s*)\S/){
210 78         70 $indent = $1;
211 78         51 last;
212             }
213             else {
214 14         19 $count++;
215             }
216             }
217              
218 81         69 push @new_file, $e;
219              
220 81 100       282 if ($e =~ $single_line) {
    100          
221 13         18 for (@$code){
222 13         21 push @new_file, $indent . $_;
223             }
224             }
225             elsif ($e =~ $multi_line) {
226 1 50       5 if ($file_contents[$count] =~ /\s*\{\s*(?!\s*[\S])/) {
227 1         1 $is_multi = 1;
228 1         2 next;
229             }
230             }
231              
232 80 100       126 if ($is_multi) {
233 1         2 for (@$code) {
234 4         6 push @new_file, $indent . $_;
235             }
236 1         1 $is_multi = 0;
237             }
238             }
239 3         35 $p->{write_file_contents} = \@new_file;
240             }
241             }
242 7         51 }
243             sub replace {
244              
245 23 100   23 0 833 trace() if $ENV{TRACE};
246              
247             return sub {
248              
249 21 100   21   39 trace() if $ENV{TRACE};
250              
251 21         27 my $p = shift;
252 21         39 my $exec = $p->{exec};
253 21 100       43 my $limit = defined $p->{limit} ? $p->{limit} : -1;
254              
255 21         18 my @file = @{ $p->{file_contents} };
  21         164  
256              
257 13 100 66     68 if (! $exec || ref $exec ne 'CODE'){
258 1         209 confess "\nDES::replace() requires 'exec => \$cref param\n";
259             }
260              
261 12         9 my $lines_changed;
262              
263 12         32 for (@file){
264 483         448 my $changed = $exec->($_);
265 483 100       1242 if ($changed){
266 146         95 $lines_changed++;
267 146         77 $limit--;
268 146 100       193 last if $limit == 0;
269             }
270             }
271              
272 12         22 $p->{write_file_contents} = \@file;
273 12         26 return $lines_changed;
274             }
275 22         121 }
276             sub remove {
277              
278 6 100   6 1 840 trace() if $ENV{TRACE};
279              
280             return sub {
281              
282 3 100   3   9 trace() if $ENV{TRACE};
283            
284 3         4 my $p = shift;
285 3         4 my @file = @{ $p->{file_contents}};
  3         29  
286              
287 1         1 my $delete = $p->{delete};
288              
289 1         3 for my $find (@$delete){
290 1         3 while (my ($index) = grep { $file[$_] =~ $find } 0..$#file){
  101         104  
291 1         3 splice @file, $index, 1;
292             }
293             }
294 1         5 $p->{write_file_contents} = \@file;
295             }
296 5         30 }
297 1     1   7 sub _vim_placeholder {1;}
298             1;
299             __END__