1MooseX::Role::ParameterUiszeerd:C:oTnuttroirbiuatle(d3M)PoeorsleXD:o:cRuomleen:t:aPtairoanmeterized::Tutorial(3)
2
3
4
6 MooseX::Role::Parameterized::Tutorial - why and how
7
9 version 1.11
10
12 Roles are composable units of behavior. They are useful for factoring
13 out functionality common to many classes from any part of your class
14 hierarchy. See Moose::Cookbook::Roles::Comparable_CodeReuse for an
15 introduction to Moose::Role.
16
17 While combining roles affords you a great deal of flexibility,
18 individual roles have very little in the way of configurability. Core
19 Moose provides "-alias" for renaming methods and "-excludes" for
20 ignoring methods. These options are primarily for resolving role
21 conflicts. Depending on how much of a purist you are, these options are
22 solely for resolving role conflicts. See
23 Moose::Cookbook::Roles::Restartable_AdvancedComposition for more about
24 "-alias" and "-excludes".
25
26 Because roles serve many different masters, they usually provide only
27 the least common denominator of functionality. To empower roles
28 further, more configurability than "-alias" and "-excludes" is
29 required. Perhaps your role needs to know which method to call when it
30 is done processing. Or what default value to use for its "url"
31 attribute.
32
33 Parameterized roles offer a solution to these (and other) kinds of
34 problems.
35
37 "with"
38 The syntax of a class consuming a parameterized role has not changed
39 from the standard "with". You pass in parameters just like you pass in
40 "-alias" and "-excludes" to ordinary roles (though your custom
41 parameters do not get hyphens, since these are not core Moose
42 composition parameters):
43
44 with 'MyRole::InstrumentMethod' => {
45 method_name => 'dbh_do',
46 log_to => 'query.log',
47 };
48
49 You can still combine parameterized roles. You just need to specify
50 parameters immediately after the role they belong to:
51
52 with (
53 'My::Parameterized::Role' => {
54 needs_better_example => 1,
55 },
56 'My::Other::Role',
57 );
58
59 We, like Moose itself, use Data::OptList to make sure that a list of
60 role names and associated parameters is handled correctly.
61
62 "parameter"
63 Inside your parameterized role, you specify a set of parameters. This
64 is exactly like specifying the attributes of a class. Instead of "has"
65 in Moose you use the keyword "parameter", but your parameters can use
66 any options to "has".
67
68 parameter 'delegation' => (
69 isa => 'HashRef|ArrayRef|RegexpRef',
70 predicate => 'has_delegation',
71 );
72
73 You do have to declare what parameters you accept, just like you have
74 to declare what attributes you accept for regular Moose objects.
75
76 One departure from "has" is that we create a reader accessor for you by
77 default. In other words, we assume "is => 'ro'". We create this reader
78 for convenience because generally the parameterized role is the only
79 consumer of the parameters object, so data hiding is not as important
80 than in the general case of "has" in Moose. If you do not want an
81 accessor, you can use "is => 'bare'".
82
83 "role"
84 "role" takes a block of code that will be used to generate your role
85 with its parameters bound. Here is where you declare components that
86 depend on parameters. You can declare attributes, methods, modifiers,
87 etc. The first argument to the "role" is an object containing the
88 parameters specified by "with". You can access the parameters just like
89 regular attributes on that object.
90
91 Each time you compose this parameterized role, the "role {}" block will
92 be executed. It will receive a new parameter object and produce an
93 entirely new role. That's the whole point, after all.
94
95 Due to limitations inherent in Perl, you must declare methods with
96 "method name => sub { ... }" instead of the usual "sub name { ... }".
97 Your methods may, of course, close over the parameter object. This
98 means that your methods may use parameters however they wish!
99
101 Ideally these will become fully-explained examples in something
102 resembling Moose::Cookbook. But for now, only a brain dump.
103
104 Configure a role's attributes
105 You can rename methods with core Moose, but now you can rename
106 attributes. You can now also choose type, default value, whether
107 it's required, traits, etc.
108
109 parameter traits => (
110 isa => 'ArrayRef',
111 default => sub { [] },
112 );
113
114 parameter type => (
115 isa => 'Str',
116 default => 'Any',
117 );
118
119 role {
120 my $p = shift;
121
122 has action => (
123 traits => $p->traits,
124 isa => $p->type,
125 ...
126 );
127 };
128
129 Inform a role of your class' attributes and methods
130 Core roles can only require methods with specific names chosen by
131 the role. Now your roles can demand that the class specifies a
132 method name you wish the role to instrument, or which attributes to
133 dump to a file.
134
135 parameter instrument_method => (
136 isa => 'Str',
137 required => 1,
138 );
139
140 role {
141 my $p = shift;
142 around $p->instrument_method => sub { ... };
143 };
144
145 Arbitrary execution choices
146 Your role may be able to provide configuration in how the role's
147 methods operate. For example, you can tell the role whether to save
148 intermediate states.
149
150 parameter save_intermediate => (
151 isa => 'Bool',
152 default => 0,
153 );
154
155 role {
156 my $p = shift;
157 method process => sub {
158 ...
159 if ($p->save_intermediate) { ... }
160 ...
161 };
162 };
163
164 Deciding a backend
165 Your role may be able to freeze and thaw your instances using YAML,
166 JSON, Storable. Which backend to use can be a parameter.
167
168 parameter format => (
169 isa => (enum ['Storable', 'YAML', 'JSON']),
170 default => 'Storable',
171 );
172
173 role {
174 my $p = shift;
175 if ($p->format eq 'Storable') {
176 method freeze => \&Storable::freeze;
177 method thaw => \&Storable::thaw;
178 }
179 elsif ($p->format eq 'YAML') {
180 method freeze => \&YAML::Dump;
181 method thaw => \&YAML::Load;
182 }
183 ...
184 };
185
186 Additional validation
187 Ordinary roles can require that its consumers have a particular
188 list of method names. Since parameterized roles have direct access
189 to its consumer, you can inspect it and throw errors if the
190 consumer does not meet your needs.
191
192 role {
193 my $p = shift;
194 my %args = @_;
195 my $consumer = $args{consumer};
196
197 $consumer->find_attribute_by_name('stack')
198 or confess "You must have a 'stack' attribute";
199
200 my $push = $consumer->find_method_by_name('push')
201 or confess "You must have a 'push' method";
202
203 my $params = $push->parsed_signature->positional_params->params;
204 @$params == 1
205 or confess "Your push method must take a single parameter";
206
207 $params->[0]->sigil eq '$'
208 or confess "Your push parameter must be a scalar";
209
210 ...
211 };
212
214 Bugs may be submitted through the RT bug tracker
215 <https://rt.cpan.org/Public/Dist/Display.html?Name=MooseX-Role-
216 Parameterized> (or bug-MooseX-Role-Parameterized@rt.cpan.org
217 <mailto:bug-MooseX-Role-Parameterized@rt.cpan.org>).
218
219 There is also a mailing list available for users of this distribution,
220 at <http://lists.perl.org/list/moose.html>.
221
222 There is also an irc channel available for users of this distribution,
223 at "#moose" on "irc.perl.org" <irc://irc.perl.org/#moose>.
224
226 Shawn M Moore <code@sartak.org>
227
229 This software is copyright (c) 2008 by Shawn M Moore.
230
231 This is free software; you can redistribute it and/or modify it under
232 the same terms as the Perl 5 programming language system itself.
233
234
235
236perl v5.32.0 2020-M0o7o-s2e8X::Role::Parameterized::Tutorial(3)