File Coverage

blib/lib/B/RecDeparse.pm
Criterion Covered Total %
statement 101 101 100.0
branch 21 22 95.4
condition 21 26 80.7
subroutine 20 20 100.0
pod 1 7 14.2
total 164 176 93.1


line stmt bran cond sub pod time code
1             package B::RecDeparse;
2              
3 12     12   247350 use 5.008_001;
  12         45  
  12         445  
4              
5 12     12   72 use strict;
  12         24  
  12         434  
6 12     12   71 use warnings;
  12         40  
  12         319  
7              
8 12     12   64 use B ();
  12         94  
  12         300  
9              
10 12     12   56 use Config;
  12         21  
  12         494  
11              
12 12     12   65 use base qw;
  12         18  
  12         2565  
13              
14             =head1 NAME
15              
16             B::RecDeparse - Deparse recursively into subroutines.
17              
18             =head1 VERSION
19              
20             Version 0.08
21              
22             =cut
23              
24             our $VERSION = '0.08';
25              
26             =head1 SYNOPSIS
27              
28             # Deparse recursively a Perl one-liner :
29             $ perl -MO=RecDeparse,deparse,@B__Deparse_opts,level,-1 -e '...'
30              
31             # Or a complete Perl script :
32             $ perl -MO=RecDeparse,deparse,@B__Deparse_opts,level,-1 x.pl
33              
34             # Or a single code reference :
35             use B::RecDeparse;
36              
37             my $brd = B::RecDeparse->new(
38             deparse => \@B__Deparse_opts,
39             level => $level,
40             );
41             my $code = $brd->coderef2text(sub { ... });
42              
43             =head1 DESCRIPTION
44              
45             This module extends L by making it recursively replace subroutine calls encountered when deparsing.
46              
47             Please refer to L documentation for what to do and how to do it.
48             Besides the constructor syntax, everything should work the same for the two modules.
49              
50             =head1 METHODS
51              
52             =head2 C
53              
54             my $brd = B::RecDeparse->new(
55             deparse => \@B__Deparse_opts,
56             level => $level,
57             );
58              
59             The L object constructor.
60             You can specify the underlying L constructor arguments by passing a string or an array reference as the value of the C key.
61             The C option expects an integer that specifies how many levels of recursions are allowed : C<-1> means infinite while C<0> means none and match L behaviour.
62              
63             =cut
64              
65             use constant {
66             # p31268 made pp_entersub call single_delim
67 12   0     6910 FOOL_SINGLE_DELIM =>
68             ("$]" >= 5.009_005)
69             || ("$]" < 5.009 and "$]" >= 5.008_009)
70             || ($Config{perl_patchlevel} && $Config{perl_patchlevel} >= 31268)
71 12     12   68 };
  12         22  
72              
73             sub _parse_args {
74 36 100   36   140 if (@_ % 2) {
75 1         11 require Carp;
76 1         250 Carp::croak('Optional arguments must be passed as key/value pairs');
77             }
78 35         129 my %args = @_;
79              
80 35         64 my $deparse = $args{deparse};
81 35 100       94 if (defined $deparse) {
82 24 100       109 if (!ref $deparse) {
    100          
83 6         19 $deparse = [ $deparse ];
84             } elsif (ref $deparse ne 'ARRAY') {
85 1         2 $deparse = [ ];
86             }
87             } else {
88 11         22 $deparse = [ ];
89             }
90              
91 35         86 my $level = $args{level};
92 35 100       96 $level = -1 unless defined $level;
93 35         49 $level = int $level;
94              
95 35         96 return $deparse, $level;
96             }
97              
98             sub new {
99 35     35 1 76245 my $class = shift;
100 35   100     265 $class = ref($class) || $class || __PACKAGE__;
101              
102 35         126 my ($deparse, $level) = _parse_args(@_);
103              
104 34         868 my $self = bless $class->SUPER::new(@$deparse), $class;
105              
106 34         75 $self->{brd_level} = $level;
107              
108 34         110 return $self;
109             }
110              
111             sub _recurse {
112 209   100 209   2549 return $_[0]->{brd_level} < 0 || $_[0]->{brd_cur} < $_[0]->{brd_level}
113             }
114              
115             sub compile {
116 1     1 0 12 my @args = @_;
117              
118 1         61 my $bd = B::Deparse->new();
119 1         7 my ($deparse, $level) = _parse_args(@args);
120              
121 1         9818 my $compiler = $bd->coderef2text(B::Deparse::compile(@$deparse));
122 1         49 $compiler =~ s/
123             ['"]? B::Deparse ['"]? \s* -> \s* (new) \s* \( ([^\)]*) \)
124             /B::RecDeparse->$1(deparse => [ $2 ], level => $level)/gx;
125 1     1   129 $compiler = eval 'sub ' . $compiler;
  1     1   10  
  1         1  
  1         700  
  1         6  
  1         2  
  1         180  
126 1 50       6 die if $@;
127              
128 1         15 return $compiler;
129             }
130              
131             sub init {
132 111     111 0 81305 my $self = shift;
133              
134 111         192 $self->{brd_cur} = 0;
135 111         169 $self->{brd_sub} = 0;
136 111         201 $self->{brd_seen} = { };
137              
138 111         1870 $self->SUPER::init(@_);
139             }
140              
141             my $key = $; . __PACKAGE__ . $;;
142              
143             if (FOOL_SINGLE_DELIM) {
144             my $oldsd = *B::Deparse::single_delim{CODE};
145              
146 12     12   88 no warnings 'redefine';
  12         28  
  12         6781  
147             *B::Deparse::single_delim = sub {
148 85     85   1205 my $body = $_[2];
149              
150 85 100 66     1491 if ((caller 1)[0] eq __PACKAGE__ and $body =~ s/^$key//) {
151 46         11628 return $body;
152             } else {
153 39         24332 $oldsd->(@_);
154             }
155             }
156             }
157              
158             sub deparse_sub {
159 123     123 0 195 my $self = shift;
160 123         150 my $cv = $_[0];
161              
162 123         123 my $name;
163 123 100       521 unless ($cv->CvFLAGS & B::CVf_ANON()) {
164 90         731 $name = $cv->GV->SAFENAME;
165             }
166              
167 123 100       443 local $self->{brd_seen}->{$name} = 1 if defined $name;
168 123         83288 return $self->SUPER::deparse_sub(@_);
169             }
170              
171             sub pp_entersub {
172 112     112 0 194 my $self = shift;
173              
174 112         249 my $body = do {
175 112         262 local $self->{brd_sub} = 1;
176 112         18579 $self->SUPER::pp_entersub(@_);
177             };
178              
179 112 100       295 $body =~ s/^&\s*(\w)/$1/ if $self->_recurse;
180              
181 112         10324 return $body;
182             }
183              
184             sub pp_refgen {
185 15     15 0 23 my $self = shift;
186              
187 15         18 return do {
188 15         30 local $self->{brd_sub} = 0;
189 15         1711 $self->SUPER::pp_refgen(@_);
190             }
191             }
192              
193             sub pp_gv {
194 113     113 0 170 my $self = shift;
195              
196 113         992 my $gv = $self->gv_or_padgv($_[0]);
197 113         338 my $name = $gv->NAME;
198 113         325 my $cv = $gv->CV;
199 113         196 my $seen = $self->{brd_seen};
200              
201 113         133 my $body;
202 113 100 100     513 if (!$self->{brd_sub} or !$self->_recurse or $seen->{$name} or !$$cv
      100        
      100        
      66        
      100        
203             or !$cv->isa('B::CV') or $cv->ROOT->isa('B::NULL')) {
204 67         1759 $body = $self->SUPER::pp_gv(@_);
205             } else {
206 46         57 $body = do {
207 46         111 local @{$self}{qw} = (0, $self->{brd_cur} + 1);
  46         193  
208 46         112 local $seen->{$name} = 1;
209 46         212 'sub ' . $self->indent($self->deparse_sub($gv->CV));
210             };
211              
212 46         94 if (FOOL_SINGLE_DELIM) {
213 46         110 $body = $key . $body;
214             } else {
215             $body .= '->';
216             }
217             }
218              
219 113         20139 return $body;
220             }
221              
222             =pod
223              
224             The following functions and methods from L are reimplemented by this module :
225              
226             =over 4
227              
228             =item *
229              
230             C
231              
232             =item *
233              
234             C
235              
236             =item *
237              
238             C
239              
240             =item *
241              
242             C
243              
244             =item *
245              
246             C
247              
248             =item *
249              
250             C
251              
252             =back
253              
254             Otherwise, L inherits all methods from L.
255              
256             =head1 EXPORT
257              
258             An object-oriented module shouldn't export any function, and so does this one.
259              
260             =head1 DEPENDENCIES
261              
262             L 5.8.1.
263              
264             L (standard since perl 5), L (since perl 5.00307) and L (since perl 5.005).
265              
266             =head1 AUTHOR
267              
268             Vincent Pit, C<< >>, L.
269              
270             You can contact me by mail or on C (vincent).
271              
272             =head1 BUGS
273              
274             Please report any bugs or feature requests to C, or through the web interface at L.
275             I will be notified, and then you'll automatically be notified of progress on your bug as I make changes.
276              
277             =head1 SUPPORT
278              
279             You can find documentation for this module with the perldoc command.
280              
281             perldoc B::RecDeparse
282              
283             Tests code coverage report is available at L.
284              
285             =head1 COPYRIGHT & LICENSE
286              
287             Copyright 2008,2009,2010,2011,2013 Vincent Pit, all rights reserved.
288              
289             This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.
290              
291             =cut
292              
293             1; # End of B::RecDeparse