File Coverage

blib/lib/B/RecDeparse.pm
Criterion Covered Total %
statement 102 102 100.0
branch 23 26 88.4
condition 22 32 68.7
subroutine 20 20 100.0
pod 1 7 14.2
total 168 187 89.8


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