Revert "give unique names to method modifiers"
[gitmo/Class-MOP.git] / lib / Class / MOP / Class.pm
index 4e02264..8810338 100644 (file)
@@ -8,14 +8,13 @@ use Class::MOP::Instance;
 use Class::MOP::Method::Wrapped;
 use Class::MOP::Method::Accessor;
 use Class::MOP::Method::Constructor;
-use Class::MOP::Class::Immutable::Class::MOP::Class;
 
 use Carp         'confess';
 use Scalar::Util 'blessed', 'weaken';
 use Sub::Name 'subname';
 use Devel::GlobalDestruction 'in_global_destruction';
 
-our $VERSION   = '0.86';
+our $VERSION   = '0.89';
 $VERSION = eval $VERSION;
 our $AUTHORITY = 'cpan:STEVAN';
 
@@ -197,17 +196,17 @@ sub _check_metaclass_compatibility {
             : ref($super_meta);
 
         ($self->isa($super_meta_type))
-            || confess "Class::MOP::class_of(" . $self->name . ") => ("
+            || confess "The metaclass of " . $self->name . " ("
                        . (ref($self)) . ")" .  " is not compatible with the " .
-                       "Class::MOP::class_of(".$superclass_name . ") => ("
+                       "metaclass of its superclass, ".$superclass_name . " ("
                        . ($super_meta_type) . ")";
         # NOTE:
         # we also need to check that instance metaclasses
         # are compatibile in the same the class.
         ($self->instance_metaclass->isa($super_meta->instance_metaclass))
-            || confess "Class::MOP::class_of(" . $self->name . ")->instance_metaclass => (" . ($self->instance_metaclass) . ")" .
+            || confess "The instance metaclass for " . $self->name . " (" . ($self->instance_metaclass) . ")" .
                        " is not compatible with the " .
-                       "Class::MOP::class_of(" . $superclass_name . ")->instance_metaclass => (" . ($super_meta->instance_metaclass) . ")";
+                       "instance metaclass of its superclass, " . $superclass_name . " (" . ($super_meta->instance_metaclass) . ")";
     }
 }
 
@@ -251,21 +250,23 @@ sub _check_metaclass_compatibility {
         return if in_global_destruction(); # it'll happen soon anyway and this just makes things more complicated
 
         no warnings 'uninitialized';
-        return unless $self->name =~ /^$ANON_CLASS_PREFIX/;
+        my $name = $self->name;
+        return unless $name =~ /^$ANON_CLASS_PREFIX/;
         # Moose does a weird thing where it replaces the metaclass for
         # class when fixing metaclass incompatibility. In that case,
         # we don't want to clean out the namespace now. We can detect
         # that because Moose will explicitly update the singleton
         # cache in Class::MOP.
-        my $current_meta = Class::MOP::get_metaclass_by_name($self->name);
+        my $current_meta = Class::MOP::get_metaclass_by_name($name);
         return if $current_meta ne $self;
 
-        my ($serial_id) = ($self->name =~ /^$ANON_CLASS_PREFIX(\d+)/);
+        my ($serial_id) = ($name =~ /^$ANON_CLASS_PREFIX(\d+)/);
         no strict 'refs';
-        foreach my $key (keys %{$ANON_CLASS_PREFIX . $serial_id}) {
-            delete ${$ANON_CLASS_PREFIX . $serial_id}{$key};
-        }
-        delete ${'main::' . $ANON_CLASS_PREFIX}{$serial_id . '::'};
+        @{$name . '::ISA'} = ();
+        %{$name . '::'}    = ();
+        delete ${$ANON_CLASS_PREFIX}{$serial_id . '::'};
+
+        Class::MOP::remove_metaclass_by_name($name);
     }
 
 }
@@ -371,7 +372,11 @@ sub _construct_instance {
     my $class = shift;
     my $params = @_ == 1 ? $_[0] : {@_};
     my $meta_instance = $class->get_meta_instance();
-    my $instance = $meta_instance->create_instance();
+    # FIXME:
+    # the code below is almost certainly incorrect
+    # but this is foreign inheritance, so we might
+    # have to kludge it in the end.
+    my $instance = $params->{__INSTANCE__} || $meta_instance->create_instance();
     foreach my $attr ($class->get_all_attributes()) {
         $attr->initialize_instance_slot($meta_instance, $instance, $params);
     }
@@ -623,7 +628,7 @@ sub add_method {
 
     my ( $current_package, $current_name ) = Class::MOP::get_code_info($body);
 
-    if ( $current_name eq '__ANON__' ) {
+    if ( !defined $current_name || $current_name eq '__ANON__' ) {
         my $full_method_name = ($self->name . '::' . $method_name);
         subname($full_method_name => $body);
     }
@@ -855,7 +860,12 @@ sub add_attribute {
     $self->get_attribute_map->{$attribute->name} = $attribute;
 
     # invalidate package flag here
-    my $e = do { local $@; eval { $attribute->install_accessors() }; $@ };
+    my $e = do {
+        local $@;
+        local $SIG{__DIE__};
+        eval { $attribute->install_accessors() };
+        $@;
+    };
     if ( $e ) {
         $self->remove_attribute($attribute->name);
         die $e;
@@ -1085,25 +1095,38 @@ sub _immutable_metaclass {
             $trait, 'ForMetaClass', ref($self);
     }
 
-    if ( Class::MOP::is_class_loaded($class_name) ) {
-        if ( $class_name->isa($trait) ) {
-            return $class_name;
+    return $class_name
+        if Class::MOP::is_class_loaded($class_name);
+
+    # If the metaclass is a subclass of CMOP::Class which has had
+    # metaclass roles applied (via Moose), then we want to make sure
+    # that we preserve that anonymous class (see Fey::ORM for an
+    # example of where this matters).
+    my $meta_name
+        = $self->meta->is_immutable
+        ? $self->meta->get_mutable_metaclass_name
+        : ref $self->meta;
+
+    my $meta = $meta_name->create(
+        $class_name,
+        superclasses => [ ref $self ],
+    );
+
+    Class::MOP::load_class($trait);
+    for my $meth ( Class::MOP::Class->initialize($trait)->get_all_methods ) {
+        next if $meta->has_method( $meth->name );
+
+        if ( $meta->find_method_by_name( $meth->name ) ) {
+            $meta->add_around_method_modifier( $meth->name, $meth->body );
         }
         else {
-            confess
-                "$class_name is already defined but does not inherit $trait";
+            $meta->add_method( $meth->name, $meth->clone );
         }
     }
-    else {
-        my @super = ( $trait, ref($self) );
 
-        my $meta = Class::MOP::Class->initialize($class_name);
-        $meta->superclasses(@super);
+    $meta->make_immutable( inline_constructor => 0 );
 
-        $meta->make_immutable;
-
-        return $class_name;
-    }
+    return $class_name;
 }
 
 sub _remove_inlined_code {
@@ -1408,7 +1431,11 @@ does nothing; it is merely a hook.
 
 This method is used to create a new object of the metaclass's
 class. Any parameters you provide are used to initialize the
-instance's attributes.
+instance's attributes. A special C<__INSTANCE__> key can be passed to
+provide an already generated instance, rather than having Class::MOP
+generate it for you. This is mostly useful for using Class::MOP with
+foreign classes, which generally generate instances using their own
+constructor.
 
 =item B<< $metaclass->instance_metaclass >>
 
@@ -1611,10 +1638,10 @@ attributes which are defined in terms of "regular" Perl 5 methods.
 
 This will return a L<Class::MOP::Attribute> for the specified
 C<$attribute_name>. If the class does not have the specified
-attribute, it returns C<undef>. 
+attribute, it returns C<undef>.
 
-NOTE that get_attribute does not search superclasses, for 
-that you need to use C<find_attribute_by_name>.
+NOTE that get_attribute does not search superclasses, for that you
+need to use C<find_attribute_by_name>.
 
 =item B<< $metaclass->has_attribute($attribute_name) >>
 
@@ -1725,7 +1752,7 @@ destructor.
 
 The name of a class which will be used as a parent class for the
 metaclass object being made immutable. This "trait" implements the
-post-immutability functionlity of the metaclass (but not the
+post-immutability functionality of the metaclass (but not the
 transformation itself).
 
 This defaults to L<Class::MOP::Class::Immutable::Trait>.