Need to use a lower level method in getting attribute value, because of things like...
[gitmo/Class-MOP.git] / lib / Class / MOP / Class.pm
index a6f9210..f22b07e 100644 (file)
@@ -393,6 +393,40 @@ sub clone_instance {
     return $clone;
 }
 
+sub rebless_instance {
+    my ($self, $instance, $new_metaclass) = @_;
+
+    # it's okay (expected, even) to pass in a package name
+    unless (blessed $new_metaclass) {
+        $new_metaclass = $self->initialize($new_metaclass);
+    }
+    my $meta_instance = $self->get_meta_instance();
+
+    # make sure we're reblessing into a subclass
+    my $is_subclass = 0;
+    for my $superclass ($new_metaclass->linearized_isa) {
+        if ($superclass eq $self->name) {
+            $is_subclass = 1;
+            last;
+        }
+    }
+
+    $is_subclass
+        || confess "You may rebless only into a subclass. (". $new_metaclass->name .") is not a subclass of (". $self->name .").";
+
+    # rebless!
+    $meta_instance->rebless_instance_structure($instance, $new_metaclass);
+
+    # check and upgrade all attributes
+    my %params = map { $_->name => $meta_instance->get_slot_value($instance, $_->name) }
+                 grep { $meta_instance->is_slot_initialized($instance, $_->name) }
+                 $new_metaclass->compute_all_applicable_attributes;
+
+    foreach my $attr ($new_metaclass->compute_all_applicable_attributes) {
+        $attr->initialize_instance_slot($meta_instance, $instance, \%params);
+    }
+}
+
 # Inheritance
 
 sub superclasses {