. $self->_get_associated_single_metaclass(blessed($object));
}
- # XXX: is this sufficient? i think so... we should never lose attributes
- # by this process
- bless($object, $new_metaclass)
+ # can't use rebless_instance here, because it might not be an actual
+ # subclass in the case of, e.g. moose role reconciliation
+ $new_metaclass->meta->_force_rebless_instance($object)
if blessed($object) ne $new_metaclass;
return $object;
return $clone;
}
-sub rebless_instance {
+sub _force_rebless_instance {
my ($self, $instance, %params) = @_;
-
my $old_metaclass = Class::MOP::class_of($instance);
- my $old_class = $old_metaclass ? $old_metaclass->name : blessed($instance);
- $self->name->isa($old_class)
- || confess "You may rebless only into a subclass of ($old_class), of which (". $self->name .") isn't.";
-
$old_metaclass->rebless_instance_away($instance, $self, %params)
if $old_metaclass;
- my $meta_instance = $self->get_meta_instance();
+ my $meta_instance = $self->get_meta_instance;
# rebless!
# we use $_[1] here because of t/306_rebless_overload.t regressions on 5.8.8
$meta_instance->rebless_instance_structure($_[1], $self);
- foreach my $attr ( $self->get_all_attributes ) {
- if ( $attr->has_value($instance) ) {
- if ( defined( my $init_arg = $attr->init_arg ) ) {
- $params{$init_arg} = $attr->get_value($instance)
- unless exists $params{$init_arg};
- }
- else {
- $attr->set_value($instance, $attr->get_value($instance));
- }
- }
- }
+ $self->_fixup_attributes_after_rebless($instance, $old_metaclass, %params);
+}
- foreach my $attr ($self->get_all_attributes) {
- $attr->initialize_instance_slot($meta_instance, $instance, \%params);
- }
-
- $instance;
+sub rebless_instance {
+ my ($self, $instance, %params) = @_;
+ my $old_metaclass = Class::MOP::class_of($instance);
+
+ my $old_class = $old_metaclass ? $old_metaclass->name : blessed($instance);
+ $self->name->isa($old_class)
+ || confess "You may rebless only into a subclass of ($old_class), of which (". $self->name .") isn't.";
+
+ $self->_force_rebless_instance($_[1], %params);
+
+ return $instance;
}
sub rebless_instance_back {
my ( $self, $instance ) = @_;
-
my $old_metaclass = Class::MOP::class_of($instance);
my $old_class
. $self->name
. ") isn't.";
- $old_metaclass->rebless_instance_away( $instance, $self )
- if $old_metaclass;
+ $self->_force_rebless_instance($_[1]);
- my $meta_instance = $self->get_meta_instance;
+ return $instance;
+}
- # we use $_[1] here because of t/306_rebless_overload.t regressions on 5.8.8
- $meta_instance->rebless_instance_structure( $_[1], $self );
+sub rebless_instance_away {
+ # this intentionally does nothing, it is just a hook
+}
+
+sub _fixup_attributes_after_rebless {
+ my $self = shift;
+ my ($instance, $rebless_from, %params) = @_;
+ my $meta_instance = $self->get_meta_instance;
- for my $attr ( $old_metaclass->get_all_attributes ) {
- next if $self->has_attribute( $attr->name );
+ for my $attr ( $rebless_from->get_all_attributes ) {
+ next if $self->find_attribute_by_name( $attr->name );
$meta_instance->deinitialize_slot( $instance, $_ ) for $attr->slots;
}
- return $instance;
-}
+ foreach my $attr ( $self->get_all_attributes ) {
+ if ( $attr->has_value($instance) ) {
+ if ( defined( my $init_arg = $attr->init_arg ) ) {
+ $params{$init_arg} = $attr->get_value($instance)
+ unless exists $params{$init_arg};
+ }
+ else {
+ $attr->set_value($instance, $attr->get_value($instance));
+ }
+ }
+ }
-sub rebless_instance_away {
- # this intentionally does nothing, it is just a hook
+ foreach my $attr ($self->get_all_attributes) {
+ $attr->initialize_instance_slot($meta_instance, $instance, \%params);
+ }
}
sub _attach_attribute {
check_meta_sanity($meta, 'Quuux');
ok(!$meta->has_method('bar'));
+{
+ package Blah::Meta::Method;
+ use base 'Class::MOP::Method';
+
+ __PACKAGE__->meta->add_attribute('foo', reader => 'foo', default => 'TEST');
+}
+
+{
+ package Blah::Meta::Attribute;
+ use base 'Class::MOP::Attribute';
+
+ __PACKAGE__->meta->add_attribute('oof', reader => 'oof', default => 'TSET');
+}
+
+{
+ package Blah;
+ use metaclass;
+ sub foo {}
+ __PACKAGE__->meta->add_attribute('bar');
+}
+
+$meta = Blah->meta;
+check_meta_sanity($meta, 'Blah');
+Class::MOP::Class->reinitialize(
+ 'Blah',
+ attribute_metaclass => 'Blah::Meta::Attribute',
+ method_metaclass => 'Blah::Meta::Method',
+);
+check_meta_sanity($meta, 'Blah');
+can_ok(Blah->meta->get_method('foo'), 'foo');
+is(Blah->meta->get_method('foo')->foo, 'TEST');
+can_ok(Blah->meta->get_attribute('bar'), 'oof');
+is(Blah->meta->get_attribute('bar')->oof, 'TSET');
+
done_testing;