]> git.vpit.fr Git - perl/modules/B-RecDeparse.git/blobdiff - lib/B/RecDeparse.pm
POD formatting nits
[perl/modules/B-RecDeparse.git] / lib / B / RecDeparse.pm
index da731d951e4a8e602565410e22ad334a75886bc4..35333fa72f97e900b60c64f2c35aa830602e1d6a 100644 (file)
@@ -1,12 +1,15 @@
 package B::RecDeparse;
 
+use 5.008;
+
 use strict;
 use warnings;
 
-use Carp qw/croak/;
+use B ();
+
 use Config;
 
-use base qw/B::Deparse/;
+use base qw<B::Deparse>;
 
 =head1 NAME
 
@@ -14,11 +17,11 @@ B::RecDeparse - Deparse recursively into subroutines.
 
 =head1 VERSION
 
-Version 0.01
+Version 0.04
 
 =cut
 
-our $VERSION = '0.01';
+our $VERSION = '0.04';
 
 =head1 SYNOPSIS
 
@@ -32,15 +35,18 @@ our $VERSION = '0.01';
 
 =head1 DESCRIPTION
 
-This module extends L<B::Deparse> by making you recursively replace subroutine calls encountered when deparsing.
+This module extends L<B::Deparse> by making it recursively replace subroutine calls encountered when deparsing.
 
-Please refer to L<B::Deparse> documentation for what to do and how to do it. Besides the constructor syntax, everything should work the same for the two modules.
+Please refer to L<B::Deparse> documentation for what to do and how to do it.
+Besides the constructor syntax, everything should work the same for the two modules.
 
 =head1 METHODS
 
 =head2 C<< new < deparse => [ @B__Deparse_opts ], level => $level > >>
 
-The L<B::RecDeparse> object constructor. You can specify the underlying L<B::Deparse> constructor arguments by passing a string or an array reference as the value of the C<deparse> key. The C<level> 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<B::Deparse> behaviour.
+The L<B::RecDeparse> object constructor.
+You can specify the underlying L<B::Deparse> constructor arguments by passing a string or an array reference as the value of the C<deparse> key.
+The C<level> 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<B::Deparse> behaviour.
 
 =cut
 
@@ -48,12 +54,17 @@ use constant {
  # p31268 made pp_entersub call single_delim
  FOOL_SINGLE_DELIM =>
      ($^V ge v5.9.5)
+  || ($^V lt v5.9.0 and $^V ge v5.8.9)
   || ($Config{perl_patchlevel} && $Config{perl_patchlevel} >= 31268)
 };
 
 sub _parse_args {
- croak 'Optional arguments must be passed as key/value pairs' if @_ % 2;
+ if (@_ % 2) {
+  require Carp;
+  Carp::croak('Optional arguments must be passed as key/value pairs');
+ }
  my %args = @_;
+
  my $deparse = $args{deparse};
  if (defined $deparse) {
   if (!ref $deparse) {
@@ -64,42 +75,54 @@ sub _parse_args {
  } else {
   $deparse = [ ];
  }
- my $level   = $args{level};
- $level      = -1  unless defined $level;
- $level      = int $level;
+
+ my $level = $args{level};
+ $level    = -1  unless defined $level;
+ $level    = int $level;
+
  return $deparse, $level;
 }
 
 sub new {
  my $class = shift;
  $class = ref($class) || $class || __PACKAGE__;
+
  my ($deparse, $level) = _parse_args(@_);
+
  my $self = bless $class->SUPER::new(@$deparse), $class;
+
  $self->{brd_level} = $level;
+
  return $self;
 }
 
 sub _recurse {
- return $_[0]->{brd_level} >= 0 && $_[0]->{brd_cur} >= $_[0]->{brd_level}
+ return $_[0]->{brd_level} < 0 || $_[0]->{brd_cur} < $_[0]->{brd_level}
 }
 
 sub compile {
- my $bd = B::Deparse->new();
  my @args = @_;
+
+ my $bd = B::Deparse->new();
  my ($deparse, $level) = _parse_args(@args);
+
  my $compiler = $bd->coderef2text(B::Deparse::compile(@$deparse));
  $compiler =~ s/
   ['"]? B::Deparse ['"]? \s* -> \s* (new) \s* \( ([^\)]*) \)
  /B::RecDeparse->$1(deparse => [ $2 ], level => $level)/gx;
  $compiler = eval 'sub ' . $compiler;
  die if $@;
+
  return $compiler;
 }
 
 sub init {
  my $self = shift;
- $self->{brd_cur} = 0;
- $self->{brd_sub} = 0;
+
+ $self->{brd_cur}  = 0;
+ $self->{brd_sub}  = 0;
+ $self->{brd_seen} = { };
+
  $self->SUPER::init(@_);
 }
 
@@ -107,10 +130,12 @@ my $key = $; . __PACKAGE__ . $;;
 
 if (FOOL_SINGLE_DELIM) {
  my $oldsd = *B::Deparse::single_delim{CODE};
+
  no warnings 'redefine';
  *B::Deparse::single_delim = sub {
   my $body = $_[2];
-  if ($body =~ s/^$key//) {
+
+  if ((caller 1)[0] eq __PACKAGE__ and $body =~ s/^$key//) {
    return $body;
   } else {
    $oldsd->(@_);
@@ -118,39 +143,65 @@ if (FOOL_SINGLE_DELIM) {
  }
 }
 
+sub deparse_sub {
+ my $self = shift;
+ my $cv   = $_[0];
+
+ my $name;
+ unless ($cv->CvFLAGS & B::CVf_ANON()) {
+  $name = $cv->GV->SAFENAME;
+ }
+
+ local $self->{brd_seen}->{$name} = 1 if defined $name;
+ return $self->SUPER::deparse_sub(@_);
+}
+
 sub pp_entersub {
  my $self = shift;
- $self->{brd_sub} = 1;
- my $body = $self->SUPER::pp_entersub(@_);
- $self->{brd_sub} = 0;
- $body =~ s/^&\s*(\w)/$1/ if not $self->_recurse;
+
+ my $body = do {
+  local $self->{brd_sub} = 1;
+  $self->SUPER::pp_entersub(@_);
+ };
+
+ $body =~ s/^&\s*(\w)/$1/ if $self->_recurse;
+
  return $body;
 }
 
 sub pp_refgen {
  my $self = shift;
- $self->{brd_sub} = 0;
- my $body = $self->SUPER::pp_refgen(@_);
- $self->{brd_sub} = 1;
- return $body;
+
+ return do {
+  local $self->{brd_sub} = 0;
+  $self->SUPER::pp_refgen(@_);
+ }
 }
 
 sub pp_gv {
  my $self = shift;
+
+ my $gv   = $self->gv_or_padgv($_[0]);
+ my $name = $gv->NAME;
+ my $seen = $self->{brd_seen};
+
  my $body;
- if ($self->{brd_sub} <= 0 || $self->_recurse) {
+ if ($self->{brd_sub} <= 0 || !$self->_recurse || $seen->{$name}) {
   $body = $self->SUPER::pp_gv(@_);
  } else {
-  my $gv = $self->gv_or_padgv($_[0]);
-  ++$self->{brd_cur};
-  $body = 'sub ' . $self->indent($self->deparse_sub($gv->CV));
-  --$self->{brd_cur};
+  $body = do {
+   local @{$self}{qw<brd_sub brd_cur>} = (0, $self->{brd_cur} + 1);
+   local $seen->{$name} = 1;
+   'sub ' . $self->indent($self->deparse_sub($gv->CV));
+  };
+
   if (FOOL_SINGLE_DELIM) {
    $body = $key . $body;
   } else {
    $body .= '->';
   }
  }
+
  return $body;
 }
 
@@ -158,13 +209,16 @@ sub pp_gv {
 
 =head2 C<init>
 
+=head2 C<deparse_sub>
+
 =head2 C<pp_entersub>
 
 =head2 C<pp_refgen>
 
 =head2 C<pp_gv>
 
-Functions and methods from L<B::Deparse> overriden by this module. Never call them directly.
+Functions and methods from L<B::Deparse> reimplemented by this module.
+Never call them directly.
 
 Otherwise, L<B::RecDeparse> inherits all methods from L<B::Deparse>.
 
@@ -180,11 +234,12 @@ L<Carp> (standard since perl 5), L<Config> (since perl 5.00307) and L<B::Deparse
 
 Vincent Pit, C<< <perl at profvince.com> >>, L<http://www.profvince.com>.
 
-You can contact me by mail or on #perl @ FreeNode (vincent or Prof_Vince).
+You can contact me by mail or on C<irc.perl.org> (vincent).
 
 =head1 BUGS
 
-Please report any bugs or feature requests to C<bug-b-recdeparse at rt.cpan.org>, or through the web interface at L<http://rt.cpan.org/NoAuth/ReportBug.html?Queue=B-RecDeparse>.  I will be notified, and then you'll automatically be notified of progress on your bug as I make changes.
+Please report any bugs or feature requests to C<bug-b-recdeparse at rt.cpan.org>, or through the web interface at L<http://rt.cpan.org/NoAuth/ReportBug.html?Queue=B-RecDeparse>.
+I will be notified, and then you'll automatically be notified of progress on your bug as I make changes.
 
 =head1 SUPPORT
 
@@ -196,7 +251,7 @@ Tests code coverage report is available at L<http://www.profvince.com/perl/cover
 
 =head1 COPYRIGHT & LICENSE
 
-Copyright 2008 Vincent Pit, all rights reserved.
+Copyright 2008,2009,2010,2011 Vincent Pit, all rights reserved.
 
 This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.