An immutable constructor called non-lazy attribute default subs twice.
Dave Rolsky [Fri, 21 Mar 2008 22:13:33 +0000 (22:13 +0000)]
Changes
lib/Moose/Meta/Method/Constructor.pm
t/300_immutable/007_immutable_default.t [new file with mode: 0644]

diff --git a/Changes b/Changes
index cbd3a1c..d2d4cbf 100644 (file)
--- a/Changes
+++ b/Changes
@@ -9,6 +9,12 @@ Revision history for Perl extension Moose
       as well. There will be 2 releases, and then it will
       be removed.
 
+    * Moose::Meta::Method::Constructor
+      - immutable classes which had non-lazy attributes were calling
+        the default generating sub twice in the constructor. (bug
+        found by Jesse Luehrs, fixed by Dave Rolsky)
+        - added tests for this (Dave Rolsky)
+
 0.40 Fri. March 14, 2008
     - I hate Pod::Coverage
 
index 40f7a9a..8c8e1db 100644 (file)
@@ -178,7 +178,7 @@ sub _generate_slot_initializer {
                 ('$type_constraints[' . $index . ']'),                
                 '$val'
             ) if ($is_moose && $attr->has_type_constraint);
-            push @source => $self->_generate_slot_assignment($attr, $default, $index);
+            push @source => $self->_generate_slot_assignment($attr, '$val', $index);
             push @source => '}'; # close - wrap this to avoid my $val overrite warnings           
 
         push @source => "}" if defined $attr->init_arg;
diff --git a/t/300_immutable/007_immutable_default.t b/t/300_immutable/007_immutable_default.t
new file mode 100644 (file)
index 0000000..bee24ef
--- /dev/null
@@ -0,0 +1,38 @@
+#!/usr/bin/perl
+
+use strict;
+use warnings;
+
+use Test::More tests => 2;
+
+{
+    package Foo;
+    use Moose;
+
+    our $foo_default_called = 0;
+
+    has foo => (
+        is      => 'rw',
+        isa     => 'Str',
+        default => sub { use Devel::StackTrace; warn Devel::StackTrace->new;$foo_default_called++; 'foo' },
+    );
+
+    our $bar_default_called = 0;
+
+    has bar => (
+        is      => 'rw',
+        isa     => 'Str',
+        lazy    => 1,
+        default => sub { $bar_default_called++; 'bar' },
+    );
+
+    __PACKAGE__->meta->make_immutable;
+}
+
+my $foo = Foo->new();
+
+is($Foo::foo_default_called, 1, "foo default was only called once during constructor");
+
+$foo->bar();
+
+is($Foo::bar_default_called, 1, "bar default was only called once when lazy attribute is accessed");