Data-Decycle

 view release on metacpan or  search on metacpan

Makefile.PL  view on Meta::CPAN

    NAME                => 'Data::Decycle',
    AUTHOR              => q{Dan Kogai <dankogai+cpan@gmail.com>},
    VERSION_FROM        => 'lib/Data/Decycle.pm',
    ABSTRACT_FROM       => 'lib/Data/Decycle.pm',
    ($ExtUtils::MakeMaker::VERSION >= 6.3002
      ? ('LICENSE'=> 'perl')
      : ()),
    PL_FILES            => {},
    PREREQ_PM => {
        'Test::More' => 0,
	# 'PadWalker'  => 0,
    },
    dist                => { COMPRESS => 'gzip -9f', SUFFIX => 'gz', },
    clean               => { FILES => 'Data-Decycle-*' },
);

lib/Data/Decycle.pm  view on Meta::CPAN

our @EXPORT    = ();
our @EXPORT_OK = qw(recsub $CALLEE
  may_leak has_cyclic_ref decycle_deeply weaken_deeply
);
our %EXPORT_TAGS = ( all => [ @EXPORT, @EXPORT_OK ], );

BEGIN {
    require constant;
    constant->import(
        HAS_PADWALKER => eval {
            require PadWalker;
            $PadWalker::VERSION >= 1.0;
        }
    );
}

sub new {
    my $class = shift;
    my $self = bless [], $class;
    $self->add(@_);
}

lib/Data/Decycle.pm  view on Meta::CPAN

                next unless ref $_;
                return 1 if $CALLEE->( $_, $_[1] );
            }
        }
        elsif (UNIVERSAL::isa( $_[0], 'SCALAR' )
            || UNIVERSAL::isa( $_[0], 'REF' ) )
        {
            return $CALLEE->( ${ $_[0] }, $_[1] );
        }
        elsif ( HAS_PADWALKER && UNIVERSAL::isa( $_[0], 'CODE' ) ) {
            my $r = PadWalker::closed_over( $_[0] );
            return unless keys %$r;
            $CALLEE->( $r, $_[1] ) && return 1;
        }
        return;
    }
}

*_has_cyclic_ref = _mkfinder { 1 };
sub has_cyclic_ref($){ _has_cyclic_ref($_[0], {}) }

lib/Data/Decycle.pm  view on Meta::CPAN

        }
        elsif ( UNIVERSAL::isa( $_[0], 'ARRAY' ) ) {
            $CALLEE->( $_, $_[1] ) for @{ $_[0] };
        }
        elsif (UNIVERSAL::isa( $_[0], 'SCALAR' )
            || UNIVERSAL::isa( $_[0], 'REF' ) )
        {
            $CALLEE->( ${ $_[0] }, $_[1] );
        }
        elsif ( HAS_PADWALKER && UNIVERSAL::isa( $_[0], 'CODE' ) ) {
            my $r = PadWalker::closed_over( $_[0] );
            return unless keys %$r;
            $CALLEE->( $r, $_[1] );
        }
        return;
    };
}

*_decycle_deeply = _mkwalker { undef $_[0] };
sub decycle_deeply($) { _decycle_deeply( $_[0], {} ) }

lib/Data/Decycle.pm  view on Meta::CPAN

      my $guard = Data::Decycle->new(
        my $cyclic_sref = \my $dummy,
        my $cyclic_aref = [],
        my $cyclic_href = {}
      );
      $cyclic_sref = \$cyclic_sref;
      $cyclic_aref->[0] = $cyclic_aref;
      $cyclic_href->{cyclic} = $cyclic_href;
  }

=head2 Code Reference and PadWalker

If you have PadWalker, you can decycle closures, too.

  {
      my $guard = Data::Decycle->new;
      my $cref;
      $cref = sub{ $_[0] <= 1 ? 1 : $_[0] * $cref->($_[0] - 1) };
      $guard->add($cref);
      print $cref->(10);
  }

=head2 Functional Interface

lib/Data/Decycle.pm  view on Meta::CPAN

What happens when it reaches out of the block?  $guard will surely be
DESTROY()'ed.  So it is guaranteed to trigger $guard->DESTROY.  And in
there it applys C<decycle_deeply> to each reference registered.

Simple, huh?

=head1 DEPENDENCY

None except for core modules.

To handle code references correctly, you need to have L<PadWalker> installed.

=head1 EXPORT

None by default.  Please import explicitly.

=head1 METHODS

=over 4

=item new

lib/Data/Decycle.pm  view on Meta::CPAN

=item * Search CPAN

L<http://search.cpan.org/dist/Data-Decycle/>

=back

=head1 ACKNOWLEDGEMENTS

=over 4

=item L<PadWalker>

You need this if you want to handle code references properly.  When
you don't have one this module simply does nothing when it encounters
them.

=item L<Devel::Cycle>

Good for inspection -- rather overkill.  Decycling features missing.

=back

t/01-has_scalar_ref.t  view on Meta::CPAN

$href->{cycle} = $href;
ok has_cyclic_ref($href), "'$href' is cyclic";

bless $aref, 'Dummy';
ok has_cyclic_ref($aref), "'$aref' is cyclic";

bless $href, 'Dummy';
ok has_cyclic_ref($href), "'$href' is cyclic";

SKIP:{
    skip 'PadWalker not installed', 3 unless Data::Decycle::HAS_PADWALKER;
    my $cref;
    $cref = sub{ $_[0] <= 1 ? 1 : $_[0] * $cref->($_[0] - 1) };
    ok has_cyclic_ref($cref), "'$cref' is cyclic";
    $cref = sub{ shift };
    ok !has_cyclic_ref($cref), "'$cref' isn't cyclic";
    $cref = recsub { $_[0] <= 1 ? 1 : $_[0] * $CALLEE->($_[0]-1) };
    ok !has_cyclic_ref($cref), "'$cref' isn't cyclic";
}

t/02-decycle_deeply.t  view on Meta::CPAN

ok !has_cyclic_ref($aref), "'$aref' isn't cyclic";

my $href = {foo => 0};
ok !has_cyclic_ref($href), "'$href' isn't cyclic";
$href->{cycle} = $href;
ok has_cyclic_ref($href), "'$href' is cyclic";
decycle_deeply($href);
ok !has_cyclic_ref($sref), "'$href' isn't cyclic";

SKIP:{
    skip 'PadWalker not installed', 5 unless Data::Decycle::HAS_PADWALKER;
    my $cref;
    $cref = sub{ $_[0] <= 1 ? 1 : $_[0] * $cref->($_[0] - 1) };
    ok has_cyclic_ref($cref), "'$cref' is cyclic";
    is $cref->(10), 3628800, "($cref)->(10) is 3628800";
    {
	no warnings 'uninitialized';
	decycle_deeply($cref);
	ok !has_cyclic_ref($cref), "'$sref' isn't cyclic";
    }
    $cref = sub{ shift };

t/04-may_leak.t  view on Meta::CPAN

ok !may_leak($aref), "'$aref' may not leak";

my $href = {foo => 0};
ok !may_leak($href), "'$href' may not leak";
$href->{cycle} = $href;
ok may_leak($href), "'$href' may leak";
weaken_deeply($href);
ok !may_leak($href), "'$href' may not leak";

SKIP:{
    skip 'PadWalker not installed', 5 unless Data::Decycle::HAS_PADWALKER;
    my $cref;
    $cref = sub{ $_[0] <= 1 ? 1 : $_[0] * $cref->($_[0] - 1) };
    ok may_leak($cref), "'$cref' may leak";
    weaken_deeply($cref);
    ok may_leak($cref), "'$cref' may STILL leak";
    is $cref->(10), 3628800, "($cref)->(10) is 3628800";

    $cref = sub{ shift };
    ok !may_leak($cref), "'$cref' may not leak";
    $cref = recsub { $_[0] <= 1 ? 1 : $_[0] * $CALLEE->($_[0]-1) };



( run in 0.656 second using v1.01-cache-2.11-cpan-05444aca049 )