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.2205';
3              
4 391     391   143622 use strict;
  391         937  
  391         14118  
5 391     391   5813 use warnings;
  391         935  
  391         12995  
6 391     391   3570 use Scalar::Util 'blessed';
  391         3506  
  391         23053  
7              
8 391     391   2460 use List::Util 1.33 qw( first all );
  391         7788  
  391         22267  
9 391     391   23686 use Moose::Deprecated;
  391         3713  
  391         4583  
10 391     391   186386 use Moose::Util 'throw_exception';
  391         1189  
  391         3614  
11              
12             sub apply_metaroles {
13 120     120 1 13388 my %args = @_;
14              
15 120         488 my $for = _metathing_for( $args{for} );
16              
17 115 100       637 if ( $for->isa('Moose::Meta::Role') ) {
18 20         75 return _make_new_metaclass( $for, $args{role_metaroles}, 'role' );
19             }
20             else {
21 95         378 return _make_new_metaclass( $for, $args{class_metaroles}, 'class' );
22             }
23             }
24              
25             sub _metathing_for {
26 126     126   285 my $passed = shift;
27              
28 126 100       743 my $found
29             = blessed $passed
30             ? $passed
31             : Class::MOP::class_of($passed);
32              
33 126 100 66     2187 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         28 local $Carp::CarpLevel = $Carp::CarpLevel + 1;
40              
41 6         36 throw_exception( InvalidArgPassedToMooseUtilMetaRole => argument => $passed );
42             }
43              
44             sub _make_new_metaclass {
45 115     115   228 my $for = shift;
46 115         224 my $roles = shift;
47 115         234 my $primary = shift;
48              
49 115 50       209 return $for unless keys %{$roles};
  115         455  
50              
51             my $new_metaclass
52             = exists $roles->{$primary}
53 115 100       654 ? _make_new_class( ref $for, $roles->{$primary} )
54             : blessed $for;
55              
56 115         634 my %classes;
57              
58 115         242 for my $key ( grep { $_ ne $primary } keys %{$roles} ) {
  140         528  
  115         384  
59 67     67   228 my $attr = first {$_}
60 67         553 map { $for->meta->find_attribute_by_name($_) } (
  134         473  
61             $key . '_metaclass',
62             $key . '_class'
63             );
64              
65 67         373 my $reader = $attr->get_read_method;
66              
67             $classes{ $attr->init_arg }
68 67         1544 = _make_new_class( $for->$reader(), $roles->{$key} );
69             }
70              
71 115         862 my $new_meta = $new_metaclass->reinitialize( $for, %classes );
72              
73 114         913 return $new_meta;
74             }
75              
76             sub apply_base_class_roles {
77 6     6 1 972 my %args = @_;
78              
79 6   33     35 my $meta = _metathing_for( $args{for} || $args{for_class} );
80 5 100       42 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         19 [ $meta->superclasses() ],
89             );
90              
91 3 50       25 $meta->superclasses($new_base)
92             if $new_base ne $meta->name();
93             }
94              
95             sub _make_new_class {
96 143     143   286 my $existing_class = shift;
97 143         264 my $roles = shift;
98 143   100     1015 my $superclasses = shift || [$existing_class];
99              
100 143 50       428 return $existing_class unless $roles;
101              
102 143         548 my $meta = Class::MOP::Class->initialize($existing_class);
103              
104             return $existing_class
105 18     18   70 if $meta->can('does_role') && all { $meta->does_role($_) }
106 143 50 66     1256 grep { !ref $_ } @{$roles};
  18         98  
  18         56  
107              
108 143         816 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.2205
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