1 package Moose::Util::MetaRole;
5 use Scalar::Util 'blessed';
8 use List::MoreUtils qw( all );
9 use List::Util qw( first );
10 use Moose::Deprecated;
11 use Scalar::Util qw( blessed );
16 my $for = _metathing_for( $args{for} );
18 if ( $for->isa('Moose::Meta::Role') ) {
19 return _make_new_metaclass( $for, $args{role_metaroles}, 'role' );
22 return _make_new_metaclass( $for, $args{class_metaroles}, 'class' );
32 : Class::MOP::class_of($passed);
37 && ( $found->isa('Moose::Meta::Role')
38 || $found->isa('Moose::Meta::Class') );
40 local $Carp::CarpLevel = $Carp::CarpLevel + 1;
43 = 'When using Moose::Util::MetaRole, you must pass a Moose class name,'
44 . ' role name, metaclass object, or metarole object.';
46 if ( defined $found && blessed $found ) {
48 . " You passed $passed, and we resolved this to a "
53 if ( defined $passed && !defined $found ) {
55 . " You passed $passed, and this did not resolve to a metaclass or metarole."
56 . ' Maybe you need to call Moose->init_meta to initialize the metaclass first?';
59 if ( !defined $passed ) {
61 . " You passed an undef."
62 . ' Maybe you need to call Moose->init_meta to initialize the metaclass first?';
66 sub _make_new_metaclass {
71 return $for unless keys %{$roles};
74 = exists $roles->{$primary}
75 ? _make_new_class( ref $for, $roles->{$primary} )
80 for my $key ( grep { $_ ne $primary } keys %{$roles} ) {
82 map { $for->meta->find_attribute_by_name($_) } (
87 my $reader = $attr->get_read_method;
89 $classes{ $attr->init_arg }
90 = _make_new_class( $for->$reader(), $roles->{$key} );
93 my $new_meta = $new_metaclass->reinitialize( $for, %classes );
98 sub apply_base_class_roles {
101 my $meta = _metathing_for( $args{for} || $args{for_class} );
102 croak 'You can only apply base class roles to a Moose class, not a role.'
103 if $meta->isa('Moose::Meta::Role');
105 my $new_base = _make_new_class(
108 [ $meta->superclasses() ],
111 $meta->superclasses($new_base)
112 if $new_base ne $meta->name();
115 sub _make_new_class {
116 my $existing_class = shift;
118 my $superclasses = shift || [$existing_class];
120 return $existing_class unless $roles;
122 my $meta = Class::MOP::Class->initialize($existing_class);
124 return $existing_class
125 if $meta->can('does_role') && all { $meta->does_role($_) }
126 grep { !ref $_ } @{$roles};
128 return Moose::Meta::Class->create_anon_class(
129 superclasses => $superclasses,
137 # ABSTRACT: Apply roles to any metaclass, as well as the object base class
143 package MyApp::Moose;
147 use Moose::Util::MetaRole;
149 use MyApp::Role::Meta::Class;
150 use MyApp::Role::Meta::Method::Constructor;
151 use MyApp::Role::Object;
153 Moose::Exporter->setup_import_methods( also => 'Moose' );
159 Moose->init_meta(%args);
161 Moose::Util::MetaRole::apply_metaroles(
162 for => $args{for_class},
164 class => => ['MyApp::Role::Meta::Class'],
165 constructor => ['MyApp::Role::Meta::Method::Constructor'],
169 Moose::Util::MetaRole::apply_base_class_roles(
170 for => $args{for_class},
171 roles => ['MyApp::Role::Object'],
174 return $args{for_class}->meta();
179 This utility module is designed to help authors of Moose extensions
180 write extensions that are able to cooperate with other Moose
181 extensions. To do this, you must write your extensions as roles, which
182 can then be dynamically applied to the caller's metaclasses.
184 This module makes sure to preserve any existing superclasses and roles
185 already set for the meta objects, which means that any number of
186 extensions can apply roles in any order.
190 The easiest way to use this module is through L<Moose::Exporter>, which can
191 generate the appropriate C<init_meta> method for you, and make sure it is
192 called when imported.
196 This module provides two functions.
198 =head2 apply_metaroles( ... )
200 This function will apply roles to one or more metaclasses for the specified
201 class. It will return a new metaclass object for the class or role passed in
204 It accepts the following parameters:
210 This specifies the class or for which to alter the meta classes. This can be a
211 package name, or an appropriate meta-object (a L<Moose::Meta::Class> or
212 L<Moose::Meta::Role>).
214 =item * class_metaroles => \%roles
216 This is a hash reference specifying which metaroles will be applied to the
217 class metaclass and its contained metaclasses and helper classes.
219 Each key should in turn point to an array reference of role names.
221 It accepts the following keys:
243 =item * role_metaroles => \%roles
245 This is a hash reference specifying which metaroles will be applied to the
246 role metaclass and its contained metaclasses and helper classes.
248 It accepts the following keys:
258 =item required_method
260 =item conflicting_method
262 =item application_to_class
264 =item application_to_role
266 =item application_to_instance
268 =item application_role_summation
270 =item applied_attribute
276 =head2 apply_base_class_roles( for => $class, roles => \@roles )
278 This function will apply the specified roles to the object's base class.
282 See L<Moose/BUGS> for details on reporting bugs.