File Coverage

blib/lib/Devel/Examine/Subs.pm
Criterion Covered Total %
statement 558 558 100.0
branch 261 274 95.2
condition 49 61 80.3
subroutine 55 56 98.2
pod 18 19 94.7
total 941 968 97.2


line stmt bran cond sub pod time code
1             package Devel::Examine::Subs;
2 57     57   2061749 use 5.008;
  57         218  
3 57     57   315 use warnings;
  57         111  
  57         1577  
4 57     57   316 use strict;
  57         117  
  57         3470  
5              
6             our $VERSION = '1.61';
7              
8 57     57   294 use Carp;
  57         115  
  57         3916  
9 57     57   43704 use Data::Compare;
  57         700681  
  57         370  
10 57     57   242537 use Data::Dumper;
  57         122038  
  57         3008  
11 57     57   34624 use Devel::Examine::Subs::Engine;
  57         152  
  57         1872  
12 57     57   35005 use Devel::Examine::Subs::Preprocessor;
  57         176  
  57         1856  
13 57     57   33095 use Devel::Examine::Subs::Postprocessor;
  57         146  
  57         1707  
14 57     57   329 use File::Basename;
  57         105  
  57         4512  
15 57     57   1075 use File::Copy;
  57         2580  
  57         2527  
16 57     57   46891 use File::Edit::Portable;
  57         1198719  
  57         2015  
17 57     57   47394 use PPI;
  57         8413321  
  57         2512  
18 57     57   525 use Symbol qw(delete_package);
  57         118  
  57         6979  
19              
20             BEGIN {
21              
22             # we need to do some trickery for DTS due to circular referencing,
23             # which broke CPAN installs.
24              
25 57     57   146 eval {
26 57         19520 require Devel::Trace::Subs;
27             };
28              
29 57         249 eval {
30 57         301 import Devel::Trace::Subs qw(trace);
31             };
32              
33 57 50       338 if (! defined &trace){
34 57     0   342029 *trace = sub {};
35             }
36             };
37              
38             #
39             # public methods
40             #
41              
42             sub new {
43            
44             # set up for tracing
45              
46 139 100   139 1 137221 if ($ENV{DES_TRACE}){
47 3         17 $ENV{DTS_ENABLE} = 1;
48 3         13 $ENV{TRACE} = 1;
49             }
50              
51 139 100       531 trace() if $ENV{TRACE};
52              
53 138         343 my $self = {};
54 138         342 bless $self, shift;
55 138         637 my $p = $self->_params(@_);
56              
57             # default configs
58              
59 138         694 $self->{namespace} = __PACKAGE__;
60 138         481 $self->{params}{regex} = 1;
61              
62 138         531 $self->_config($p);
63              
64 138         488 return $self;
65             }
66             sub all {
67            
68 26 100   26 1 10017 trace() if $ENV{TRACE};
69              
70 25         61 my $self = shift;
71 25         92 my $p = $self->_params(@_);
72              
73 25         79 $self->{params}{engine} = 'all';
74            
75 25         117 $self->run($p);
76             }
77             sub has {
78              
79 49 100   49 1 10277 trace() if $ENV{TRACE};
80              
81 48         87 my $self = shift;
82 48         174 my $p = $self->_params(@_);
83              
84 48         141 $self->{params}{post_proc} = 'file_lines_contain';
85 48         121 $self->{params}{engine} = 'has';
86            
87 48         167 $self->run($p);
88             }
89             sub missing {
90            
91 8 100   8 1 5246 trace() if $ENV{TRACE};
92              
93 7         19 my $self = shift;
94 7         27 my $p = $self->_params(@_);
95              
96 7         20 $self->{params}{engine} = 'missing';
97            
98 7         23 $self->run($p);
99             }
100             sub lines {
101            
102 8 100   8 1 4166 trace() if $ENV{TRACE};
103              
104 7         23 my $self = shift;
105 7         38 my $p = $self->_params(@_);
106              
107 7         20 $self->{params}{engine} = 'lines';
108            
109 7 100 66     41 if ($self->{params}{search} || $p->{search}){
110 5         14 $self->{params}{post_proc} = 'file_lines_contain';
111             }
112              
113 7         27 $self->run($p);
114             }
115             sub module {
116            
117 9 100   9 0 231082 trace() if $ENV{TRACE};
118              
119 8         22 my $self = shift;
120              
121 8         11 my $p;
122              
123             # allow for single string value
124              
125 8 100       27 if (@_ == 1){
126 1         3 my %p;
127 1         3 $p{module} = shift;
128 1         3 $p = $self->_params(%p);
129             }
130             else {
131 7         38 $p = $self->_params(@_);
132             }
133              
134             # set the preprocessor up, and have it return before
135             # the building/compiling of file data happens
136              
137 8         24 $self->{params}{pre_proc} = 'module';
138 8         18 $self->{params}{pre_proc_return} = 1;
139              
140 8         18 $self->{params}{engine} = 'module';
141              
142 8         33 $self->run($p);
143             }
144             sub objects {
145            
146 15 100   15 1 73851 trace() if $ENV{TRACE};
147              
148 14         33 my $self = shift;
149 14         42 my $p = $self->_params(@_);
150              
151 14         41 $self->{params}{post_proc} = 'subs';
152 14         102 $self->{params}{engine} = 'objects';
153              
154 14         118 $self->run($p);
155             }
156             sub search_replace {
157            
158 8 100   8 1 7106 trace() if $ENV{TRACE};
159              
160 7         18 my $self = shift;
161 7         27 my $p = $self->_params(@_);
162              
163             $self->{params}{post_proc}
164 7         28 = ['file_lines_contain', 'subs', 'objects'];
165              
166 7         19 $self->{params}{engine} = 'search_replace';
167              
168 7         24 $self->run($p);
169             }
170             sub replace {
171              
172 9 100   9 1 960 trace() if $ENV{TRACE};
173              
174 8         23 my $self = shift;
175 8         22 my $p = $self->_params(@_);
176              
177 8         20 $self->{params}{pre_proc} = 'replace';
178 8         17 $self->{params}{pre_proc_return} = 1;
179              
180 8         24 $self->run($p);
181             }
182             sub inject_after {
183            
184 8 100   8 1 943 trace() if $ENV{TRACE};
185              
186 7         22 my $self = shift;
187 7         23 my $p = $self->_params(@_);
188              
189 7 100 66     42 if (! $p->{injects} && ! $self->{params}{injects}){
190 3         9 $p->{injects} = 1;
191             }
192              
193             $self->{params}{post_proc}
194 7         24 = ['file_lines_contain', 'subs', 'objects'];
195              
196 7         19 $self->{params}{engine} = 'inject_after';
197              
198 7         23 $self->run($p);
199             }
200             sub inject {
201 7 100   7 1 3640 trace() if $ENV{TRACE};
202 6         21 my $self = shift;
203 6         20 my $p = $self->_params(@_);
204              
205             # inject_use/inject_after_sub_def are preprocs
206              
207 6 100 66     54 if ($p->{inject_use} || $p->{inject_after_sub_def} || defined $p->{line_num}){
      100        
208 5         12 $self->{params}{pre_proc} = 'inject';
209 5         9 $self->{params}{pre_proc_return} = 1;
210             }
211              
212 6         27 $self->run($p);
213             }
214             sub remove {
215 3 100   3 1 1673 trace() if $ENV{TRACE};
216              
217 2         12 my $self = shift;
218 2         9 my $p = $self->_params(@_);
219              
220 2         6 $self->{params}{pre_proc} = 'remove';
221 2         6 $self->{params}{pre_proc_return} = 1;
222              
223 2         8 $self->run($p);
224             }
225             sub order {
226 3 100   3 1 932 trace() if $ENV{TRACE};
227              
228 2         12 my $self = shift;
229 2         3 return @{ $self->{order} };
  2         18  
230             }
231              
232             #
233             # publicly available semi-private developer methods
234             #
235              
236             sub add_functionality {
237              
238 7 100   7 1 941 trace() if $ENV{TRACE};
239            
240 6         21 my $self = shift;
241 6         23 my $p = $self->_params(@_);
242              
243 6         20 $self->_config($p);
244            
245 6         12 my $to_add = $self->{params}{add_functionality};
246 6         17 my $in_prod = $self->{params}{add_functionality_prod};
247              
248 6         22 my @allowed = qw(
249             pre_proc
250             post_proc
251             engine
252             );
253              
254 6         11 my $is_allowed = 0;
255              
256 6         16 for (@allowed){
257 15 100       87 if ($_ eq $to_add){
258 5         10 $is_allowed = 1;
259 5         11 last;
260             }
261             }
262            
263 6 100       27 if (! $is_allowed){
264 1         168 croak "Adding a non-allowed piece of functionality...\n";
265             }
266              
267             my %dt = (
268             pre_proc => sub {
269 1 50   1   4 trace() if $ENV{TRACE};
270             return $in_prod
271 1 50       13 ? $INC{'Devel/Examine/Subs/Preprocessor.pm'}
272             : 'lib/Devel/Examine/Subs/Preprocessor.pm';
273             },
274             post_proc => sub {
275 1 50   1   11 trace() if $ENV{TRACE};
276             return $in_prod
277 1 50       5 ? $INC{'Devel/Examine/Subs/Postprocessor.pm'}
278             : 'lib/Devel/Examine/Subs/Postprocessor.pm';
279             },
280             engine => sub {
281 3 50   3   13 trace() if $ENV{TRACE};
282             return $in_prod
283 3 50       19 ? $INC{'Devel/Examine/Subs/Engine.pm'}
284             : 'lib/Devel/Examine/Subs/Engine.pm';
285             },
286 5         49 );
287              
288 5         22 my $caller = (caller)[1];
289              
290 5 50       242 open my $fh, '<', $caller
291             or confess "can't open the caller file $caller: $!";
292              
293 5         11 my $code_found = 0;
294 5         8 my @code;
295              
296 5         112 while (<$fh>){
297 139         170 chomp;
298 139 100       317 if (m|^#(.*)|){
299 5         19 $code_found = 1;
300 5         19 next;
301             }
302 134 100       386 next if ! $code_found;
303 39 100       101 last if m|^#(.*)|;
304 34         103 push @code, $_;
305             }
306              
307 5         25 my $file = $dt{$to_add}->();
308 5         16 my $copy = $self->{params}{copy};
309              
310 5 50       17 if ($copy) {
311 5 50       85 copy $file, $copy or die $!;
312 5         2495 $file = $copy;
313             }
314              
315 5         9 my $sub_name;
316            
317 5 100       33 if ($code[0] =~ /sub\s+(\w+)/){
318 4         14 $sub_name = $1;
319             }
320             else {
321 1         170 croak "couldn't extract the sub name";
322             }
323              
324 4         28 my $des = Devel::Examine::Subs->new(file => $file);
325              
326 4         21 my $existing_subs = $des->all;
327              
328 4 100       11 if (grep { $sub_name eq $_ } @$existing_subs) {
  45         91  
329 1         193 croak "the sub you're trying to add already exists";
330             }
331              
332 3         29 $des = Devel::Examine::Subs->new(
333             file => $file,
334             engine => 'objects',
335             post_proc => [qw(subs end_of_last_sub)],
336             );
337 3         56 $p = {
338             engine => 'objects',
339             post_proc => [qw(subs end_of_last_sub)],
340             post_proc_return => 1,
341             };
342              
343 3         968 my $start_writing = $des->run($p);
344              
345 3         40 my $rw = File::Edit::Portable->new;
346              
347 3         35 $rw->splice(file => $file, insert => \@code, line => $start_writing);
348              
349 3         7703 my @insert = (" $sub_name => \\&$sub_name,");
350              
351 3         15 my @ret = $rw->splice(
352             file => $file,
353             find => 'my\s+\$dt\s+=\s+\{',
354             insert => \@insert,
355             );
356              
357 3         7993 return 1;
358             }
359             sub engines {
360            
361 3 100   3 1 958 trace() if $ENV{TRACE};
362              
363 2         14 my $self = shift;
364 2         8 my $module = $self->{namespace} . "::Engine";
365 2         11 my $engine = $module->new;
366            
367 2         7 my @engines;
368              
369 2         4 for (keys %{$engine->_dt}){
  2         8  
370 20 100       67 push @engines, $_ if $_ !~ /^_/;
371             }
372 2         22 return @engines;
373             }
374             sub pre_procs {
375            
376 2 50   2 1 935 trace() if $ENV{TRACE};
377              
378 1         10 my $self = shift;
379 1         5 my $module = $self->{namespace} . "::Preprocessor";
380 1         11 my $pre_proc = $module->new;
381              
382 1         2 my @pre_procs;
383              
384 1         3 for (keys %{$pre_proc->_dt}){
  1         4  
385 5 100       21 push @pre_procs, $_ if $_ !~ /^_/;
386             }
387 1         15 return @pre_procs;
388             }
389             sub post_procs {
390            
391 3 100   3 1 895 trace() if $ENV{TRACE};
392              
393 2         12 my $self = shift;
394 2         9 my $module = $self->{namespace} . "::Postprocessor";
395 2         18 my $post_proc = $module->new;
396              
397 2         5 my @post_procs;
398              
399 2         6 for (keys %{$post_proc->_dt}){
  2         7  
400 14 100       58 push @post_procs, $_ if $_ !~ /^_/;
401             }
402 2         117 return @post_procs;
403             }
404             sub run {
405              
406 186 100   186 1 15835 trace() if $ENV{TRACE};
407              
408 185         483 my $self = shift;
409 185         320 my $p = shift;
410              
411 185         570 $self->_config($p);
412              
413 181         739 $self->_run_end(0);
414              
415 181         232 my $struct;
416              
417 181 100       500 if ($self->{params}{directory}){
418 9         34 $struct = $self->_run_directory;
419             }
420             else {
421 172         598 $struct = $self->_core;
422 139 100       585 $self->_write_file if $self->{write_file_contents};
423             }
424              
425 148         590 $self->_run_end(1);
426              
427 148         759 return $struct;
428             }
429             sub valid_params {
430            
431 3 100   3 1 939 trace() if $ENV{TRACE};
432              
433 2         14 my $self = shift;
434 2         4 return %{$self->{valid_params}};
  2         26  
435             }
436              
437             #
438             # private methods
439             #
440              
441             sub _cache {
442            
443 30 100   30   1016 trace() if $ENV{TRACE};
444              
445 29         51 my $self = shift;
446 29         52 my $file = shift;
447 29         47 my $struct = shift;
448              
449 29 100       89 if ($self->{params}{cache_dump}){
450              
451 1         9 print Dumper $self->{cache};
452              
453 1 50       391 if ($self->{params}{cache_dump} > 1){
454 1         8 exit;
455             }
456             }
457              
458 28 100 100     149 if (! $struct && $file){
459 25         203 return $self->{cache}{$file};
460             }
461 3 100 66     22 if ($file && $struct){
462 2         7 $self->{cache}{$file} = $struct;
463             }
464             }
465             sub _cache_enabled {
466            
467 770 100   770   3607 trace() if $ENV{TRACE};
468              
469 769         1358 my $self = shift;
470 769         2758 return $self->{params}{cache};
471             }
472             sub _cache_safe {
473            
474 356 100   356   2037 trace() if $ENV{TRACE};
475              
476 355         575 my $self = shift;
477 355         612 my $value = shift;
478              
479 355 100       989 $self->{cache_safe} = $value if defined $value;
480              
481 355         906 return $self->{cache_safe};
482             }
483             sub _clean_config {
484            
485 334 100   334   1903 trace() if $ENV{TRACE};
486              
487 333         665 my $self = shift;
488 333         517 my $config_vars = shift; # href of valid params
489 333         506 my $p = shift; # href of params passed in
490              
491 333         2459 for my $var (keys %$config_vars){
492            
493 2438 100       4824 last if ! $self->_run_end;
494              
495             # skip if it's a persistent var
496              
497 2160 100       4972 next if $config_vars->{$var} == 1;
498              
499 1566         2440 delete $self->{params}{$var};
500             }
501              
502             # delete non-valid params
503              
504 333         1815 for my $param (keys %$p){
505 463 100       1439 if (! exists $config_vars->{$param}){
506 5         112 print "\n\nDES::_clean_config() deleting invalid param: $param\n";
507 5         12 delete $p->{$param};
508             }
509             }
510             }
511             sub _clean_core_config {
512            
513 151 100   151   1424 trace() if $ENV{TRACE};
514              
515 150         278 my $self = shift;
516              
517             # delete params we collected after _clean_config()
518              
519 150         1374 delete $self->{params}{file_contents};
520 150         482 delete $self->{params}{order};
521              
522 150         440 my @core_phases = qw(
523             pre_proc
524             post_proc
525             engine
526             );
527              
528 150         388 for (@core_phases){
529 450         1005 delete $self->{params}{$_};
530             }
531             }
532             sub _config {
533            
534 333 100   333   2271 trace() if $ENV{TRACE};
535              
536 332         618 my $self = shift;
537 332         495 my $p = shift;
538              
539 332         7225 my %valid_params = (
540              
541             # persistent
542              
543             file => 1,
544             extensions => 1,
545             maxdepth => 1,
546             regex => 1,
547             copy => 1,
548             diff => 1,
549             no_indent => 1,
550             cache => 1,
551              
552             # persistent - core phases
553              
554             pre_proc => 1,
555             post_proc => 1,
556             engine => 1,
557              
558             # transient
559              
560             directory => 0,
561             search => 0,
562             replace => 0,
563             injects => 0,
564             code => 0,
565             include => 0,
566             exclude => 0,
567             lines => 0,
568             module => 0,
569             objects_in_hash => 0,
570             pre_proc_dump => 0,
571             post_proc_dump => 0,
572             engine_dump => 0,
573             core_dump => 0,
574             pre_proc_return => 0,
575             post_proc_return => 0,
576             engine_return => 0,
577             config_dump => 0,
578             cache_dump => 0,
579             inject_use => 0,
580             inject_after_sub_def => 0,
581             delete => 0,
582             file_contents => 0,
583             exec => 0,
584             limit => 0,
585             line_num => 0, # inject()
586             add_functionality => 0,
587             add_functionality_prod => 0,
588             order => 0,
589             );
590              
591 332         807 $self->{valid_params} = \%valid_params;
592              
593             # get previous run's config
594              
595 332         1256 %{$self->{previous_run_config}} = %{$self->{params}};
  332         1442  
  332         1062  
596              
597             # clean config
598              
599 332         1246 $self->_clean_config(\%valid_params, $p);
600              
601 332         2267 for my $param (keys %$p){
602              
603             # validate the file
604              
605 457 100       1165 if ($param eq 'file'){
606 151         499 $self->_file($p);
607 147         297 next;
608             }
609              
610 306         829 $self->{params}{$param} = $p->{$param};
611             }
612              
613             # check if we can cache
614              
615 328 100       1335 if ($self->_cache_enabled) {
616              
617             my @unsafe_cache_params
618 16         47 = qw(file extensions include exclude search);
619              
620 16         29 my $current = $self->{params};
621 16         19 my $previous = $self->{previous_run_config};
622              
623 16         36 for (@unsafe_cache_params) {
624 57   100     256 my $safe = Compare($current->{$_}, $previous->{$_}) || 0;
625              
626 57         2838 $self->_cache_safe($safe);
627              
628 57 100       112 last if !$self->_cache_safe;
629             }
630             }
631              
632 328 100       1176 if ($self->{params}{config_dump}){
633 1         8 print Dumper $self->{params};
634             }
635             }
636             sub _file {
637            
638 154 100   154   1420 trace() if $ENV{TRACE};
639              
640 153         256 my $self = shift;
641 153         235 my $p = shift;
642              
643 153 100       647 $self->{params}{file} = defined $p->{file} ? $p->{file} : $self->{params}{file};
644              
645             # if a module was passed in, dig up the file
646              
647 153 100       697 if ($self->{params}{file} =~ /::/){
648              
649 3         6 my $module = $self->{params}{file};
650 3         12 (my $file = $module) =~ s|::|/|g;
651 3         7 $file .= '.pm';
652            
653 3         4 my $module_is_loaded;
654            
655 3 100       11 if (! $INC{$file}){
656            
657 2         4 eval { require $file; import $module; };
  2         5691  
  1         67674  
658              
659 2 100       13 if ($@){
660 1         3 $@ = "\nDevel::Examine::Subs::_file() speaking ... " .
661             "Can't transform module to a file name\n\n"
662             . $@;
663 1         179 croak $@;
664             }
665             }
666             else {
667 1         3 $module_is_loaded = 1;
668             }
669              
670             # set the file param
671              
672 2         14 $self->{params}{file} = $INC{$file};
673              
674 2 100       12 if (! $module_is_loaded){
675 1         8 delete_package $module;
676 1         265 delete $INC{$file};
677             }
678             }
679              
680             # configure directory searching for run()
681              
682 152 100       3492 if (-d $self->{params}{file}){
683 10         29 $self->{params}{directory} = 1;
684             $self->{params}{extensions}
685 10 100       54 = defined $p->{extensions} ? $p->{extensions} : [qw(*.pm *.pl)];
686             }
687             else {
688 142 100 66     2222 if (! $self->{params}{file} || ! -f $self->{params}{file}){
689 4         82 die "Invalid file supplied: $self->{params}{file} $!";
690             }
691             }
692              
693 148         343 return $self->{params}{file};
694             }
695             sub _params {
696            
697 285 100   285   1730 trace() if $ENV{TRACE};
698              
699 284         583 my $self = shift;
700 284         930 my %params = @_;
701 284         657 return \%params;
702             }
703             sub _read_file {
704              
705             # this sub prepares a temp copy of the original file,
706             # recseps changed to local platform for PPI
707              
708 273 100   273   1780 trace() if $ENV{TRACE};
709              
710 272         531 my $self = shift;
711 272         402 my $p = shift;
712              
713 272         492 my $file = $p->{file};
714              
715 272 100       680 return if ! $file;
716              
717 242         11083 my $basename = basename($file);
718 242         628 my $bak = "$basename.bak";
719              
720 242 100       1263 copy $file, $bak
721             or croak "DES::_read_file() can't create backup copy $bak!";
722              
723 241         100350 $self->{rw} = File::Edit::Portable->new;
724              
725 241         2122 my $fh = $self->{rw}->read($file);
726 241         1688593 my $tempfile = $self->{rw}->tempfile;
727 241         86305 my $tempfile_name = $tempfile->filename;
728 241         1929 my $platform_recsep = $self->{rw}->platform_recsep;
729              
730             $self->{rw}->write(
731 241         161097 copy => $tempfile_name,
732             contents => $fh,
733             recsep => $platform_recsep
734             );
735              
736 241         122970 my $ppi_doc = PPI::Document->new($tempfile_name);
737            
738 241         10331444 @{ $p->{file_contents} } = split /\n/, $ppi_doc->content;
  241         401117  
739              
740 241         12298 close $tempfile;
741              
742 241 100       1143 if (! $p->{file_contents}->[0]){
743 2         8 return 0;
744             }
745             else {
746 239         679 $self->{params}{file_contents} = $p->{file_contents};
747 239         1504 return 1;
748             }
749             }
750             sub _run_directory {
751            
752 11 100   11   936 trace() if $ENV{TRACE};
753              
754 10         28 my $self = shift;
755 10         20 my $p = shift;
756              
757 10         22 my $dir = $self->{params}{file};
758              
759 10         91 $self->{rw} = File::Edit::Portable->new;
760              
761             my @files = $self->{rw}->dir(
762             dir => $dir,
763             maxdepth => $self->{params}{maxdepth} || 0,
764             types => $self->{params}{extensions},
765 10   50     210 list => 1,
766             );
767              
768 9         18313 my %struct;
769              
770 9         27 for my $file (@files){
771            
772 97         302 $self->{params}{file} = $file;
773 97         390 my $data = $self->_core($p);
774              
775 97 100       337 $self->_write_file if $self->{write_file_contents};
776              
777 97 100 66     682 if (ref $data eq 'HASH' || ref $data eq 'ARRAY'){
778 70         250 $struct{$file} = $data;
779             }
780             }
781              
782 9         63 return \%struct;
783             }
784             sub _run_end {
785            
786 2772 100   2772   7908 trace() if $ENV{TRACE};
787              
788 2771         4338 my $self = shift;
789 2771         3343 my $value = shift;
790              
791 2771 100       5572 $self->{run_end} = $value if defined $value;
792              
793             # we clean core_config here
794              
795 2771 100       5662 $self->_clean_core_config if $value;
796              
797 2771         6620 return $self->{run_end};
798             }
799             sub _write_file {
800              
801 29 100   29   968 trace() if $ENV{TRACE};
802              
803 28         56 my $self = shift;
804              
805 28         68 my $copy = $self->{params}{copy};
806            
807 28         64 my $file = $self->{params}{file};
808 28         57 my $contents = $self->{write_file_contents};
809              
810 28 100       85 return if ! $file;
811              
812 27 100 100     496 if ($self->{params}{directory} && $copy && ! -d $copy){
      100        
813 2         32 warn "\n\nin directory mode, all files are copied to the dir named " .
814             "in the copy param, which is $copy\n\n";
815              
816 2 50       135 mkdir $copy or croak "can't create directory $copy";
817             }
818 27 100 100     645 if ($copy && -d $copy){
    100          
819 8         32 copy $file, $copy;
820 8         2857 my $filename = basename $file;
821 8         22 $file = "$copy/$filename";
822             }
823             elsif ($copy) {
824 16         31 $file = $copy;
825             }
826              
827 27         43 my $write_response;
828              
829 27         46 eval {
830 27         162 $write_response = $self->{rw}->write(file => $file, contents => $contents);
831             };
832              
833 27 100 66     19344 if ($@ || ! $write_response){
834 1         3 $@ = "\nDevel::Examine::Subs::_write_file() speaking...\n\n" .
835             "File::Edit::Portable::write() returned a failure status.\n\n" .
836             $@;
837 1         172 croak $@;
838             }
839             }
840              
841             #
842             # private methods for core phases
843             #
844              
845             sub _core {
846              
847 271 100   271   1771 trace() if $ENV{TRACE};
848            
849 270         525 my $self = shift;
850              
851 270         522 my $p = $self->{params};
852              
853 270         586 my $search = $self->{params}{search};
854 270         540 my $file = $self->{params}{file};
855              
856 270         897 $self->_read_file($p);
857              
858             # pre processor
859              
860 270         844032 my $data;
861              
862 270 100       1451 if ($self->{params}{pre_proc}){
863 42         146 my $pre_proc = $self->_pre_proc;
864              
865 37         129 $data = $pre_proc->($p, $data);
866              
867 25 100       2324 if ($self->{params}{pre_proc_dump}){
868 1         7 print Dumper $data;
869 1         365 exit;
870             }
871              
872 24 100       71 if ($p->{write_file_contents}){
873 15         36 $self->{write_file_contents} = $p->{write_file_contents};
874             }
875              
876             # for things that don't need to process files
877             # (such as 'module'), return early
878              
879 24 100       150 if ($self->{params}{pre_proc_return}){
880 22         217 return $data;
881             }
882             }
883              
884             # processor
885              
886 230         428 my $subs = $data;
887              
888             # bypass the proc if cache
889              
890 230         980 my $cache_enabled = $self->_cache_enabled;
891 230         925 my $cache_safe = $self->_cache_safe;
892              
893 230 100 100     1235 if ($cache_enabled && $cache_safe && $self->_cache($p->{file})){
      66        
894 6         20 $subs = $self->_cache($p->{file});
895             }
896             else {
897 224         934 $subs = $self->_proc($p);
898             }
899              
900 230 100       674227 return if ! $subs;
901              
902             # write to cache
903              
904 210 100 100     927 if ($self->_cache_enabled && ! $self->_cache($p->{file})){
905 2         8 $self->_cache($p->{file}, $subs);
906             }
907              
908             # post processor
909              
910 209 100       910 if ($self->{params}{post_proc}){
911 101         504 for my $post_proc ($self->_post_proc($p, $subs)){
912 133         475 $subs = $post_proc->($p, $subs);
913 133         744 $self->{write_file_contents} = $p->{write_file_contents};
914             }
915             }
916              
917 203 100       1642 if ($self->{params}{post_proc_return}){
918 5         20 return $subs;
919             }
920              
921             # engine
922              
923 198         890 my $engine = $self->_engine($p, $subs);
924              
925 195 100       730 if ($self->{params}{engine}){
926 183         672 $subs = $engine->($p, $subs);
927 178         3979 $self->{write_file_contents} = $p->{write_file_contents};
928             }
929              
930             # core dump
931              
932 190 100       634 if ($self->{params}{core_dump}){
933            
934 1         121 print "\n\t Core Dump called...\n\n";
935 1         12 print "\n\n\t Dumping data... \n\n";
936 1         7 print Dumper $subs;
937              
938 1         184 print "\n\n\t Dumping instance...\n\n";
939 1         5 print Dumper $self;
940              
941 1         664 exit;
942             }
943              
944 189         1495 return $subs;
945             }
946             sub _pre_proc {
947            
948 46 100   46   2090 trace() if $ENV{TRACE};
949              
950 45         149 my $self = shift;
951 45         75 my $p = shift;
952 45         62 my $subs = shift;
953              
954 45         94 my $pre_proc = $self->{params}{pre_proc};
955              
956 45 100 66     299 if (not $pre_proc or $pre_proc eq ''){
957 1         4 return $subs;
958             }
959            
960             # tell _core() to return directly from the pre_processor
961             # if necessary, and bypass post_proc and engine
962              
963 44 100       123 if ($pre_proc eq 'module'){
964 8         17 $self->{params}{pre_proc_return} = 1;
965             }
966              
967 44         60 my $cref;
968            
969 44 100       127 if (not ref($pre_proc) eq 'CODE'){
970 43         121 my $pre_proc_module = $self->{namespace} . "::Preprocessor";
971 43         367 my $compiler = $pre_proc_module->new;
972              
973 43 100       166 if (! $compiler->exists($pre_proc)){
974 1         103 croak "Devel::Examine::Subs::_pre_proc() speaking...\n\n" .
975             "pre_processor '$pre_proc' is not implemented.\n";
976             }
977              
978 42         78 eval {
979 42         215 $cref = $compiler->{pre_procs}{$pre_proc}->();
980             };
981            
982 42 100       230 if ($@){
983 4         10 $@ = "\n[Devel::Examine::Subs speaking] " .
984             "dispatch table in Devel::Examine::Subs::Preprocessor " .
985             "has a mistyped function as a value, but the key is ok\n\n"
986             . $@;
987 4         683 croak $@;
988             }
989              
990             }
991              
992 39 100       104 if (ref($pre_proc) eq 'CODE'){
993 1         2 $cref = $pre_proc;
994             }
995            
996 39         94 return $cref;
997             }
998             sub _proc {
999            
1000             # this method is the core data collection/manipulation
1001             # routine (aka the 'Processor phase') for all of DES
1002              
1003             # make sure all unit tests are successful after any change
1004             # to this subroutine!
1005              
1006             # if you want the data structure to look differently before
1007             # reaching here, use a pre_proc. If you want it different
1008             # afterwards, use a post_proc or an engine
1009              
1010 226 100   226   1626 trace() if $ENV{TRACE};
1011            
1012 225         404 my $self = shift;
1013 225         396 my $p = shift;
1014            
1015 225         603 my $file = $self->{params}{file};
1016              
1017 225 100       705 return {} if ! $file;
1018              
1019 214         1031 my $PPI_doc = PPI::Document->new($file);
1020 214         9624969 my $PPI_subs = $PPI_doc->find('PPI::Statement::Sub');
1021              
1022 214 100       2957899 return if ! $PPI_subs;
1023              
1024 194         442 my %subs;
1025 194         769 $subs{$file} = {};
1026 194         384 my @sub_order;
1027              
1028 194         382 for my $PPI_sub (@{$PPI_subs}){
  194         668  
1029            
1030             my $include
1031 1552 100       4957 = defined $self->{params}{include} ? $self->{params}{include} : [];
1032             my $exclude
1033 1552 100       4011 = defined $self->{params}{exclude} ? $self->{params}{exclude} : [];
1034              
1035 1552 100       3976 delete $self->{params}{include} if $exclude->[0];
1036              
1037 1552         4857 my $name = $PPI_sub->name;
1038            
1039 1552         36181 push @sub_order, $name;
1040              
1041             # skip over excluded (or not included) subs
1042              
1043 1552 100       4025 next if grep {$name eq $_ } @$exclude;
  88         226  
1044              
1045 1544 100       3711 if ($include->[0]){
1046 127 100       192 next if (! grep {$name eq $_ && $_} @$include);
  303 100       1147  
1047             }
1048              
1049 1449         4388 $subs{$file}{subs}{$name}{start} = $PPI_sub->line_number;
1050 1449         2141845 $subs{$file}{subs}{$name}{start}--;
1051              
1052 1449         3887 my $lines = $PPI_sub =~ y/\n//;
1053              
1054             $subs{$file}{subs}{$name}{end}
1055 1449         529038 = $subs{$file}{subs}{$name}{start} + $lines;
1056              
1057 1449         2980 my $count_start = $subs{$file}{subs}{$name}{start};
1058 1449         1804 $count_start--;
1059              
1060             my $sub_line_count
1061 1449         2983 = $subs{$file}{subs}{$name}{end} - $count_start;
1062              
1063 1449         3030 $subs{$file}{subs}{$name}{num_lines} = $sub_line_count;
1064              
1065 1449         3805 @{ $subs{$file}{subs}{$name}{code} } = split /\n/, $PPI_sub->content;
  1449         256673  
1066             }
1067            
1068 194         474 @{ $p->{order} } = @sub_order;
  194         1036  
1069 194         369 @{ $self->{order} } = @sub_order;
  194         960  
1070              
1071 194         1255 return \%subs;
1072             }
1073             sub _post_proc {
1074            
1075 103 100   103   1291 trace() if $ENV{TRACE};
1076              
1077 102         212 my $self = shift;
1078 102         193 my $p = shift;
1079 102         194 my $struct = shift;
1080              
1081 102         258 my $post_proc = $self->{params}{post_proc};
1082              
1083 102         280 my $post_proc_dump = $self->{params}{post_proc_dump};
1084              
1085 102         171 my @post_procs;
1086              
1087 102 100       288 if ($post_proc){
1088              
1089 101         158 my @post_proc_list;
1090              
1091 101 100       328 if (ref $post_proc ne 'ARRAY'){
1092 76         176 push @post_proc_list, $post_proc;
1093             }
1094             else {
1095 25         44 @post_proc_list = @{$post_proc};
  25         105  
1096             }
1097              
1098 101         247 for my $pf (@post_proc_list){
1099              
1100 141         220 my $cref;
1101              
1102 141 100       415 if (ref $pf ne 'CODE'){
1103              
1104 136         424 my $post_proc_module = $self->{namespace} . "::Postprocessor";
1105 136         1298 my $compiler = $post_proc_module->new;
1106              
1107             # post_proc isn't in the dispatch table
1108              
1109 136 100       529 if (! $compiler->exists($pf)){
1110 3         443 croak "\nDevel::Examine::Subs::_post_proc() " .
1111             "speaking...\n\npost_proc '$pf' is not " .
1112             "implemented. '$post_proc' was sent in.\n";
1113             }
1114            
1115 133         237 eval {
1116 133         560 $cref = $compiler->{post_procs}{$pf}->();
1117             };
1118            
1119 133 100       1070 if ($@){
1120 1         3 $@ = "\n[Devel::Examine::Subs speaking] " .
1121             "dispatch table in " .
1122             "Devel::Examine::Subs::Postprocessor has a mistyped " .
1123             "function as a value, but the key is ok\n\n"
1124             . $@;
1125 1         102 croak $@;
1126             }
1127             }
1128 137 100       396 if (ref($pf) eq 'CODE'){
1129 5         8 $cref = $pf;
1130             }
1131              
1132 137 100 100     464 if ($post_proc_dump && $post_proc_dump > 1){
1133 1         3 $self->{params}{post_proc_dump}--;
1134 1         2 $post_proc_dump = $self->{params}{post_proc_dump};
1135             }
1136              
1137 137 100 66     442 if ($post_proc_dump && $post_proc_dump == 1){
1138 2         9 my $subs = $cref->($p, $struct);
1139 2         15 print Dumper $subs;
1140 2         1557 exit;
1141             }
1142 135         395 push @post_procs, $cref;
1143             }
1144             }
1145             else {
1146 1         4 return;
1147             }
1148 95         332 return @post_procs;
1149             }
1150             sub _engine {
1151            
1152 203 100   203   1549 trace() if $ENV{TRACE};
1153              
1154 202         392 my $self = shift;
1155 202         372 my $p = shift;
1156 202         338 my $struct = shift;
1157              
1158             my $engine
1159 202 100       784 = defined $p->{engine} ? $p->{engine} : $self->{params}{engine};
1160              
1161 202 100 66     1388 if (not $engine or $engine eq ''){
1162 13         35 return $struct;
1163             }
1164              
1165 189         282 my $cref;
1166              
1167 189 100       585 if (not ref($engine) eq 'CODE'){
1168              
1169             # engine is a name
1170              
1171 188         552 my $engine_module = $self->{namespace} . "::Engine";
1172 188         2133 my $compiler = $engine_module->new;
1173              
1174             # engine isn't in the dispatch table
1175              
1176 188 100       852 if (! $compiler->exists($engine)){
1177 1         102 croak "engine '$engine' is not implemented.\n";
1178             }
1179              
1180 187         366 eval {
1181 187         775 $cref = $compiler->{engines}{$engine}->();
1182             };
1183              
1184             # engine has bad func val in dispatch table, but key is ok
1185              
1186 187 100       1167 if ($@){
1187 1         4 $@ = "\n[Devel::Examine::Subs speaking] " .
1188             "dispatch table in Devel::Examine::Subs::Engine " .
1189             "has a mistyped function as a value, but the key is ok\n\n"
1190             . $@;
1191 1         171 croak $@;
1192             }
1193             }
1194              
1195 187 100       573 if (ref($engine) eq 'CODE'){
1196 1         2 $cref = $engine;
1197             }
1198              
1199 187 100       657 if ($self->{params}{engine_dump}){
1200 1         5 my $subs = $cref->($p, $struct);
1201 1         7 print Dumper $subs;
1202 1         308 exit;
1203             }
1204              
1205 186         444 return $cref;
1206             }
1207              
1208             #
1209             # pod
1210             #
1211              
1212 1     1   2858 sub _pod{1;} #vim placeholder
1213             1;
1214             __END__