9 my %checked_metaclass_attrs = (
10 'Instance' => 'instance_metaclass',
11 'Method::Wrapped' => 'wrapped_method_metaclass',
12 'Method::Constructor' => 'constructor_class',
14 my %unchecked_metaclass_attrs = (
15 'Attribute' => 'attribute_metaclass',
16 'Method' => 'method_metaclass',
18 my %metaclass_attrs = (
19 %checked_metaclass_attrs,
20 %unchecked_metaclass_attrs,
24 for my $suffix ('Class', keys %metaclass_attrs) {
25 Class::MOP::Class->create(
27 superclasses => ["Class::MOP::$suffix"]
29 Class::MOP::Class->create(
31 superclasses => ["Class::MOP::$suffix"]
33 Class::MOP::Class->create(
34 "FooBar::Meta::$suffix",
35 superclasses => ["Foo::Meta::$suffix", "Bar::Meta::$suffix"]
42 Foo::Meta::Class->create('Foo')
43 } '... Foo.meta => Foo::Meta::Class is compatible';
45 Bar::Meta::Class->create('Bar')
46 } '... Bar.meta => Bar::Meta::Class is compatible';
49 Bar::Meta::Class->create('Foo::Foo', superclasses => ['Foo'])
50 } qr/compatible/, '... Foo::Foo.meta => Bar::Meta::Class is not compatible';
52 Foo::Meta::Class->create('Bar::Bar', superclasses => ['Bar'])
53 } qr/compatible/, '... Bar::Bar.meta => Foo::Meta::Class is not compatible';
56 FooBar::Meta::Class->create('FooBar', superclasses => ['Foo'])
57 } '... FooBar.meta => FooBar::Meta::Class is compatible';
59 FooBar::Meta::Class->create('FooBar2', superclasses => ['Bar'])
60 } '... FooBar2.meta => FooBar::Meta::Class is compatible';
62 Foo::Meta::Class->create(
64 map { $metaclass_attrs{$_} => "Foo::Meta::$_" } keys %metaclass_attrs,
68 Bar::Meta::Class->create(
69 'Foo::All::Sub::Class',
70 superclasses => ['Foo::All'],
71 map { $metaclass_attrs{$_} => "Foo::Meta::$_" } keys %metaclass_attrs,
73 } qr/compatible/, 'incompatible Class metaclass';
74 for my $suffix (keys %checked_metaclass_attrs) {
76 Foo::Meta::Class->create(
77 "Foo::All::Sub::$suffix",
78 superclasses => ['Foo::All'],
79 (map { $metaclass_attrs{$_} => "Foo::Meta::$_" } keys %metaclass_attrs),
80 $metaclass_attrs{$suffix} => "Bar::Meta::$suffix",
82 } qr/compatible/, "incompatible $suffix metaclass";
84 for my $suffix (keys %unchecked_metaclass_attrs) {
86 Foo::Meta::Class->create(
87 "Foo::All::Sub::$suffix",
88 superclasses => ['Foo::All'],
89 (map { $metaclass_attrs{$_} => "Foo::Meta::$_" } keys %metaclass_attrs),
90 $metaclass_attrs{$suffix} => "Bar::Meta::$suffix",
92 } "compatible $suffix metaclass";
98 Class::MOP::Class->create('Foo::Foo::CMOP', superclasses => ['Foo'])
99 } 'metaclass fixing fixes a cmop metaclass, when the parent has a subclass';
100 isa_ok(Foo::Foo::CMOP->meta, 'Foo::Meta::Class');
102 Class::MOP::Class->create('Bar::Bar::CMOP', superclasses => ['Bar'])
103 } 'metaclass fixing fixes a cmop metaclass, when the parent has a subclass';
104 isa_ok(Bar::Bar::CMOP->meta, 'Bar::Meta::Class');
107 Class::MOP::Class->create(
108 'Foo::All::Sub::CMOP::Class',
109 superclasses => ['Foo::All'],
110 map { $metaclass_attrs{$_} => "Foo::Meta::$_" } keys %metaclass_attrs,
112 } 'metaclass fixing works with other non-default metaclasses';
113 isa_ok(Foo::All::Sub::CMOP::Class->meta, 'Foo::Meta::Class');
115 for my $suffix (keys %metaclass_attrs) {
117 Foo::Meta::Class->create(
118 "Foo::All::Sub::CMOP::$suffix",
119 superclasses => ['Foo::All'],
120 (map { $metaclass_attrs{$_} => "Foo::Meta::$_" } keys %metaclass_attrs),
121 $metaclass_attrs{$suffix} => "Class::MOP::$suffix",
123 } "$metaclass_attrs{$suffix} fixing works with other non-default metaclasses";
124 for my $suffix2 (keys %checked_metaclass_attrs) {
125 my $method = $metaclass_attrs{$suffix2};
126 isa_ok("Foo::All::Sub::CMOP::$suffix"->meta->$method, "Foo::Meta::$suffix2");
128 for my $suffix2 (keys %unchecked_metaclass_attrs) {
129 my $method = $metaclass_attrs{$suffix2};
130 isa_ok("Foo::All::Sub::CMOP::$suffix"->meta->$method, "Class::MOP::$suffix2");
140 Class::MOP::Class->create('Foo::NoMeta::Sub', superclasses => ['Foo::NoMeta']);
141 ok(!Foo::NoMeta->can('meta'), "non-cmop superclass doesn't get methods installed");
142 isa_ok(Class::MOP::class_of('Foo::NoMeta'), 'Class::MOP::Class');
143 isa_ok(Foo::NoMeta::Sub->meta, 'Class::MOP::Class');
146 package Foo::NoMeta2;
148 Foo::Meta::Class->create('Foo::NoMeta2::Sub', superclasses => ['Foo::NoMeta2']);
149 ok(!Foo::NoMeta->can('meta'), "non-cmop superclass doesn't get methods installed");
150 isa_ok(Class::MOP::class_of('Foo::NoMeta2'), 'Class::MOP::Class');
151 isa_ok(Foo::NoMeta2::Sub->meta, 'Foo::Meta::Class');
153 Foo::Meta::Class->create('Foo::WithMeta');
155 package Foo::WithMeta::Sub;
156 use base 'Foo::WithMeta';
158 Class::MOP::Class->create(
159 'Foo::WithMeta::Sub::Sub',
160 superclasses => ['Foo::WithMeta::Sub']
163 isa_ok(Class::MOP::class_of('Foo::WithMeta'), 'Foo::Meta::Class');
164 isa_ok(Class::MOP::class_of('Foo::WithMeta::Sub'), 'Foo::Meta::Class');
165 isa_ok(Class::MOP::class_of('Foo::WithMeta::Sub::Sub'), 'Foo::Meta::Class');
167 Foo::Meta::Class->create('Foo::WithMeta2');
169 package Foo::WithMeta2::Sub;
170 use base 'Foo::WithMeta2';
173 package Foo::WithMeta2::Sub::Sub;
174 use base 'Foo::WithMeta2::Sub';
176 Class::MOP::Class->create(
177 'Foo::WithMeta2::Sub::Sub::Sub',
178 superclasses => ['Foo::WithMeta2::Sub::Sub']
181 isa_ok(Class::MOP::class_of('Foo::WithMeta2'), 'Foo::Meta::Class');
182 isa_ok(Class::MOP::class_of('Foo::WithMeta2::Sub'), 'Foo::Meta::Class');
183 isa_ok(Class::MOP::class_of('Foo::WithMeta2::Sub::Sub'), 'Foo::Meta::Class');
184 isa_ok(Class::MOP::class_of('Foo::WithMeta2::Sub::Sub::Sub'), 'Foo::Meta::Class');
186 Class::MOP::Class->create(
187 'Foo::Reverse::Sub::Sub',
188 superclasses => ['Foo::Reverse::Sub'],
190 eval "package Foo::Reverse::Sub; use base 'Foo::Reverse';";
191 Foo::Meta::Class->create(
194 isa_ok(Class::MOP::class_of('Foo::Reverse'), 'Foo::Meta::Class');
195 { local $TODO = 'No idea how to handle case where parent class is created before children';
196 isa_ok(Class::MOP::class_of('Foo::Reverse::Sub'), 'Foo::Meta::Class');
197 isa_ok(Class::MOP::class_of('Foo::Reverse::Sub::Sub'), 'Foo::Meta::Class');
203 Class::MOP::Class->create(
205 instance_metaclass => 'Foo::Meta::Instance',
207 my $meta = Class::MOP::Class->create(
210 $meta->add_attribute(foo => reader => 'foo');
211 throws_ok { $meta->superclasses('Foo::Unsafe') }
212 qr/compatibility.*pristine/,
213 "can't switch out the metaclass of a class that already has attributes";
219 my $foometa = Foo::Meta::Class->create(
222 $foometa->make_immutable;
223 my $barmeta = Class::MOP::Class->create(
226 my $bazmeta = Class::MOP::Class->create(
229 $bazmeta->superclasses($foometa->name);
230 lives_ok { $bazmeta->superclasses($barmeta->name) }
231 "can still set superclasses";
232 ok(!$bazmeta->is_immutable,
233 "immutable superclass doesn't make this class immutable");
234 lives_ok { $bazmeta->make_immutable } "can still make immutable";
237 # nonexistent metaclasses
239 Class::MOP::Class->create('Weird::Meta::Method::Destructor');
242 Class::MOP::Class->create(
244 destructor_class => 'Weird::Meta::Method::Destructor',
246 } "defined metaclass in child with defined metaclass in parent is fine";
248 is(Weird::Class->meta->destructor_class, 'Weird::Meta::Method::Destructor',
249 "got the right destructor class");
252 Class::MOP::Class->create(
254 superclasses => ['Weird::Class'],
255 destructor_class => undef,
257 } "undef metaclass in child with defined metaclass in parent can be fixed";
259 is(Weird::Class::Sub->meta->destructor_class, 'Weird::Meta::Method::Destructor',
260 "got the right destructor class");
263 Class::MOP::Class->create(
264 'Weird::Class::Sub2',
265 destructor_class => undef,
267 } "undef metaclass in child with defined metaclass in parent can be fixed";
270 Weird::Class::Sub2->meta->superclasses('Weird::Class');
271 } "undef metaclass in child with defined metaclass in parent can be fixed";
273 is(Weird::Class::Sub->meta->destructor_class, 'Weird::Meta::Method::Destructor',
274 "got the right destructor class");