Data-Decycle
view release on metacpan or search on metacpan
Changes
MANIFEST This list of files
Makefile.PL
README
lib/Data/Decycle.pm
t/00-load.t
t/01-has_scalar_ref.t
t/02-decycle_deeply.t
t/03-weaken_deeply.t
t/04-may_leak.t
t/manifest.t
t/pod-coverage.t
t/pod.t
META.yml Module meta-data (added by MakeMaker)
lib/Data/Decycle.pm view on Meta::CPAN
#
# $Id: Decycle.pm,v 0.2 2010/08/23 09:11:03 dankogai Exp dankogai $
#
package Data::Decycle;
use 5.008001;
use warnings;
use strict;
use Carp;
use Scalar::Util qw/refaddr weaken isweak/;
our $VERSION = sprintf "%d.%02d", q$Revision: 0.2 $ =~ /(\d+)/g;
our $DEBUG = 0;
use base 'Exporter';
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;
}
lib/Data/Decycle.pm view on Meta::CPAN
return unless keys %$r;
$CALLEE->( $r, $_[1] );
}
return;
};
}
*_decycle_deeply = _mkwalker { undef $_[0] };
sub decycle_deeply($) { _decycle_deeply( $_[0], {} ) }
*_weaken_deeply = _mkwalker {
weaken $_[0] unless UNIVERSAL::isa( $_[0], 'CODE' )
};
sub weaken_deeply($) { _weaken_deeply( $_[0], {} ) }
1; # End of Data::Decycle
__END__
=head1 NAME
Data::Decycle - (Cyclic|Circular) reference decycler
=head1 VERSION
lib/Data/Decycle.pm view on Meta::CPAN
}
=head2 Functional Interface
You can also cope with circular references explicitly
use Data::Decycle ':all';
my $obj = bless {}, 'Dummy';
$obj->{me} = $obj;
print may_leak($obj); # true
weaken_deeply($obj);
print may_leak($obj); # false
print has_cyclic_ref($obj); # true
decycle_deeply($obj);
print $obj->{me} == undef; # true
=head2 as a base class
You can also use it as a base class.
{
lib/Data/Decycle.pm view on Meta::CPAN
}
{
my $mom = Dummy->new( {} );
my $son = Dummy->new( {} );
say "($mom) has cyclic ref ? ", $mom->has_cyclic_ref ? 'yes' : 'no';
say "($son) may leak ? ", $son->may_leak? 'yes' : 'no';
$mom->{son} = $son;
$son->{mom} = $mom;
say "($mom) has cyclic ref ? ", $mom->has_cyclic_ref ? 'yes' : 'no';
say "($son) may leak ? ", $son->may_leak? 'yes' : 'no';
$mom->weaken_deeply;
$son->weaken_deeply;
say "($mom) has cyclic ref ? ", $mom->has_cyclic_ref ? 'yes' : 'no';
say "($son) may leak ? ", $son->may_leak? 'yes' : 'no';
}
=head1 DESCRIPTION
Perl programmers love to hate cyclic References, or circular
references. It easly leaks out of perl's reference-counter based
garbage collection and stays there until perl exits.
Even with the introduction of weak references in Perl 5.8, you still
have to tell perl explicitly to weaken references and which reference
to weaken is tricky.
use Devel::Peek;
use Scalar::Util qw/weaken/;
my $obj = {you => $ENV{USER}};
$obj->{me} = $obj;
weaken($obj); # wrong
weaken($obj->{me}) # right;
In addition to that, weak references do not work with code references.
my $cref;
$cref = sub { $_[0] <= 1 ? 1 : $_[0] * $cref->( $_[0] - 1 ) };
print $cref->(10);
weaken($cref); # does undef($cref)
print $cref->(10); # goodbye
This module offers something easier than that.
=head2 HOW DOES IT WORK?
See the source :-p
Okay, I'll be nicer. Consider the code below again.
lib/Data/Decycle.pm view on Meta::CPAN
checks if C<$obj> may leak. That is, contains a circular reference
that is not weak.
=head2 has_cyclic_ref($obj)
checks if cyclic reference exists in C<$obj>.
=head2 decycle_deeply($obj)
C<undef>s all duplicate references in C<$obj> thus breaks all cyclic
reference. Unlike C<weaken_deeply>, it decycles even code
references. You shouldn't call it yourself; let C<decycle> take care
of it.
=head2 weaken_deeply($obj)
weaken all duplicate references in C<$obj>. Unlike C<decycle_deeply>
it leaves code references intact. So you can safely call it but you
are at your own if C<$obj> contains a code reference that cycles.
=head2 recsub { }
Consider the code below:
my $fact;
$fact = sub { $_[0] <= 1 ? 1 : $_[0] * $fact->($_[0]-1) };
t/03-weaken_deeply.t view on Meta::CPAN
#
# $Id: 03-weaken_deeply.t,v 0.1 2010/08/22 19:58:45 dankogai Exp $
#
use strict;
use warnings;
use Test::More;
use Scalar::Util qw/isweak/;
use Data::Decycle qw/weaken_deeply/;
plan tests => 6;
{
my $sref;
$sref = \$sref;
bless $sref, 'Dummy';
ok !isweak($sref), "$sref is not a weak reference";
weaken_deeply($sref);
ok isweak($sref), "$sref is a weak reference now";
}
{
my $aref = bless [], 'Dummy';
$aref->[0] = $aref;
ok !isweak($aref->[0]), "($aref)->[0] is not a weak reference";
weaken_deeply($aref);
ok isweak($aref->[0]), "($aref)->[0] is a weak reference now";
}
{
my $href = bless {}, 'Dummy';
$href->{cyclic} = $href;
ok !isweak($href->{cyclic}), "($href)->{cyclic} is not a weak reference";
weaken_deeply($href);
ok isweak($href->{cyclic}), "($href)->{cyclic} is a weak reference now";
}
t/04-may_leak.t view on Meta::CPAN
#
# $Id: 04-may_leak.t,v 0.1 2010/08/22 19:58:45 dankogai Exp $
#
use strict;
use warnings;
use Test::More;
use Data::Decycle qw/may_leak weaken_deeply recsub $CALLEE/;
plan tests => 13;
my $sref = 'scalar';
ok !may_leak($sref), "'$sref' may not leak";
$sref = \$sref;
ok may_leak($sref), "'$sref' is leak";
weaken_deeply($sref);
ok !may_leak($sref), "'$sref' may not leak";
my $aref = [0];
ok !may_leak($aref), "'$aref' may not leak";
$aref->[1] = $aref;
weaken_deeply($aref);
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) };
ok !may_leak($cref), "'$cref' may not leak";
}
( run in 0.624 second using v1.01-cache-2.11-cpan-65fba6d93b7 )