Docs for things in Class::MOP::Attribute + tests for trigger behaviours
Tomas Doran [Mon, 6 Oct 2008 16:14:51 +0000 (16:14 +0000)]
Changes
lib/Moose.pm
t/020_attributes/004_attribute_triggers.t

diff --git a/Changes b/Changes
index 8412e68..c783632 100644 (file)
--- a/Changes
+++ b/Changes
@@ -1,6 +1,10 @@
 Revision history for Perl extension Moose
 
 0.59
+    * Moose
+      - Add abridged documentation for builder/default/initializer/
+        predicate, and link to more details sections in 
+        Class::MOP::Attribute. (t0m)
     * Moose::Util::TypeConstraints
       - removed prototypes from all but the &-based stuff (mst)
     * Moose::Util::TypeConstraints
@@ -11,6 +15,8 @@ Revision history for Perl extension Moose
       - Some tests that used Test::Warn if it was available failed
         with older versions of Test::Warn. Reported by Fayland. (Dave
         Rolsky)
+      - Test firing behavior of triggers in relation to builder/default/
+        lazy_build. (t0m)
     * Moose::Meta::Class
       - In create(), do not pass "roles" option to the superclass
         - added related test that creates an anon metaclass with
index 2ddb8bd..4e95778 100644 (file)
@@ -418,7 +418,8 @@ only). These will create either a read/write accessor or a read-only
 accessor respectively, using the same name as the C<$name> of the attribute.
 
 If you need more control over how your accessors are named, you can use the
-I<reader>, I<writer> and I<accessor> options inherited from
+L<reader|Class::MOP::Attribute#reader>, I<|Class::MOP::Attribute#writer> and 
+I<|Class::MOP::Attribute#accessor> options inherited from 
 L<Class::MOP::Attribute>, however if you use those, you won't need the I<is> 
 option.
 
@@ -471,7 +472,11 @@ The I<trigger> option is a CODE reference which will be called after the value o
 the attribute is set. The CODE ref will be passed the instance itself, the
 updated value and the attribute meta-object (this is for more advanced fiddling
 and can typically be ignored). You B<cannot> have a trigger on a read-only
-attribute.
+attribute. 
+
+B<NOTE:> Triggers will only fire when you B<assign> to the attribute,
+either in the constructor, or using the writer. Default and built values will
+B<not> cause the trigger to be fired.
 
 =item I<handles =E<gt> ARRAY | HASH | REGEXP | ROLE | CODE>
 
@@ -606,6 +611,37 @@ resolved to a class name.
 Also see L<Moose::Cookbook::Meta::Recipe3> for a metaclass trait
 example.
 
+=item I<builder>
+
+The value of this key is the name of the method that will be called to obtain the value used to 
+initialize the attribute. See the documentation in
+L<Class::MOP::Attribute|Class::MOP::Attribute#builder> for more information.
+
+=item I<default>
+
+The value of this key is the default value which will initialize the attribute.
+
+NOTE: If the value is a simple scalar (string or number), then it can be just passed as is. 
+However, if you wish to initialize it with a HASH or ARRAY ref, then you need to wrap that inside a CODE reference. 
+See the documentation in L<Class::MOP::Attribute|Class::MOP::Attribute#default> for more information.
+
+=item I<initializer>
+
+This may be a method name (referring to a method on the class with this attribute) or a CODE ref. 
+The initializer is used to set the attribute value on an instance when the attribute is set during 
+instance initialization (but not when the value is being assigned to). See the documentation in
+L<Class::MOP::Attribute|Class::MOP::Attribute#initializer> for more information.
+
+=item I<clearer>
+
+Allows you to clear the value, see the documentation in 
+L<Class::MOP::Attribute|Class::MOP::Attribute#clearer> for more information.
+
+=item I<predicate>
+
+Basic test to see if a value has been set in the attribute, see the documentation in 
+L<Class::MOP::Attribute|Class::MOP::Attribute#predicate> for more information.
+
 =back
 
 =item B<has +$name =E<gt> %options>
index 0695dc3..637d604 100644 (file)
@@ -5,7 +5,7 @@ use warnings;
 
 use Scalar::Util 'isweak';
 
-use Test::More tests => 25;
+use Test::More tests => 36;
 use Test::Exception;
 
 
@@ -115,4 +115,46 @@ use Test::Exception;
     } '... a trigger must be a CODE ref';    
 }
 
+# Triggers do not fire on built values
+
+{
+    package Blarg;
+    use Moose;
+
+    our %trigger_calls;
+    our %trigger_vals;
+    has foo => (is => 'rw', default => sub { 'default foo value' },
+                trigger => sub { my ($self, $val, $attr) = @_;
+                                 $trigger_calls{foo}++;
+                                 $trigger_vals{foo} = $val });
+    has bar => (is => 'rw', lazy_build => 1,
+                trigger => sub { my ($self, $val, $attr) = @_;
+                                 $trigger_calls{bar}++;
+                                 $trigger_vals{bar} = $val });
+    sub _build_bar { return 'default bar value' }
+    has baz => (is => 'rw', builder => '_build_baz',
+                trigger => sub { my ($self, $val, $attr) = @_;
+                                 $trigger_calls{baz}++;
+                                 $trigger_vals{baz} = $val });
+    sub _build_baz { return 'default baz value' }
+}
+
+{
+    my $blarg;
+    lives_ok { $blarg = Blarg->new; } 'Blarg->new() lives';
+    ok($blarg, 'Have a $blarg');
+    foreach my $attr (qw/foo bar baz/) {
+        is($blarg->$attr(), "default $attr value", "$attr has default value");
+    }
+    is_deeply(\%Blarg::trigger_calls, {}, 'No triggers fired');
+    foreach my $attr (qw/foo bar baz/) {
+        $blarg->$attr("Different $attr value");
+    }
+    is_deeply(\%Blarg::trigger_calls, { map { $_ => 1 } qw/foo bar baz/ }, 'All triggers fired once on assign');
+    is_deeply(\%Blarg::trigger_vals, { map { $_ => "Different $_ value" } qw/foo bar baz/ }, 'All triggers given assigned values');
+
+    lives_ok { $blarg => Blarg->new( map { $_ => "Yet another $_ value" } qw/foo bar baz/ ) } '->new() with parameters';
+    is_deeply(\%Blarg::trigger_calls, { map { $_ => 2 } qw/foo bar baz/ }, 'All triggers fired once on construct');
+    is_deeply(\%Blarg::trigger_vals, { map { $_ => "Yet another $_ value" } qw/foo bar baz/ }, 'All triggers given assigned values');
+}