6 use lib 't/lib', 'lib';
11 use Moose::Util::MetaRole;
15 package My::Meta::Class;
17 extends 'Moose::Meta::Class';
23 has 'foo' => ( is => 'ro', default => 10 );
38 Moose::Util::MetaRole::apply_metaroles(
39 for => My::Class->meta,
40 class_metaroles => { class => ['Role::Foo'] },
43 ok( My::Class->meta()->meta()->does_role('Role::Foo'),
44 'apply Role::Foo to My::Class->meta()' );
45 is( My::Class->meta()->foo(), 10,
46 '... and call foo() on that meta object' );
50 Moose::Util::MetaRole::apply_metaroles(
52 class_metaroles => { attribute => ['Role::Foo'] },
55 ok( My::Class->meta()->attribute_metaclass()->meta()->does_role('Role::Foo'),
56 q{apply Role::Foo to My::Class->meta()'s attribute metaclass} );
57 ok( My::Class->meta()->meta()->does_role('Role::Foo'),
58 '... My::Class->meta() still does Role::Foo' );
60 My::Class->meta()->add_attribute( 'size', is => 'ro' );
61 is( My::Class->meta()->get_attribute('size')->foo(), 10,
62 '... call foo() on an attribute metaclass object' );
66 Moose::Util::MetaRole::apply_metaroles(
68 class_metaroles => { method => ['Role::Foo'] },
71 ok( My::Class->meta()->method_metaclass()->meta()->does_role('Role::Foo'),
72 q{apply Role::Foo to My::Class->meta()'s method metaclass} );
73 ok( My::Class->meta()->meta()->does_role('Role::Foo'),
74 '... My::Class->meta() still does Role::Foo' );
75 ok( My::Class->meta()->attribute_metaclass()->meta()->does_role('Role::Foo'),
76 q{... My::Class->meta()'s attribute metaclass still does Role::Foo} );
78 My::Class->meta()->add_method( 'bar' => sub { 'bar' } );
79 is( My::Class->meta()->get_method('bar')->foo(), 10,
80 '... call foo() on a method metaclass object' );
84 Moose::Util::MetaRole::apply_metaroles(
86 class_metaroles => { wrapped_method => ['Role::Foo'] },
89 ok( My::Class->meta()->wrapped_method_metaclass()->meta()->does_role('Role::Foo'),
90 q{apply Role::Foo to My::Class->meta()'s wrapped method metaclass} );
91 ok( My::Class->meta()->method_metaclass()->meta()->does_role('Role::Foo'),
92 '... My::Class->meta() still does Role::Foo' );
93 ok( My::Class->meta()->meta()->does_role('Role::Foo'),
94 '... My::Class->meta() still does Role::Foo' );
95 ok( My::Class->meta()->attribute_metaclass()->meta()->does_role('Role::Foo'),
96 q{... My::Class->meta()'s attribute metaclass still does Role::Foo} );
98 My::Class->meta()->add_after_method_modifier( 'bar' => sub { 'bar' } );
99 is( My::Class->meta()->get_method('bar')->foo(), 10,
100 '... call foo() on a wrapped method metaclass object' );
104 Moose::Util::MetaRole::apply_metaroles(
106 class_metaroles => { instance => ['Role::Foo'] },
109 ok( My::Class->meta()->instance_metaclass()->meta()->does_role('Role::Foo'),
110 q{apply Role::Foo to My::Class->meta()'s instance metaclass} );
111 ok( My::Class->meta()->meta()->does_role('Role::Foo'),
112 '... My::Class->meta() still does Role::Foo' );
113 ok( My::Class->meta()->attribute_metaclass()->meta()->does_role('Role::Foo'),
114 q{... My::Class->meta()'s attribute metaclass still does Role::Foo} );
115 ok( My::Class->meta()->method_metaclass()->meta()->does_role('Role::Foo'),
116 q{... My::Class->meta()'s method metaclass still does Role::Foo} );
118 is( My::Class->meta()->get_meta_instance()->foo(), 10,
119 '... call foo() on an instance metaclass object' );
123 Moose::Util::MetaRole::apply_metaroles(
125 class_metaroles => { constructor => ['Role::Foo'] },
128 ok( My::Class->meta()->constructor_class()->meta()->does_role('Role::Foo'),
129 q{apply Role::Foo to My::Class->meta()'s constructor class} );
130 ok( My::Class->meta()->meta()->does_role('Role::Foo'),
131 '... My::Class->meta() still does Role::Foo' );
132 ok( My::Class->meta()->attribute_metaclass()->meta()->does_role('Role::Foo'),
133 q{... My::Class->meta()'s attribute metaclass still does Role::Foo} );
134 ok( My::Class->meta()->method_metaclass()->meta()->does_role('Role::Foo'),
135 q{... My::Class->meta()'s method metaclass still does Role::Foo} );
136 ok( My::Class->meta()->instance_metaclass()->meta()->does_role('Role::Foo'),
137 q{... My::Class->meta()'s instance metaclass still does Role::Foo} );
139 # Actually instantiating the constructor class is too freaking hard!
140 ok( My::Class->meta()->constructor_class()->can('foo'),
141 '... constructor class has a foo method' );
145 Moose::Util::MetaRole::apply_metaroles(
147 class_metaroles => { destructor => ['Role::Foo'] },
150 ok( My::Class->meta()->destructor_class()->meta()->does_role('Role::Foo'),
151 q{apply Role::Foo to My::Class->meta()'s destructor class} );
152 ok( My::Class->meta()->meta()->does_role('Role::Foo'),
153 '... My::Class->meta() still does Role::Foo' );
154 ok( My::Class->meta()->attribute_metaclass()->meta()->does_role('Role::Foo'),
155 q{... My::Class->meta()'s attribute metaclass still does Role::Foo} );
156 ok( My::Class->meta()->method_metaclass()->meta()->does_role('Role::Foo'),
157 q{... My::Class->meta()'s method metaclass still does Role::Foo} );
158 ok( My::Class->meta()->instance_metaclass()->meta()->does_role('Role::Foo'),
159 q{... My::Class->meta()'s instance metaclass still does Role::Foo} );
160 ok( My::Class->meta()->constructor_class()->meta()->does_role('Role::Foo'),
161 q{... My::Class->meta()'s constructor class still does Role::Foo} );
163 # same problem as the constructor class
164 ok( My::Class->meta()->destructor_class()->can('foo'),
165 '... destructor class has a foo method' );
169 Moose::Util::MetaRole::apply_metaroles(
171 role_metaroles => { application_to_class => ['Role::Foo'] },
174 ok( My::Role->meta->application_to_class_class->meta->does_role('Role::Foo'),
175 q{apply Role::Foo to My::Role->meta's application_to_class class} );
177 is( My::Role->meta->application_to_class_class->new->foo, 10,
178 q{... call foo() on an application_to_class instance} );
182 Moose::Util::MetaRole::apply_metaroles(
184 role_metaroles => { application_to_role => ['Role::Foo'] },
187 ok( My::Role->meta->application_to_role_class->meta->does_role('Role::Foo'),
188 q{apply Role::Foo to My::Role->meta's application_to_role class} );
189 ok( My::Role->meta->application_to_class_class->meta->does_role('Role::Foo'),
190 q{... My::Role->meta's application_to_class class still does Role::Foo} );
192 is( My::Role->meta->application_to_role_class->new->foo, 10,
193 q{... call foo() on an application_to_role instance} );
197 Moose::Util::MetaRole::apply_metaroles(
199 role_metaroles => { application_to_instance => ['Role::Foo'] },
202 ok( My::Role->meta->application_to_instance_class->meta->does_role('Role::Foo'),
203 q{apply Role::Foo to My::Role->meta's application_to_instance class} );
204 ok( My::Role->meta->application_to_role_class->meta->does_role('Role::Foo'),
205 q{... My::Role->meta's application_to_role class still does Role::Foo} );
206 ok( My::Role->meta->application_to_class_class->meta->does_role('Role::Foo'),
207 q{... My::Role->meta's application_to_class class still does Role::Foo} );
209 is( My::Role->meta->application_to_instance_class->new->foo, 10,
210 q{... call foo() on an application_to_instance instance} );
214 Moose::Util::MetaRole::apply_base_class_roles(
216 roles => ['Role::Foo'],
219 ok( My::Class->meta()->does_role('Role::Foo'),
220 'apply Role::Foo to My::Class base class' );
221 is( My::Class->new()->foo(), 10,
222 '... call foo() on a My::Class object' );
232 Moose::Util::MetaRole::apply_metaroles(
235 class => ['Role::Foo'],
236 attribute => ['Role::Foo'],
237 method => ['Role::Foo'],
238 instance => ['Role::Foo'],
239 constructor => ['Role::Foo'],
240 destructor => ['Role::Foo'],
244 ok( My::Class2->meta()->meta()->does_role('Role::Foo'),
245 'apply Role::Foo to My::Class2->meta()' );
246 is( My::Class2->meta()->foo(), 10,
247 '... and call foo() on that meta object' );
248 ok( My::Class2->meta()->attribute_metaclass()->meta()->does_role('Role::Foo'),
249 q{apply Role::Foo to My::Class2->meta()'s attribute metaclass} );
250 My::Class2->meta()->add_attribute( 'size', is => 'ro' );
252 is( My::Class2->meta()->get_attribute('size')->foo(), 10,
253 '... call foo() on an attribute metaclass object' );
255 ok( My::Class2->meta()->method_metaclass()->meta()->does_role('Role::Foo'),
256 q{apply Role::Foo to My::Class2->meta()'s method metaclass} );
258 My::Class2->meta()->add_method( 'bar' => sub { 'bar' } );
259 is( My::Class2->meta()->get_method('bar')->foo(), 10,
260 '... call foo() on a method metaclass object' );
262 ok( My::Class2->meta()->instance_metaclass()->meta()->does_role('Role::Foo'),
263 q{apply Role::Foo to My::Class2->meta()'s instance metaclass} );
264 is( My::Class2->meta()->get_meta_instance()->foo(), 10,
265 '... call foo() on an instance metaclass object' );
267 ok( My::Class2->meta()->constructor_class()->meta()->does_role('Role::Foo'),
268 q{apply Role::Foo to My::Class2->meta()'s constructor class} );
269 ok( My::Class2->meta()->constructor_class()->can('foo'),
270 '... constructor class has a foo method' );
272 ok( My::Class2->meta()->destructor_class()->meta()->does_role('Role::Foo'),
273 q{apply Role::Foo to My::Class2->meta()'s destructor class} );
274 ok( My::Class2->meta()->destructor_class()->can('foo'),
275 '... destructor class has a foo method' );
283 Moose::Exporter->setup_import_methods( also => 'Moose' );
289 Moose->init_meta( %p, metaclass => 'My::Meta::Class' );
301 Moose::Util::MetaRole::apply_metaroles(
303 class_metaroles => { class => ['Role::Foo'] },
306 ok( My::Class3->meta()->meta()->does_role('Role::Foo'),
307 'apply Role::Foo to My::Class3->meta()' );
308 is( My::Class3->meta()->foo(), 10,
309 '... and call foo() on that meta object' );
310 ok( ( grep { $_ eq 'My::Meta::Class' } My::Class3->meta()->meta()->superclasses() ),
311 'apply_metaroles() does not interfere with metaclass set via Moose->init_meta()' );
317 has 'bar' => ( is => 'ro', default => 200 );
326 Moose::Util::MetaRole::apply_metaroles(
328 class_metaroles => { class => ['Role::Foo'] },
331 ok( My::Class4->meta()->meta()->does_role('Role::Foo'),
332 'apply Role::Foo to My::Class4->meta()' );
334 Moose::Util::MetaRole::apply_metaroles(
336 class_metaroles => { class => ['Role::Bar'] },
339 ok( My::Class4->meta()->meta()->does_role('Role::Bar'),
340 'apply Role::Bar to My::Class4->meta()' );
341 ok( My::Class4->meta()->meta()->does_role('Role::Foo'),
342 '... and My::Class4->meta() still does Role::Foo' );
353 ok( My::Class5->meta()->meta()->does_role('Role::Foo'),
354 q{My::Class5->meta()'s does Role::Foo because it extends My::Class} );
355 ok( My::Class5->meta()->attribute_metaclass()->meta()->does_role('Role::Foo'),
356 q{My::Class5->meta()'s attribute metaclass also does Role::Foo} );
357 ok( My::Class5->meta()->method_metaclass()->meta()->does_role('Role::Foo'),
358 q{My::Class5->meta()'s method metaclass also does Role::Foo} );
359 ok( My::Class5->meta()->instance_metaclass()->meta()->does_role('Role::Foo'),
360 q{My::Class5->meta()'s instance metaclass also does Role::Foo} );
361 ok( My::Class5->meta()->constructor_class()->meta()->does_role('Role::Foo'),
362 q{My::Class5->meta()'s constructor class also does Role::Foo} );
363 ok( My::Class5->meta()->destructor_class()->meta()->does_role('Role::Foo'),
364 q{My::Class5->meta()'s destructor class also does Role::Foo} );
368 Moose::Util::MetaRole::apply_metaroles(
370 class_metaroles => { class => ['Role::Bar'] },
373 ok( My::Class5->meta()->meta()->does_role('Role::Bar'),
374 q{apply Role::Bar My::Class5->meta()} );
375 ok( My::Class5->meta()->meta()->does_role('Role::Foo'),
376 q{... and My::Class5->meta() still does Role::Foo} );
383 Moose::Util::MetaRole::apply_metaroles(
385 class_metaroles => { class => ['Role::Bar'] },
392 ok( My::Class6->meta()->meta()->does_role('Role::Bar'),
393 q{apply Role::Bar My::Class6->meta() before extends} );
394 ok( My::Class6->meta()->meta()->does_role('Role::Foo'),
395 q{... and My::Class6->meta() does Role::Foo because My::Class6 extends My::Class} );
398 # This is the hack that used to be needed to work around the
399 # _fix_metaclass_incompatibility problem. You called extends() (which
400 # in turn calls _fix_metaclass_imcompatibility) _before_ you apply
401 # more extensions in the subclass. We wabt to make sure this continues
402 # to work in the future.
407 # In real usage this would go in a BEGIN block so it happened
408 # before apply_metaroles was called by an extension.
411 Moose::Util::MetaRole::apply_metaroles(
413 class_metaroles => { class => ['Role::Bar'] },
418 ok( My::Class7->meta()->meta()->does_role('Role::Bar'),
419 q{apply Role::Bar My::Class7->meta() before extends} );
420 ok( My::Class7->meta()->meta()->does_role('Role::Foo'),
421 q{... and My::Class7->meta() does Role::Foo because My::Class7 extends My::Class} );
428 Moose::Util::MetaRole::apply_metaroles(
431 class => ['Role::Bar'],
432 attribute => ['Role::Bar'],
440 ok( My::Class8->meta()->meta()->does_role('Role::Bar'),
441 q{apply Role::Bar My::Class8->meta() before extends} );
442 ok( My::Class8->meta()->meta()->does_role('Role::Foo'),
443 q{... and My::Class8->meta() does Role::Foo because My::Class8 extends My::Class} );
444 ok( My::Class8->meta()->attribute_metaclass->meta()->does_role('Role::Bar'),
445 q{apply Role::Bar to My::Class8->meta()->attribute_metaclass before extends} );
446 ok( My::Class8->meta()->attribute_metaclass->meta()->does_role('Role::Foo'),
447 q{... and My::Class8->meta()->attribute_metaclass does Role::Foo because My::Class8 extends My::Class} );
455 Moose::Util::MetaRole::apply_metaroles(
457 class_metaroles => { attribute => ['Role::Bar'] },
464 ok( My::Class9->meta()->meta()->does_role('Role::Foo'),
465 q{... and My::Class9->meta() does Role::Foo because My::Class9 extends My::Class} );
466 ok( My::Class9->meta()->attribute_metaclass->meta()->does_role('Role::Bar'),
467 q{apply Role::Bar to My::Class9->meta()->attribute_metaclass before extends} );
468 ok( My::Class9->meta()->attribute_metaclass->meta()->does_role('Role::Foo'),
469 q{... and My::Class9->meta()->attribute_metaclass does Role::Foo because My::Class9 extends My::Class} );
472 # This tests applying meta roles to a metaclass's metaclass. This is
473 # completely insane, but is exactly what happens with
474 # Fey::Meta::Class::Table. It's a subclass of Moose::Meta::Class
475 # itself, and then it _uses_ MooseX::ClassAttribute, so the metaclass
476 # for Fey::Meta::Class::Table does a role.
478 # At one point this caused a metaclass incompatibility error down
479 # below, when we applied roles to the metaclass of My::Class10. It's
480 # all madness but as long as the tests pass we're happy.
482 package My::Meta::Class2;
484 extends 'Moose::Meta::Class';
486 Moose::Util::MetaRole::apply_metaroles(
487 for => 'My::Meta::Class2',
488 class_metaroles => { class => ['Role::Foo'] },
495 extends 'Moose::Object';
502 Moose::Exporter->setup_import_methods( also => 'Moose' );
510 metaclass => 'My::Meta::Class2',
511 base_class => 'My::Object',
520 Moose::Util::MetaRole::apply_metaroles(
521 for => 'My::Class10',
522 class_metaroles => { class => ['Role::Bar'] },
527 ok( My::Class10->meta()->meta()->meta()->does_role('Role::Foo'),
528 q{My::Class10->meta()->meta() does Role::Foo } );
529 ok( My::Class10->meta()->meta()->does_role('Role::Bar'),
530 q{My::Class10->meta()->meta() does Role::Bar } );
531 ok( My::Class10->meta()->isa('My::Meta::Class2'),
532 q{... and My::Class10->meta still isa(My::Meta::Class2)} );
533 ok( My::Class10->isa('My::Object'),
534 q{... and My::Class10 still isa(My::Object)} );
538 package My::Constructor;
540 use base 'Moose::Meta::Method::Constructor';
548 __PACKAGE__->meta->constructor_class('My::Constructor');
550 Moose::Util::MetaRole::apply_metaroles(
551 for => 'My::Class11',
552 class_metaroles => { class => ['Role::Foo'] },
557 ok( My::Class11->meta()->meta()->does_role('Role::Foo'),
558 q{My::Class11->meta()->meta() does Role::Foo } );
559 is( My::Class11->meta()->constructor_class, 'My::Constructor',
560 q{... and explicitly set constructor_class value is unchanged)} );
564 package ExportsMoose;
566 Moose::Exporter->setup_import_methods(
573 Moose->init_meta(%p);
574 return Moose::Util::MetaRole::apply_metaroles(
575 for => $p{for_class},
576 # Causes us to recurse through init_meta, as we have to
577 # load MyMetaclassRole from disk.
578 class_metaroles => { class => [qw/MyMetaclassRole/] },
584 package UsesExportedMoose;
585 ExportsMoose->import;
586 }, undef, 'import module which loads a role from disk during init_meta' );
589 package Foo::Meta::Role;
597 Moose::Exporter->setup_import_methods(
598 also => 'Moose::Role',
605 Moose::Role->init_meta(%p);
607 return Moose::Util::MetaRole::apply_metaroles(
608 for => $p{for_class},
609 role_metaroles => { method => ['Foo::Meta::Role'] },
632 My::Class12->meta->does_role( 'Role::Baz' ),
636 my $method = My::Class12->meta->get_method( 'bla' );
638 $method->meta->does_role( 'Foo::Meta::Role' ),
639 'method_metaclass_role applied'
647 Moose::Util::MetaRole::apply_metaroles(
649 class_metaroles => { constructor => ['Role::Foo'] },
662 Parent->meta->constructor_class->meta->can('does_role')
663 && Parent->meta->constructor_class->meta->does_role('Role::Foo'),
664 'Parent constructor class has metarole from Parent'
668 Child->meta->constructor_class->meta->can('does_role')
669 && Child->meta->constructor_class->meta->does_role(
671 'Child constructor class has metarole from Parent'
684 Moose::Util::MetaRole::apply_metaroles(
685 for => 'Does::Not::Exist',
686 class_metaroles => { class => ['Role::Foo'] },
689 qr/When using Moose::Util::MetaRole.+You passed Does::Not::Exist.+Maybe you need to call.+/,
690 'useful error when apply metaroles to a class without a metaclass'
695 Moose::Util::MetaRole::apply_metaroles(
697 class_metaroles => { class => ['Role::Foo'] },
700 qr/When using Moose::Util::MetaRole.+You passed NotMoosey.+we resolved this to a Class::MOP::Class object.+/,
701 'useful error when using apply metaroles to a class with a Class::MOP::Class metaclass'
706 Moose::Util::MetaRole::apply_base_class_roles(
708 roles => { class => ['Role::Foo'] },
711 qr/When using Moose::Util::MetaRole.+You passed NotMoosey.+we resolved this to a Class::MOP::Class object.+/,
712 'useful error when applying base class to roles to a non-Moose class'
717 Moose::Util::MetaRole::apply_base_class_roles(
719 roles => { class => ['Role::Foo'] },
722 qr/You can only apply base class roles to a Moose class.+/,
723 'useful error when applying base class to roles to a non-Moose class'