# 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();
+ my $instance;
+ if (my $instance_class = blessed($params->{__INSTANCE__})) {
+ ($instance_class eq $class->name)
+ || confess "Objects passed as the __INSTANCE__ parameter must "
+ . "already be blessed into the correct class, but "
+ . "$params->{__INSTANCE__} is not a " . $class->name;
+ $instance = $params->{__INSTANCE__};
+ }
+ elsif (exists $params->{__INSTANCE__}) {
+ confess "The __INSTANCE__ parameter must be a blessed reference, not "
+ . $params->{__INSTANCE__};
+ }
+ else {
+ $instance = $meta_instance->create_instance();
+ }
foreach my $attr ($class->get_all_attributes()) {
$attr->initialize_instance_slot($meta_instance, $instance, $params);
}
--- /dev/null
+#!/usr/bin/env perl
+use strict;
+use warnings;
+use Test::More;
+use Test::Exception;
+
+use Class::MOP;
+
+my $instance;
+{
+ package Foo;
+
+ sub new {
+ my $class = shift;
+ $instance = bless {@_}, $class;
+ return $instance;
+ }
+
+ sub foo { shift->{foo} }
+}
+
+{
+ package Foo::Sub;
+ use base 'Foo';
+ use metaclass;
+
+ sub new {
+ my $class = shift;
+ $class->meta->new_object(
+ __INSTANCE__ => $class->SUPER::new(@_),
+ @_,
+ );
+ }
+
+ __PACKAGE__->meta->add_attribute(
+ bar => (
+ reader => 'bar',
+ initializer => sub {
+ my $self = shift;
+ my ($value, $writer, $attr) = @_;
+ $writer->(uc $value);
+ },
+ ),
+ );
+}
+
+undef $instance;
+lives_and {
+ my $foo = Foo::Sub->new;
+ isa_ok($foo, 'Foo');
+ isa_ok($foo, 'Foo::Sub');
+ is($foo, $instance, "used the passed-in instance");
+};
+
+undef $instance;
+lives_and {
+ my $foo = Foo::Sub->new(foo => 'FOO');
+ isa_ok($foo, 'Foo');
+ isa_ok($foo, 'Foo::Sub');
+ is($foo, $instance, "used the passed-in instance");
+ is($foo->foo, 'FOO', "set non-CMOP constructor args");
+};
+
+undef $instance;
+lives_and {
+ my $foo = Foo::Sub->new(bar => 'bar');
+ isa_ok($foo, 'Foo');
+ isa_ok($foo, 'Foo::Sub');
+ is($foo, $instance, "used the passed-in instance");
+ is($foo->bar, 'BAR', "set CMOP attributes");
+};
+
+undef $instance;
+lives_and {
+ my $foo = Foo::Sub->new(foo => 'FOO', bar => 'bar');
+ isa_ok($foo, 'Foo');
+ isa_ok($foo, 'Foo::Sub');
+ is($foo, $instance, "used the passed-in instance");
+ is($foo->foo, 'FOO', "set non-CMOP constructor arg");
+ is($foo->bar, 'BAR', "set correct CMOP attribute");
+};
+
+{
+ package BadFoo;
+
+ sub new {
+ my $class = shift;
+ $instance = bless {@_};
+ return $instance;
+ }
+
+ sub foo { shift->{foo} }
+}
+
+{
+ package BadFoo::Sub;
+ use base 'BadFoo';
+ use metaclass;
+
+ sub new {
+ my $class = shift;
+ $class->meta->new_object(
+ __INSTANCE__ => $class->SUPER::new(@_),
+ @_,
+ );
+ }
+
+ __PACKAGE__->meta->add_attribute(
+ bar => (
+ reader => 'bar',
+ initializer => sub {
+ my $self = shift;
+ my ($value, $writer, $attr) = @_;
+ $writer->(uc $value);
+ },
+ ),
+ );
+}
+
+throws_ok { BadFoo::Sub->new }
+ qr/BadFoo=HASH.*is not a BadFoo::Sub/,
+ "error with incorrect constructors";
+
+{
+ my $meta = Class::MOP::Class->create('Really::Bad::Foo');
+ throws_ok {
+ $meta->new_object(__INSTANCE__ => (bless {}, 'Some::Other::Class'))
+ } qr/Some::Other::Class=HASH.*is not a Really::Bad::Foo/,
+ "error with completely invalid class";
+}
+
+{
+ my $meta = Class::MOP::Class->create('Really::Bad::Foo::2');
+ for my $invalid ('foo', 1, 0, '') {
+ throws_ok {
+ $meta->new_object(__INSTANCE__ => $invalid)
+ } qr/The __INSTANCE__ parameter must be a blessed reference, not $invalid/,
+ "error with unblessed thing";
+ }
+}
+
+done_testing;