Moose::Exception::TypeConstraint is no longer a role
[gitmo/Moose.git] / lib / Moose / Meta / Attribute.pm
index 0b348d2..f0156fd 100644 (file)
@@ -4,8 +4,8 @@ package Moose::Meta::Attribute;
 use strict;
 use warnings;
 
-use Class::MOP ();
 use B ();
+use Class::Load qw(is_class_loaded load_class);
 use Scalar::Util 'blessed', 'weaken';
 use List::MoreUtils 'any';
 use Try::Tiny;
@@ -49,12 +49,7 @@ sub _error_thrower {
 
 sub throw_error {
     my $self = shift;
-    my $inv = $self->_error_thrower;
-    unshift @_, "message" if @_ % 2 == 1;
-    unshift @_, attr => $self if ref $self;
-    unshift @_, $inv;
-    my $handler = $inv->can("throw_error"); # to avoid incrementing depth by 1
-    goto $handler;
+    Moose::Util::throw(@_);
 }
 
 sub _inline_throw_error {
@@ -64,23 +59,13 @@ sub _inline_throw_error {
     # XXX ugh
     $inv = 'Moose::Meta::Class' unless $inv->can('_inline_throw_error');
 
-    # XXX ugh ugh UGH
-    my $class = $self->associated_class;
-    if ($class) {
-        my $class_name = B::perlstring($class->name);
-        my $attr_name = B::perlstring($self->name);
-        $args = 'attr => Class::MOP::class_of(' . $class_name . ')'
-              . '->find_attribute_by_name(' . $attr_name . '), '
-              . (defined $args ? $args : '');
-    }
-
     return $inv->_inline_throw_error($msg, $args)
 }
 
 sub new {
     my ($class, $name, %options) = @_;
     $class->_process_options($name, \%options) unless $options{__hack_no_process_options}; # used from clone()... YECHKKK FIXME ICKY YUCK GROSS
-    
+
     delete $options{__hack_no_process_options};
 
     my %attrs =
@@ -129,6 +114,8 @@ sub interpolate_class {
 
     if (my $traits = $options->{traits}) {
         my $i = 0;
+        my $has_foreign_options = 0;
+
         while ($i < @$traits) {
             my $trait = $traits->[$i++];
             next if ref($trait); # options to a trait we discarded
@@ -141,17 +128,28 @@ sub interpolate_class {
             push @traits, $trait;
 
             # are there options?
-            push @traits, $traits->[$i++]
-                if $traits->[$i] && ref($traits->[$i]);
+            if ($traits->[$i] && ref($traits->[$i])) {
+                $has_foreign_options = 1
+                    if any { $_ ne '-alias' && $_ ne '-excludes' } keys %{ $traits->[$i] };
+
+                push @traits, $traits->[$i++];
+            }
         }
 
         if (@traits) {
-            my $anon_class = Moose::Meta::Class->create_anon_class(
+            my %options = (
                 superclasses => [ $class ],
                 roles        => [ @traits ],
-                cache        => 1,
             );
 
+            if ($has_foreign_options) {
+                $options{weaken} = 0;
+            }
+            else {
+                $options{cache} = 1;
+            }
+
+            my $anon_class = Moose::Meta::Class->create_anon_class(%options);
             $class = $anon_class->name;
         }
     }
@@ -204,7 +202,7 @@ sub clone_and_inherit_options {
             $type_constraint = $options{isa};
         }
         else {
-            $type_constraint = Moose::Util::TypeConstraints::find_or_create_isa_type_constraint($options{isa});
+            $type_constraint = Moose::Util::TypeConstraints::find_or_create_isa_type_constraint($options{isa}, { package_defined_in => $options{definition_context}->{package} });
             (defined $type_constraint)
                 || $self->throw_error("Could not find the type constraint '" . $options{isa} . "'", data => $options{isa});
         }
@@ -218,7 +216,7 @@ sub clone_and_inherit_options {
             $type_constraint = $options{does};
         }
         else {
-            $type_constraint = Moose::Util::TypeConstraints::find_or_create_does_type_constraint($options{does});
+            $type_constraint = Moose::Util::TypeConstraints::find_or_create_does_type_constraint($options{does}, { package_defined_in => $options{definition_context}->{package} });
             (defined $type_constraint)
                 || $self->throw_error("Could not find the type constraint '" . $options{does} . "'", data => $options{does});
         }
@@ -349,7 +347,9 @@ sub _process_isa_option {
     else {
         $options->{type_constraint}
             = Moose::Util::TypeConstraints::find_or_create_isa_type_constraint(
-            $options->{isa} );
+            $options->{isa},
+            { package_defined_in => $options->{definition_context}->{package} }
+        );
     }
 }
 
@@ -366,7 +366,9 @@ sub _process_does_option {
     else {
         $options->{type_constraint}
             = Moose::Util::TypeConstraints::find_or_create_does_type_constraint(
-            $options->{does} );
+            $options->{does},
+            { package_defined_in => $options->{definition_context}->{package} }
+        );
     }
 }
 
@@ -690,7 +692,10 @@ sub _inline_check_constraint {
                   . 'do { local $_ = ' . $value . '; '
                       . $message . '->(' . $value . ')'
                   . '}',
-                    'data => ' . $value
+                    'class => "Moose::Exception::TypeConstraint"',
+                    'attribute_name => ' . $self->name,
+                    'type_name => ' . $self->type_constraint->name,
+                    'value => ' . $value,
                 ) . ';',
             '}',
         );
@@ -704,7 +709,10 @@ sub _inline_check_constraint {
                   . 'do { local $_ = ' . $value . '; '
                       . $message . '->(' . $value . ')'
                   . '}',
-                    'data => ' . $value
+                    'class => "Moose::Exception::TypeConstraint"',
+                    'attribute_name => ' . $self->name,
+                    'type_name => ' . $self->type_constraint->name,
+                    'value => ' . $value,
                 ) . ';',
             '}',
         );
@@ -732,7 +740,7 @@ sub _inline_weaken_value {
 
     my $mi = $self->associated_class->get_meta_instance;
     return (
-        $mi->inline_weaken_slot_value($instance, $self->name, $value),
+        $mi->inline_weaken_slot_value($instance, $self->name),
             'if ref ' . $value . ';',
     );
 }
@@ -808,6 +816,10 @@ sub get_value {
             $value = $self->_coerce_and_verify( $value, $instance );
 
             $self->set_initial_value($instance, $value);
+
+            if ( ref $value && $self->is_weak_ref ) {
+                $self->_weaken_value($instance);
+            }
         }
     }
 
@@ -889,6 +901,7 @@ sub _inline_init_from_default {
                $self->_inline_check_constraint($default, $tc, $message, $for_lazy))
             : (),
         $self->_inline_init_slot($instance, $default),
+        $self->_inline_weaken_value($instance, $default),
     );
 }
 
@@ -1024,6 +1037,7 @@ sub _process_accessors {
 
     if (
            $method
+        && !$method->is_stub
         && !$method->isa('Class::MOP::Method::Accessor')
         && (  !$self->definition_context
             || $method->package_name eq $self->definition_context->{package} )
@@ -1070,8 +1084,12 @@ sub install_delegation {
         my $class_name = $associated_class->name;
         my $name = "${class_name}::${handle}";
 
-            (!$associated_class->has_method($handle))
-                || $self->throw_error("You cannot overwrite a locally defined method ($handle) with a delegation", method_name => $handle);
+        if ( my $method = $associated_class->get_method($handle) ) {
+            $self->throw_error(
+                "You cannot overwrite a locally defined method ($handle) with a delegation",
+                method_name => $handle
+            ) unless $method->is_stub;
+        }
 
         # NOTE:
         # handles is not allowed to delegate
@@ -1134,7 +1152,7 @@ sub _canonicalize_handles {
         }
     }
 
-    Class::MOP::load_class($handles);
+    load_class($handles);
     my $role_meta = Class::MOP::class_of($handles);
 
     (blessed $role_meta && $role_meta->isa('Moose::Meta::Role'))
@@ -1167,7 +1185,7 @@ sub _get_delegate_method_list {
 sub _find_delegate_metaclass {
     my $self = shift;
     if (my $class = $self->_isa_metadata) {
-        unless ( Class::MOP::is_class_loaded($class) ) {
+        unless ( is_class_loaded($class) ) {
             $self->throw_error(
                 sprintf(
                     'The %s attribute is trying to delegate to a class which has not been loaded - %s',
@@ -1181,7 +1199,7 @@ sub _find_delegate_metaclass {
         return Class::MOP::Class->initialize($class);
     }
     elsif (my $role = $self->_does_metadata) {
-        unless ( Class::MOP::is_class_loaded($class) ) {
+        unless ( is_class_loaded($class) ) {
             $self->throw_error(
                 sprintf(
                     'The %s attribute is trying to delegate to a role which has not been loaded - %s',
@@ -1240,10 +1258,16 @@ sub verify_against_type_constraint {
     my $type_constraint = $self->type_constraint;
 
     $type_constraint->check($val)
-        || $self->throw_error("Attribute ("
+        || $self->throw_error(
+                superclass => 'Moose::Exception::TypeConstraint',
+                message => "Attribute ("
                  . $self->name
                  . ") does not pass the type constraint because: "
-                 . $type_constraint->get_message($val), data => $val, @_);
+                 . $type_constraint->get_message($val),
+                 value => $val,
+                 attribute_name => $self->name,
+                 type_name => $type_constraint->name,
+                 @_);
 }
 
 package Moose::Meta::Attribute::Custom::Moose;
@@ -1448,14 +1472,14 @@ I<Attribute (x) does not pass the type constraint (Int) with 'forty-two'>
 
 Before setting the value, a check is made on the type constraint of
 the attribute, if it has one, to see if the value passes it. If the
-value fails to pass, the set operation dies with a L</throw_error>.
+value fails to pass, the set operation dies.
 
 Any coercion to convert values is done before checking the type constraint.
 
 To check a value against a type constraint before setting it, fetch the
 attribute instance using L<Class::MOP::Class/find_attribute_by_name>,
 fetch the type_constraint from the attribute using L<Moose::Meta::Attribute/type_constraint>
-and call L<Moose::Meta::TypeConstraint/check>. See L<Moose::Cookbook::Basics::Recipe4>
+and call L<Moose::Meta::TypeConstraint/check>. See L<Moose::Cookbook::Basics::Company_Subtypes>
 for an example.
 
 =back