Add illigal inheritance process (Moose 1.09 feature)
gfx [Mon, 26 Jul 2010 11:24:13 +0000 (20:24 +0900)]
lib/Mouse/Meta/Attribute.pm
lib/Mouse/Meta/Class.pm
t/020_attributes/009_attribute_inherited_slot_specs.t [moved from t/020_attributes/failing/009_attribute_inherited_slot_specs.t with 95% similarity]

index 6d8bb3a..12dead6 100644 (file)
@@ -192,20 +192,29 @@ sub _throw_type_constraint_error {
     );
 }
 
+sub illegal_options_for_inheritance {
+    return qw(is reader writer accessor clearer predicate);
+}
+
 sub clone_and_inherit_options{
     my $self = shift;
     my $args = $self->Mouse::Object::BUILDARGS(@_);
 
-    my($attribute_class, @traits) = ref($self)->interpolate_class($args);
+    foreach my $illegal($self->illegal_options_for_inheritance) {
+        if(exists $args->{$illegal}) {
+            $self->throw_error("Illegal inherited option: $illegal");
+        }
+    }
 
-    $args->{traits} = \@traits if @traits;
-    # do not inherit the 'handles' attribute
     foreach my $name(keys %{$self}){
-        if(!exists $args->{$name} && $name ne 'handles'){
-            $args->{$name} = $self->{$name};
+        if(!exists $args->{$name}){
+            $args->{$name} = $self->{$name}; # inherit from self
         }
     }
 
+    my($attribute_class, @traits) = ref($self)->interpolate_class($args);
+    $args->{traits} = \@traits if @traits;
+
     # remove temporary caches
     foreach my $attr(keys %{$args}){
         if($attr =~ /\A _/xms){
@@ -213,6 +222,11 @@ sub clone_and_inherit_options{
         }
     }
 
+    # remove default if lazy_build => 1
+    if($args->{lazy_build}) {
+        delete $args->{default};
+    }
+
     return $attribute_class->new($self->name, $args);
 }
 
@@ -329,6 +343,10 @@ sub install_accessors{
         my %handles = $attribute->_canonicalize_handles($attribute->{handles});
 
         while(my($handle, $method_to_call) = each %handles){
+            if($metaclass->has_method($handle)) {
+                $attribute->throw_error("You cannot overwrite a locally defined method ($handle) with a delegation");
+            }
+
             $metaclass->add_method($handle =>
                 $attribute->_make_delegation_method(
                     $handle, $method_to_call));
index a21c83d..e2eb4bf 100644 (file)
@@ -209,9 +209,12 @@ sub add_attribute {
 
     weaken( $attr->{associated_class} = $self );
 
+    # install accessors first
+    $attr->install_accessors();
+
+    # then register the attribute to the metaclass
     $attr->{insertion_order} = keys %{ $self->{attributes} };
     $self->{attributes}{$attr->name} = $attr;
-    $attr->install_accessors();
 
     if(!$attr->{associated_methods} && ($attr->{is} || '') ne 'bare'){
         Carp::carp(qq{Attribute ($name) of class }.$self->name
@@ -3,12 +3,19 @@
 use strict;
 use warnings;
 
-use Test::More tests => 84;
+use Test::More;
 use Test::Exception;
 
 
-
 {
+    package Thing::Meta::Attribute;
+    use Mouse;
+
+    extends 'Mouse::Meta::Attribute';
+    around illegal_options_for_inheritance => sub {
+        return (shift->(@_), qw/trigger/);
+    };
+
     package Thing;
     use Mouse;
 
@@ -44,7 +51,7 @@ use Test::Exception;
 
     # this one will work here ....
     has 'fail' => (isa => 'CodeRef', is => 'bare');
-    has 'other_fail' => (is => 'bare');
+    has 'other_fail' => (metaclass => 'Thing::Meta::Attribute', is => 'bare', trigger => sub { });
 
     package Bar;
     use Mouse;
@@ -195,15 +202,9 @@ 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('bunch_of_stuff'), '... Bar does have a bunch_of_stuff attr');
-{
-local $TODO = 'not supported';
-ok(!Bar->meta->has_attribute('blang'), '... Bar does not have a blang attr');
-}
+ok(!Bar->meta->has_attribute('blang'), '... Bar has a blang attr');
 ok(Bar->meta->has_attribute('fail'), '... Bar has a fail attr');
-{
-local $TODO = 'not supported';
 ok(!Bar->meta->has_attribute('other_fail'), '... Bar does not have an other_fail attr');
-}
 
 isnt(Foo->meta->get_attribute('foo'),
      Bar->meta->get_attribute('foo'),
@@ -267,4 +268,4 @@ ok(!Foo->meta->get_attribute('bling')->has_handles,
 ok(Bar->meta->get_attribute('bling')->has_handles,
    '... Bar::foo should handles');
 
-
+done_testing;