From: Matt S Trout Date: Sat, 20 Jun 2009 21:27:47 +0000 (-0400) Subject: redistributing modifications to alternative method executions brings gratification X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?p=gitmo%2FMooseX-Antlers.git;a=commitdiff_plain;h=9b97c7a2c61d538ff34a89264d68cadc5363953c redistributing modifications to alternative method executions brings gratification --- diff --git a/tracer.pl b/tracer.pl index a170ace..fbc08e5 100644 --- a/tracer.pl +++ b/tracer.pl @@ -97,49 +97,66 @@ package Ref::Replacer; # as yet use Moose; -# ensure we have next::method available - just because Moose loads it -# as a side effect doesn't mean it's clever to rely on that -use MRO::Compat (); use Scalar::Util qw(refaddr isweak); use namespace::clean -except => 'meta'; extends 'Data::Visitor'; -with 'Visitor::NameTracking'; +# we need name tracking but have to apply the role at the end of the file +# so that our around modifiers end up within the name tracking around +# instead of outside - otherwise e.g. array value weakening goes wrong has 'external_mappings' => (is => 'ro', lazy => 1, default => sub { {} }); has 'weaken_these' => (is => 'ro', lazy => 1, default => sub { {} }); has 'map_these' => (is => 'ro', lazy => 1, default => sub { {} }); -# fairly sure an around modifier will get severely fucked up here -# in that the copying of @_ will lose the weakness we need to check - -sub visit_ref { - my $self = shift; - - # have to test $_[0] directly since copying a weak ref gives a strong ref - -warn $self->_current_trace_name; -warn $_[0]; - if (isweak $_[0]) { -warn "got here"; - $self->weaken_these->{$self->_current_trace_name} = 1; - } +around visit_ref => sub { + my ($orig, $self) = (shift, shift); + my $value = $_[0]; # if we've got a mapping for a reference (i.e. it's supplied from # somewhere else) then we need to record where we are and then # return undef for the fmap process so we serialize an undefined # value and the fixup puts the external reference back in later - if (my $m = $self->external_mappings->{refaddr $_[0]}) { + if (my $m = $self->external_mappings->{refaddr $value}) { $self->map_these->{$self->_current_trace_name} = $m; return undef; } - return $self->next::method(@_); -} + return $self->$orig(@_); +}; + +around visit_hash_value => sub { + my ($orig, $self) = (shift, shift); + my ($value, $key, $hash) = @_; + if (isweak $hash->{$key}) { + $self->weaken_these->{$self->_current_trace_name} = 1; + } + return $self->$orig(@_); +}; -sub _register_mapping { $_[2] } +around visit_array_entry => sub { + my ($orig, $self) = (shift, shift); + my ($value, $index, $array) = @_; + if (isweak $array->[$index]) { + $self->weaken_these->{$self->_current_trace_name} = 1; + } + return $self->$orig(@_); +}; + +around visit_scalar => sub { + my ($orig, $self) = (shift, shift); + my $scalar = $_[0]; + if (isweak $$scalar) { + $self->weaken_these->{$self->_current_trace_name} = 1; + } + return $self->$orig(@_); +}; + +# now it's safe to apply the role + +with 'Visitor::NameTracking'; sub fixup_code { my $self = shift; @@ -233,6 +250,8 @@ my $flimflam = { }; weaken($flimflam->{weak_one} = $flimflam->{one}); +weaken($flimflam->{weak_member}[0] = $flimflam->{bard}); +weaken(${$flimflam->{weak_scalar}} = $flimflam->{bard_guts}); my $replacer = Ref::Replacer->new({ external_mappings => $result,