File Coverage

blib/lib/Devel/Examine/Subs/Preprocessor.pm
Criterion Covered Total %
statement 136 136 100.0
branch 54 60 90.0
condition 4 6 66.6
subroutine 20 20 100.0
pod 4 6 66.6
total 218 228 95.6


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