File Coverage

blib/lib/Moose/Util/MetaRole.pm
Criterion Covered Total %
statement 60 60 100.0
branch 14 18 77.7
condition 13 17 76.4
subroutine 13 13 100.0
pod 2 2 100.0
total 102 110 92.7


line stmt bran cond sub pod time code
1             package Moose::Util::MetaRole;
2             our $VERSION = '2.2206';
3              
4 391     391   142011 use strict;
  391         944  
  391         13849  
5 391     391   4502 use warnings;
  391         934  
  391         13308  
6 391     391   2274 use Scalar::Util 'blessed';
  391         5632  
  391         23245  
7              
8 391     391   2425 use List::Util 1.33 qw( first all );
  391         6368  
  391         23661  
9 391     391   23115 use Moose::Deprecated;
  391         2365  
  391         4827  
10 391     391   183845 use Moose::Util 'throw_exception';
  391         1134  
  391         3577  
11              
12             sub apply_metaroles {
13 120     120 1 11629 my %args = @_;
14              
15 120         482 my $for = _metathing_for( $args{for} );
16              
17 115 100       644 if ( $for->isa('Moose::Meta::Role') ) {
18 20         80 return _make_new_metaclass( $for, $args{role_metaroles}, 'role' );
19             }
20             else {
21 95         392 return _make_new_metaclass( $for, $args{class_metaroles}, 'class' );
22             }
23             }
24              
25             sub _metathing_for {
26 126     126   304 my $passed = shift;
27              
28 126 100       731 my $found
29             = blessed $passed
30             ? $passed
31             : Class::MOP::class_of($passed);
32              
33 126 100 66     2161 return $found
      100        
      100        
34             if defined $found
35             && blessed $found
36             && ( $found->isa('Moose::Meta::Role')
37             || $found->isa('Moose::Meta::Class') );
38              
39 6         21 local $Carp::CarpLevel = $Carp::CarpLevel + 1;
40              
41 6         29 throw_exception( InvalidArgPassedToMooseUtilMetaRole => argument => $passed );
42             }
43              
44             sub _make_new_metaclass {
45 115     115   257 my $for = shift;
46 115         247 my $roles = shift;
47 115         216 my $primary = shift;
48              
49 115 50       192 return $for unless keys %{$roles};
  115         487  
50              
51             my $new_metaclass
52             = exists $roles->{$primary}
53 115 100       1339 ? _make_new_class( ref $for, $roles->{$primary} )
54             : blessed $for;
55              
56 115         699 my %classes;
57              
58 115         251 for my $key ( grep { $_ ne $primary } keys %{$roles} ) {
  140         526  
  115         425  
59 67     67   221 my $attr = first {$_}
60 67         455 map { $for->meta->find_attribute_by_name($_) } (
  134         480  
61             $key . '_metaclass',
62             $key . '_class'
63             );
64              
65 67         382 my $reader = $attr->get_read_method;
66              
67             $classes{ $attr->init_arg }
68 67         1476 = _make_new_class( $for->$reader(), $roles->{$key} );
69             }
70              
71 115         862 my $new_meta = $new_metaclass->reinitialize( $for, %classes );
72              
73 114         902 return $new_meta;
74             }
75              
76             sub apply_base_class_roles {
77 6     6 1 910 my %args = @_;
78              
79 6   33     32 my $meta = _metathing_for( $args{for} || $args{for_class} );
80 5 100       46 throw_exception( CannotApplyBaseClassRolesToRole => params => \%args,
81             role_name => $meta->name,
82             )
83             if $meta->isa('Moose::Meta::Role');
84              
85             my $new_base = _make_new_class(
86             $meta->name,
87             $args{roles},
88 3         18 [ $meta->superclasses() ],
89             );
90              
91 3 50       28 $meta->superclasses($new_base)
92             if $new_base ne $meta->name();
93             }
94              
95             sub _make_new_class {
96 143     143   313 my $existing_class = shift;
97 143         245 my $roles = shift;
98 143   100     684 my $superclasses = shift || [$existing_class];
99              
100 143 50       447 return $existing_class unless $roles;
101              
102 143         577 my $meta = Class::MOP::Class->initialize($existing_class);
103              
104             return $existing_class
105 18     18   64 if $meta->can('does_role') && all { $meta->does_role($_) }
106 143 50 66     1317 grep { !ref $_ } @{$roles};
  18         97  
  18         55  
107              
108 143         819 return Moose::Meta::Class->create_anon_class(
109             superclasses => $superclasses,
110             roles => $roles,
111             cache => 1,
112             )->name();
113             }
114              
115             1;
116              
117             # ABSTRACT: Apply roles to any metaclass, as well as the object base class
118              
119             __END__
120              
121             =pod
122              
123             =encoding UTF-8
124              
125             =head1 NAME
126              
127             Moose::Util::MetaRole - Apply roles to any metaclass, as well as the object base class
128              
129             =head1 VERSION
130              
131             version 2.2206
132              
133             =head1 SYNOPSIS
134              
135             package MyApp::Moose;
136              
137             use Moose ();
138             use Moose::Exporter;
139             use Moose::Util::MetaRole;
140              
141             use MyApp::Role::Meta::Class;
142             use MyApp::Role::Meta::Method::Constructor;
143             use MyApp::Role::Object;
144              
145             Moose::Exporter->setup_import_methods( also => 'Moose' );
146              
147             sub init_meta {
148             shift;
149             my %args = @_;
150              
151             Moose->init_meta(%args);
152              
153             Moose::Util::MetaRole::apply_metaroles(
154             for => $args{for_class},
155             class_metaroles => {
156             class => ['MyApp::Role::Meta::Class'],
157             constructor => ['MyApp::Role::Meta::Method::Constructor'],
158             },
159             );
160              
161             Moose::Util::MetaRole::apply_base_class_roles(
162             for => $args{for_class},
163             roles => ['MyApp::Role::Object'],
164             );
165              
166             return $args{for_class}->meta();
167             }
168              
169             =head1 DESCRIPTION
170              
171             This utility module is designed to help authors of Moose extensions
172             write extensions that are able to cooperate with other Moose
173             extensions. To do this, you must write your extensions as roles, which
174             can then be dynamically applied to the caller's metaclasses.
175              
176             This module makes sure to preserve any existing superclasses and roles
177             already set for the meta objects, which means that any number of
178             extensions can apply roles in any order.
179              
180             =head1 USAGE
181              
182             The easiest way to use this module is through L<Moose::Exporter>, which can
183             generate the appropriate C<init_meta> method for you, and make sure it is
184             called when imported.
185              
186             =head1 FUNCTIONS
187              
188             This module provides two functions.
189              
190             =head2 apply_metaroles( ... )
191              
192             This function will apply roles to one or more metaclasses for the specified
193             class. It will return a new metaclass object for the class or role passed in
194             the "for" parameter.
195              
196             It accepts the following parameters:
197              
198             =over 4
199              
200             =item * for => $name
201              
202             This specifies the class for which to alter the meta classes. This can be a
203             package name, or an appropriate meta-object (a L<Moose::Meta::Class> or
204             L<Moose::Meta::Role>).
205              
206             =item * class_metaroles => \%roles
207              
208             This is a hash reference specifying which metaroles will be applied to the
209             class metaclass and its contained metaclasses and helper classes.
210              
211             Each key should in turn point to an array reference of role names.
212              
213             It accepts the following keys:
214              
215             =over 8
216              
217             =item class
218              
219             =item attribute
220              
221             =item method
222              
223             =item wrapped_method
224              
225             =item instance
226              
227             =item constructor
228              
229             =item destructor
230              
231             =item error
232              
233             =back
234              
235             =item * role_metaroles => \%roles
236              
237             This is a hash reference specifying which metaroles will be applied to the
238             role metaclass and its contained metaclasses and helper classes.
239              
240             It accepts the following keys:
241              
242             =over 8
243              
244             =item role
245              
246             =item attribute
247              
248             =item method
249              
250             =item required_method
251              
252             =item conflicting_method
253              
254             =item application_to_class
255              
256             =item application_to_role
257              
258             =item application_to_instance
259              
260             =item application_role_summation
261              
262             =item applied_attribute
263              
264             =back
265              
266             =back
267              
268             =head2 apply_base_class_roles( for => $class, roles => \@roles )
269              
270             This function will apply the specified roles to the object's base class.
271              
272             =head1 BUGS
273              
274             See L<Moose/BUGS> for details on reporting bugs.
275              
276             =head1 AUTHORS
277              
278             =over 4
279              
280             =item *
281              
282             Stevan Little <stevan@cpan.org>
283              
284             =item *
285              
286             Dave Rolsky <autarch@urth.org>
287              
288             =item *
289              
290             Jesse Luehrs <doy@cpan.org>
291              
292             =item *
293              
294             Shawn M Moore <sartak@cpan.org>
295              
296             =item *
297              
298             יובל קוג'מן (Yuval Kogman) <nothingmuch@woobling.org>
299              
300             =item *
301              
302             Karen Etheridge <ether@cpan.org>
303              
304             =item *
305              
306             Florian Ragwitz <rafl@debian.org>
307              
308             =item *
309              
310             Hans Dieter Pearcey <hdp@cpan.org>
311              
312             =item *
313              
314             Chris Prather <chris@prather.org>
315              
316             =item *
317              
318             Matt S Trout <mstrout@cpan.org>
319              
320             =back
321              
322             =head1 COPYRIGHT AND LICENSE
323              
324             This software is copyright (c) 2006 by Infinity Interactive, Inc.
325              
326             This is free software; you can redistribute it and/or modify it under
327             the same terms as the Perl 5 programming language system itself.
328              
329             =cut