a weakened value should still be returned on set (fixes lazy + weak_ref)
Matt S Trout [Mon, 14 May 2012 07:33:07 +0000 (07:33 +0000)]
Changes
lib/Method/Generate/Accessor.pm
t/accessor-weaken.t

diff --git a/Changes b/Changes
index b2c2c13..215507d 100644 (file)
--- a/Changes
+++ b/Changes
@@ -1,3 +1,4 @@
+  - a weakened value should still be returned on set (fixes lazy + weak_ref)
   - add an explicit return to all exported subs so people don't accidentally
     rely on the return value
 
index b01ab04..05d4764 100644 (file)
@@ -399,9 +399,10 @@ sub _generate_core_set {
 sub _generate_simple_set {
   my ($self, $me, $name, $spec, $value) = @_;
   my $name_str = perlstring $name;
-  my $simple = $self->_generate_core_set($me, $name, $spec, $value);
 
   if ($spec->{weak_ref}) {
+    $value = '$preserve = '.$value;
+    my $simple = $self->_generate_core_set($me, $name, $spec, $value);
     require Scalar::Util;
 
     # Perl < 5.8.3 can't weaken refs to readonly vars
@@ -413,8 +414,10 @@ sub _generate_simple_set {
     #
     # but requires XS and is just too damn crazy
     # so simply throw a better exception
-    Moo::_Utils::lt_5_8_3() ? <<"EOC" : "Scalar::Util::weaken(${simple})";
+    my $weak_simple = "my \$preserve; Scalar::Util::weaken(${simple})";
+    Moo::_Utils::lt_5_8_3() ? <<"EOC" : $weak_simple;
 
+      my \$preserve;
       eval { Scalar::Util::weaken($simple); 1 } or do {
         if( \$@ =~ /Modification of a read-only value attempted/) {
           require Carp;
@@ -428,7 +431,7 @@ sub _generate_simple_set {
       };
 EOC
   } else {
-    $simple;
+    $self->_generate_core_set($me, $name, $spec, $value);
   }
 }
 
index d390c27..ec5b069 100644 (file)
@@ -7,6 +7,12 @@ use Test::More;
   use Moo;
 
   has one => (is => 'ro', weak_ref => 1);
+
+  package Foo2;
+
+  use Moo;
+
+  has one => (is => 'lazy', weak_ref => 1, default => sub { {} });
 }
 
 my $ref = {};
@@ -14,7 +20,13 @@ my $foo = Foo->new(one => $ref);
 is($foo->one, $ref, 'value present');
 ok(Scalar::Util::isweak($foo->{one}), 'value weakened');
 undef $ref;
-ok (!defined $foo->{one}, 'weak value gone');
+ok(!defined $foo->{one}, 'weak value gone');
+
+my $foo2 = Foo2->new;
+ok(my $ref2 = $foo2->one, 'value returned');
+ok(Scalar::Util::isweak($foo2->{one}), 'value weakened');
+undef $ref2;
+ok(!defined $foo->{one}, 'weak value gone');
 
 # test readonly SVs
 sub mk_ref { \ 'yay' };