File Coverage

blib/lib/MooseX/Role/Parameterized/Meta/Trait/Parameterizable.pm
Criterion Covered Total %
statement 37 37 100.0
branch 5 6 83.3
condition 2 3 66.6
subroutine 8 8 100.0
pod 1 1 100.0
total 53 55 96.3


line stmt bran cond sub pod time code
1             package MooseX::Role::Parameterized::Meta::Trait::Parameterizable;
2             # ABSTRACT: trait for parameterizable roles
3              
4             our $VERSION = '1.10';
5              
6 27     27   7450 use Moose::Role;
  27         61008  
  27         93  
7 27     27   108197 use MooseX::Role::Parameterized::Meta::Role::Parameterized;
  27         70  
  27         1038  
8 27     27   158 use MooseX::Role::Parameterized::Parameters;
  27         28  
  27         574  
9 27     27   92 use Module::Runtime 'use_module';
  27         32  
  27         138  
10 27     27   950 use namespace::autoclean;
  27         32  
  27         112  
11              
12             has parameterized_role_metaclass => (
13             is => 'ro',
14             isa => 'ClassName',
15             default => 'MooseX::Role::Parameterized::Meta::Role::Parameterized',
16             );
17              
18             has parameters_class => (
19             is => 'ro',
20             isa => 'ClassName',
21             default => 'MooseX::Role::Parameterized::Parameters',
22             );
23              
24             has parameters_metaclass => (
25             is => 'rw',
26             isa => 'Moose::Meta::Class',
27             lazy => 1,
28             builder => '_build_parameters_metaclass',
29             handles => {
30             has_parameter => 'has_attribute',
31             add_parameter => 'add_attribute',
32             construct_parameters => 'new_object',
33             },
34             predicate => '_has_parameters_metaclass',
35             );
36              
37             has role_generator => (
38             is => 'rw',
39             isa => 'CodeRef',
40             predicate => 'has_role_generator',
41             );
42              
43             sub _build_parameters_metaclass {
44 35     35   65 my $self = shift;
45              
46 35         1269 return $self->parameters_class->meta->create_anon_class(
47             superclasses => [$self->parameters_class],
48             );
49             }
50              
51             my $package_counter = 0;
52             sub generate_role {
53 66     66 1 184525 my $self = shift;
54 66         173 my %args = @_;
55              
56             my $parameters = blessed($args{parameters})
57             ? $args{parameters}
58 66 50       240 : $self->construct_parameters(%{ $args{parameters} });
  66         399  
59              
60 64 100       26703 confess "A role generator is required to apply parameterized roles (did you forget the 'role { ... }' block in your parameterized role '".$self->name."'?)"
61             unless $self->has_role_generator;
62              
63 63         2152 my $parameterized_role_metaclass = $self->parameterized_role_metaclass;
64 63         197 use_module($parameterized_role_metaclass);
65              
66 63         1334 my $package = $args{package};
67 63 100       155 unless ($package) {
68 62         71 $package_counter++;
69 62         304 $package = $self->name . '::__ANON__::SERIAL::' . $package_counter;
70             }
71 63         495 my $role = $parameterized_role_metaclass->create(
72             $package,
73             genitor => $self,
74             parameters => $parameters,
75             );
76              
77 63         105889 local $MooseX::Role::Parameterized::CURRENT_METACLASS = $role;
78              
79             # The generate_role method is being called directly by things like
80             # MooseX::ClassCompositor. We don't want to force such modules to pass
81             # this arg so we default to something sane.
82 63   66     392 my $orig_apply = $args{orig_apply} || Moose::Meta::Role->can('apply');
83 63         171 $self->$orig_apply($role);
84              
85             $self->role_generator->($parameters,
86             operating_on => $role,
87             consumer => $args{consumer},
88 63         55157 );
89              
90             # don't just return $role here, because it might have been changed when
91             # metaroles are applied
92 63         6101 return $MooseX::Role::Parameterized::CURRENT_METACLASS;
93             }
94              
95             sub _role_for_combination {
96 6     6   751 my $self = shift;
97 6         8 my $parameters = shift;
98              
99 6         21 return $self->generate_role(
100             parameters => $parameters,
101             );
102             }
103              
104             around apply => sub {
105             my $orig = shift;
106             my $self = shift;
107             my $consumer = shift;
108             my %args = @_;
109              
110             my $role = $self->generate_role(
111             consumer => $consumer,
112             parameters => \%args,
113             orig_apply => $orig,
114             );
115              
116             $role->apply($consumer, %args);
117             };
118              
119             around reinitialize => sub {
120             my $orig = shift;
121             my $class = shift;
122             my ($pkg) = @_;
123             my $meta = blessed($pkg) ? $pkg : find_meta($pkg);
124              
125             my $meta_meta = $meta->meta;
126              
127             my %p;
128             if ( $meta_meta->can('does_role') && $meta_meta->does_role(__PACKAGE__) ) {
129             %p = map { $_ => $meta->$_ }
130             qw( parameterized_role_metaclass parameters_class );
131             $p{parameters_metaclass} = $meta->parameters_metaclass
132             if $meta->_has_parameters_metaclass;
133             $p{role_generator} = $meta->role_generator
134             if $meta->has_role_generator;
135             }
136              
137             my $new = $class->$orig(
138             @_,
139             %p,
140             );
141              
142             return $new;
143             };
144              
145             1;
146              
147             __END__
148              
149             =pod
150              
151             =encoding UTF-8
152              
153             =head1 NAME
154              
155             MooseX::Role::Parameterized::Meta::Trait::Parameterizable - trait for parameterizable roles
156              
157             =head1 VERSION
158              
159             version 1.10
160              
161             =head1 DESCRIPTION
162              
163             This is the trait that is applied to the metaclass for parameterizable roles,
164             roles that have their parameters currently unbound. These are the roles that
165             you use L<Moose/with>, but instead of composing the parameterizable role, we
166             construct a new parameterized role
167             (L<MooseX::Role::Parameterized::Meta::Role::Parameterized>) and use that new
168             parameterized role instead.
169              
170             =head1 ATTRIBUTES
171              
172             =head2 parameterized_role_metaclass
173              
174             The name of the class that will be used to construct the parameterized role.
175              
176             =head2 parameters_class
177              
178             The name of the class that will be used to construct the parameters object.
179              
180             =head2 parameters_metaclass
181              
182             A metaclass representing this role's parameters. It will be an anonymous
183             subclass of L</parameters_class>. Each call to
184             L<MooseX::Role::Parameters/parameter> adds an attribute to this metaclass.
185              
186             When this role is consumed, the parameters object will be instantiated using
187             this metaclass.
188              
189             =head2 role_generator
190              
191             A code reference that is used to generate a role based on the parameters
192             provided by the consumer. The user usually specifies it using the
193             L<MooseX::Role::Parameterized/role> keyword.
194              
195             =head1 METHODS
196              
197             =head2 add_parameter $name, %options
198              
199             Delegates to L<Moose::Meta::Class/add_attribute> on the
200             L</parameters_metaclass> object.
201              
202             =head2 construct_parameters %arguments
203              
204             Creates a new L<MooseX::Role::Parameterized::Parameters> object using metaclass
205             L</parameters_metaclass>.
206              
207             The arguments are those specified by the consumer as parameter values.
208              
209             =head2 generate_role %arguments
210              
211             This method generates and returns a new instance of
212             L</parameterized_role_metaclass>. It can take any combination of
213             three named arguments:
214              
215             =over 4
216              
217             =item parameters
218              
219             A hashref of parameters for the role, same as would be passed in at a "with"
220             statement.
221              
222             =item package
223              
224             A package name that, if present, we will use for the generated role; if not,
225             we generate an anonymous role.
226              
227             =item consumer
228              
229             =for stopwords metaobject
230              
231             A consumer metaobject, if available.
232              
233             =back
234              
235             =head2 apply
236              
237             Overrides L<Moose::Meta::Role/apply> to automatically generate the
238             parameterized role.
239              
240             =head1 SUPPORT
241              
242             Bugs may be submitted through L<the RT bug tracker|https://rt.cpan.org/Public/Dist/Display.html?Name=MooseX-Role-Parameterized>
243             (or L<bug-MooseX-Role-Parameterized@rt.cpan.org|mailto:bug-MooseX-Role-Parameterized@rt.cpan.org>).
244              
245             There is also a mailing list available for users of this distribution, at
246             L<http://lists.perl.org/list/moose.html>.
247              
248             There is also an irc channel available for users of this distribution, at
249             L<C<#moose> on C<irc.perl.org>|irc://irc.perl.org/#moose>.
250              
251             =head1 AUTHOR
252              
253             Shawn M Moore <code@sartak.org>
254              
255             =head1 COPYRIGHT AND LICENSE
256              
257             This software is copyright (c) 2008 by Shawn M Moore.
258              
259             This is free software; you can redistribute it and/or modify it under
260             the same terms as the Perl 5 programming language system itself.
261              
262             =cut