adding lazy and handles to the has +foo form 0_24
Stevan Little [Tue, 3 Jul 2007 15:56:19 +0000 (15:56 +0000)]
Changes
lib/Moose.pm
lib/Moose/Meta/Attribute.pm
t/038_attribute_inherited_slot_specs.t

diff --git a/Changes b/Changes
index 857e0b3..f8a4583 100644 (file)
--- a/Changes
+++ b/Changes
@@ -7,6 +7,10 @@ Revision history for Perl extension Moose
       - added support for roles to be given as parameters 
         to the 'handles' option.
         - added tests and docs for this
+      - the has '+foo' attribute form now accepts changes to 
+        the lazy option, and the addition of a handles option
+        (but not changing the handles option)
+        - added tests and docs for this
 
     * Moose::Meta::Role
       - required methods are now fetched using find_method_by_name
index a4e670b..bc62262 100644 (file)
@@ -585,7 +585,7 @@ What is happening here is that B<My::Foo> is cloning the C<message> attribute
 from its parent class B<Foo>, retaining the C<is =E<gt> 'rw'> and C<isa =E<gt>
 'Str'> characteristics, but changing the value in C<default>.
 
-This feature is restricted somewhat, so as to try and enfore at least I<some>
+This feature is restricted somewhat, so as to try and force at least I<some>
 sanity into it. You are only allowed to change the following attributes:
 
 =over 4
@@ -606,11 +606,20 @@ Change if the attribute is required to have a value.
 
 Change the documentation string associated with the attribute.
 
+=item I<lazy>
+
+Change if the attribute lazily initializes the slot.
+
 =item I<isa>
 
 You I<are> allowed to change the type, B<if and only if> the new type is a
 subtype of the old type.
 
+=item I<handles>
+
+You are allowed to B<add> a new C<handles> definition, but you are B<not> 
+allowed to I<change> one. 
+
 =back
 
 =item B<before $name|@names =E<gt> sub { ... }>
index a8365a4..c1613da 100644 (file)
@@ -52,14 +52,23 @@ sub new {
 
 sub clone_and_inherit_options {
     my ($self, %options) = @_;
-    # you can change default, required, coerce and documentation 
+    # you can change default, required, coerce, documentation and lazy
     my %actual_options;
-    foreach my $legal_option (qw(default coerce required documentation)) {
+    foreach my $legal_option (qw(default coerce required documentation lazy)) {
         if (exists $options{$legal_option}) {
             $actual_options{$legal_option} = $options{$legal_option};
             delete $options{$legal_option};
         }
     }
+    
+    # handles can only be added, not changed
+    if ($options{handles}) {
+        confess "You can only add the 'handles' option, you cannot change it"
+            if $self->has_handles;
+        $actual_options{handles} = $options{handles};
+        delete $options{handles};
+    }
+    
     # isa can be changed, but only if the 
     # new type is a subtype    
     if ($options{isa}) {
index 88eb18b..791f042 100644 (file)
@@ -3,7 +3,7 @@
 use strict;
 use warnings;
 
-use Test::More tests => 57;
+use Test::More tests => 72;
 use Test::Exception;
 
 BEGIN {
@@ -11,6 +11,12 @@ BEGIN {
 }
 
 {
+    package Thing;
+    use Moose;
+    
+    sub hello   { 'Hello World (from Thing)' }
+    sub goodbye { 'Goodbye World (from Thing)' }    
+    
     package Foo;
     use Moose;
     use Moose::Util::TypeConstraints;
@@ -27,7 +33,11 @@ BEGIN {
     has 'baz' => (is => 'rw', isa => 'Ref');   
     has 'foo' => (is => 'rw', isa => 'FooStr');       
     
-    has 'gorch' => (is => 'ro');        
+    has 'gorch' => (is => 'ro'); 
+    has 'gloum' => (is => 'ro', default => sub {[]});  
+    
+    has 'bling' => (is => 'ro', isa => 'Thing');
+    has 'blang' => (is => 'ro', isa => 'Thing', handles => ['goodbye']);         
     
     # this one will work here ....
     has 'fail' => (isa => 'CodeRef');
@@ -37,14 +47,35 @@ BEGIN {
     use Moose;
     
     extends 'Foo';
+
+    ::lives_ok {     
+        has '+bar' => (default => 'Bar::bar');  
+    } '... we can change the default attribute option';        
+    
+    ::lives_ok {     
+        has '+baz' => (isa => 'ArrayRef');        
+    } '... we can add change the isa as long as it is a subtype';        
     
-    has '+bar' => (default => 'Bar::bar');  
-    has '+baz' => (isa     => 'ArrayRef');        
+    ::lives_ok {     
+        has '+foo' => (coerce => 1);    
+    } '... we can change/add coerce as an attribute option';            
+
+    ::lives_ok {     
+        has '+gorch' => (required => 1); 
+    } '... we can change/add required as an attribute option';    
+    
+    ::lives_ok { 
+        has '+gloum' => (lazy => 1);           
+    } '... we can change/add lazy as an attribute option';    
     
-    has '+foo'   => (coerce   => 1);    
-    has '+gorch' => (required => 1); 
+    ::lives_ok {
+        has '+bling' => (handles => ['hello']);        
+    } '... we can add the handles attribute option';
     
     # this one will *not* work here ....
+    ::dies_ok {
+        has '+blang' => (handles => ['hello']);        
+    } '... we can not alter the handles attribute option';    
     ::dies_ok { 
         has '+fail' => (isa => 'Ref');           
     } '... cannot create an attribute with an improper subtype relation';    
@@ -54,9 +85,6 @@ BEGIN {
     ::dies_ok { 
         has '+other_fail' => (weak_ref => 1);           
     } '... cannot create an attribute with an illegal option';    
-    ::dies_ok { 
-        has '+other_fail' => (lazy => 1);           
-    } '... cannot create an attribute with an illegal option';    
     
 }
 
@@ -134,6 +162,9 @@ ok(Bar->meta->has_attribute('foo'), '... Bar has a foo attr');
 ok(Bar->meta->has_attribute('bar'), '... Bar has a bar attr');
 ok(Bar->meta->has_attribute('baz'), '... Bar has a baz attr');
 ok(Bar->meta->has_attribute('gorch'), '... Bar has a gorch attr');
+ok(Bar->meta->has_attribute('gloum'), '... Bar has a gloum attr');
+ok(Bar->meta->has_attribute('bling'), '... Bar has a bling attr');
+ok(!Bar->meta->has_attribute('blang'), '... Bar has a blang attr');
 ok(!Bar->meta->has_attribute('fail'), '... Bar does not have a fail attr');
 ok(!Bar->meta->has_attribute('other_fail'), '... Bar does not have a fail attr');
 
@@ -148,7 +179,13 @@ isnt(Foo->meta->get_attribute('baz'),
      '... Foo and Bar have different copies of baz');          
 isnt(Foo->meta->get_attribute('gorch'), 
      Bar->meta->get_attribute('gorch'), 
-     '... Foo and Bar have different copies of gorch');     
+     '... Foo and Bar have different copies of gorch');
+isnt(Foo->meta->get_attribute('gloum'), 
+     Bar->meta->get_attribute('gloum'), 
+     '... Foo and Bar have different copies of gloum'); 
+isnt(Foo->meta->get_attribute('bling'), 
+     Bar->meta->get_attribute('bling'), 
+     '... Foo and Bar have different copies of bling');              
      
 ok(Bar->meta->get_attribute('bar')->has_type_constraint, 
    '... Bar::bar inherited the type constraint too');
@@ -168,9 +205,19 @@ ok(!Foo->meta->get_attribute('gorch')->is_required,
 ok(Bar->meta->get_attribute('gorch')->is_required, 
    '... Bar::gorch is a required attr');
    
+ok(!Foo->meta->get_attribute('gloum')->is_lazy, 
+   '... Foo::gloum is not a required attr');
+ok(Bar->meta->get_attribute('gloum')->is_lazy, 
+   '... Bar::gloum is a required attr');   
+   
 ok(!Foo->meta->get_attribute('foo')->should_coerce, 
   '... Foo::foo should not coerce');
 ok(Bar->meta->get_attribute('foo')->should_coerce, 
-   '... Bar::foo should coerce');    
+   '... Bar::foo should coerce');  
+   
+ok(!Foo->meta->get_attribute('bling')->has_handles, 
+   '... Foo::foo should not handles');
+ok(Bar->meta->get_attribute('bling')->has_handles, 
+   '... Bar::foo should handles');