File Coverage

blib/lib/B/RecDeparse.pm
Criterion Covered Total %
statement 102 106 96.2
branch 23 26 88.4
condition 22 32 68.7
subroutine 20 21 95.2
pod 1 8 12.5
total 168 193 87.0


line stmt bran cond sub pod time code
1             package B::RecDeparse;
2              
3 12     12   172435 use 5.008_001;
  12         36  
  12         387  
4              
5 12     12   50 use strict;
  12         20  
  12         357  
6 12     12   50 use warnings;
  12         31  
  12         304  
7              
8 12     12   56 use B ();
  12         27  
  12         219  
9              
10 12     12   54 use Config;
  12         14  
  12         488  
11              
12 12     12   52 use base qw;
  12         20  
  12         1969  
13              
14             =head1 NAME
15              
16             B::RecDeparse - Deparse recursively into subroutines.
17              
18             =head1 VERSION
19              
20             Version 0.10
21              
22             =cut
23              
24             our $VERSION = '0.10';
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     5387 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   63 };
  12         15  
72              
73             sub _parse_args {
74 36 100   36   116 if (@_ % 2) {
75 1         6 require Carp;
76 1         196 Carp::croak('Optional arguments must be passed as key/value pairs');
77             }
78 35         122 my %args = @_;
79              
80 35         64 my $deparse = $args{deparse};
81 35 100       91 if (defined $deparse) {
82 24 100       103 if (!ref $deparse) {
    100          
83 6         14 $deparse = [ $deparse ];
84             } elsif (ref $deparse ne 'ARRAY') {
85 1         3 $deparse = [ ];
86             }
87             } else {
88 11         18 $deparse = [ ];
89             }
90              
91 35         54 my $level = $args{level};
92 35 100       82 $level = -1 unless defined $level;
93 35         48 $level = int $level;
94              
95 35         90 return $deparse, $level;
96             }
97              
98             sub new {
99 35     35 1 65853 my $class = shift;
100 35   100     255 $class = ref($class) || $class || __PACKAGE__;
101              
102 35         109 my ($deparse, $level) = _parse_args(@_);
103              
104 34         794 my $self = bless $class->SUPER::new(@$deparse), $class;
105              
106 34         63 $self->{brd_level} = $level;
107              
108 34         113 return $self;
109             }
110              
111             sub _recurse {
112 209   100 209   2249 return $_[0]->{brd_level} < 0 || $_[0]->{brd_cur} < $_[0]->{brd_level}
113             }
114              
115             sub compile {
116 1     1 0 10 my @args = @_;
117              
118 1         52 my $bd = B::Deparse->new();
119 1         4 my ($deparse, $level) = _parse_args(@args);
120              
121 1         6492 my $compiler = $bd->coderef2text(B::Deparse::compile(@$deparse));
122 1         43 $compiler =~ s/
123             ['"]? B::Deparse ['"]? \s* -> \s* (new) \s* \( ([^\)]*) \)
124             /B::RecDeparse->$1(deparse => [ $2 ], level => $level)/gx;
125 1     1   114 $compiler = eval 'sub ' . $compiler;
  1     1   14  
  1         2  
  1         454  
  1         5  
  1         2  
  1         138  
126 1 50       3 die if $@;
127              
128 1         13 return $compiler;
129             }
130              
131             sub init {
132 111     111 0 57722 my $self = shift;
133              
134 111         192 $self->{brd_cur} = 0;
135 111         167 $self->{brd_sub} = 0;
136 111         163 $self->{brd_seen} = { };
137              
138 111         1805 $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   73 no warnings 'redefine';
  12         20  
  12         5715  
147             *B::Deparse::single_delim = sub {
148 85     85   854 my $body = $_[2];
149              
150 85 100 66     961 if ((caller 1)[0] eq __PACKAGE__ and $body =~ s/^$key//) {
151 46         9546 return $body;
152             } else {
153 39         18399 $oldsd->(@_);
154             }
155             }
156             }
157              
158             sub deparse_sub {
159 123     123 0 164 my $self = shift;
160 123         137 my $cv = $_[0];
161              
162 123         120 my $name;
163 123 100       507 unless ($cv->CvFLAGS & B::CVf_ANON()) {
164 90         749 $name = $cv->GV->SAFENAME;
165             }
166              
167 123 100       430 local $self->{brd_seen}->{$name} = 1 if defined $name;
168 123         63979 return $self->SUPER::deparse_sub(@_);
169             }
170              
171             sub pp_entersub {
172 112     112 0 192 my $self = shift;
173              
174 112         211 my $body = do {
175 112         244 local $self->{brd_sub} = 1;
176 112         13803 $self->SUPER::pp_entersub(@_);
177             };
178              
179 112 100       288 $body =~ s/^&\s*(\w)/$1/ if $self->_recurse;
180              
181 112         9497 return $body;
182             }
183              
184             sub pp_refgen {
185 15     15 0 19 my $self = shift;
186              
187 15         15 return do {
188 15         26 local $self->{brd_sub} = 0;
189 15         1275 $self->SUPER::pp_refgen(@_);
190             }
191             }
192              
193             sub pp_srefgen {
194 0     0 0 0 my $self = shift;
195              
196 0         0 return do {
197 0         0 local $self->{brd_sub} = 0;
198 0         0 $self->SUPER::pp_srefgen(@_);
199             }
200             }
201              
202             sub pp_gv {
203 113     113 0 146 my $self = shift;
204              
205 113         836 my $gv = $self->gv_or_padgv($_[0]);
206 113 50       415 my $cv = $gv->FLAGS & B::SVf_ROK ? $gv->RV : undef;
207 113 50 0     345 my $name = $cv ? $cv->NAME_HEK || $cv->GV->NAME : $gv->NAME;
208 113   33     642 $cv ||= $gv->CV;
209 113         227 my $seen = $self->{brd_seen};
210              
211 113         110 my $body;
212 113 100 100     428 if (!$self->{brd_sub} or !$self->_recurse or $seen->{$name} or !$$cv
      100        
      100        
      66        
      100        
213             or !$cv->isa('B::CV') or $cv->ROOT->isa('B::NULL')) {
214 67         1721 $body = $self->SUPER::pp_gv(@_);
215             } else {
216 46         44 $body = do {
217 46         97 local @{$self}{qw} = (0, $self->{brd_cur} + 1);
  46         134  
218 46         144 local $seen->{$name} = 1;
219 46         464 'sub ' . $self->indent($self->deparse_sub($cv));
220             };
221              
222 46         82 if (FOOL_SINGLE_DELIM) {
223 46         111 $body = $key . $body;
224             } else {
225             $body .= '->';
226             }
227             }
228              
229 113         16118 return $body;
230             }
231              
232             =pod
233              
234             The following functions and methods from L are reimplemented by this module :
235              
236             =over 4
237              
238             =item *
239              
240             C
241              
242             =item *
243              
244             C
245              
246             =item *
247              
248             C
249              
250             =item *
251              
252             C
253              
254             =item *
255              
256             C
257              
258             =item *
259              
260             C
261              
262             =item *
263              
264             C
265              
266             =back
267              
268             Otherwise, L inherits all methods from L.
269              
270             =head1 EXPORT
271              
272             An object-oriented module shouldn't export any function, and so does this one.
273              
274             =head1 DEPENDENCIES
275              
276             L 5.8.1.
277              
278             L (standard since perl 5), L (since perl 5.00307) and L (since perl 5.005).
279              
280             =head1 AUTHOR
281              
282             Vincent Pit, C<< >>, L.
283              
284             You can contact me by mail or on C (vincent).
285              
286             =head1 BUGS
287              
288             Please report any bugs or feature requests to C, or through the web interface at L.
289             I will be notified, and then you'll automatically be notified of progress on your bug as I make changes.
290              
291             =head1 SUPPORT
292              
293             You can find documentation for this module with the perldoc command.
294              
295             perldoc B::RecDeparse
296              
297             Tests code coverage report is available at L.
298              
299             =head1 COPYRIGHT & LICENSE
300              
301             Copyright 2008,2009,2010,2011,2013,2014,2015 Vincent Pit, all rights reserved.
302              
303             This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.
304              
305             =cut
306              
307             1; # End of B::RecDeparse