Commit | Line | Data |
f2ef3547 |
1 | =pod |
93c2fd30 |
2 | |
30788701 |
3 | =head1 NAME |
4 | |
5 | MooseX::Role::Parameterized::Tutorial - why and how |
6 | |
a4ac31fa |
7 | =head1 MOTIVATION |
d2abd756 |
8 | |
a4ac31fa |
9 | Roles are composable units of behavior. They are useful for factoring out |
f2ef3547 |
10 | functionality common to many classes from any part of your class hierarchy. See |
a4ac31fa |
11 | L<Moose::Cookbook::Roles::Recipe1> for an introduction to L<Moose::Role>. |
d2abd756 |
12 | |
a4ac31fa |
13 | While combining roles affords you a great deal of flexibility, individual roles |
f2ef3547 |
14 | have very little in the way of configurability. Core Moose provides C<alias> |
15 | for renaming methods and C<excludes> for ignoring methods. These options are |
16 | primarily (perhaps solely) for disambiguating role conflicts. See |
17 | L<Moose::Cookbook::Roles::Recipe2> for more about C<alias> and C<excludes>. |
93c2fd30 |
18 | |
a4ac31fa |
19 | Because roles serve many different masters, they usually provide only the least |
1d669b8a |
20 | common denominator of functionality. To empower roles further, more |
21 | configurability than C<alias> and C<excludes> is required. Perhaps your role |
22 | needs to know which method to call when it is done. Or what default value to |
f2ef3547 |
23 | use for its C<url> attribute. |
d2abd756 |
24 | |
a4ac31fa |
25 | Parameterized roles offer exactly this solution. |
d2abd756 |
26 | |
93c2fd30 |
27 | =head1 USAGE |
28 | |
29 | =head3 C<with> |
30 | |
a4ac31fa |
31 | The syntax of a class consuming a parameterized role has not changed from the |
32 | standard C<with>. You pass in parameters just like you pass in C<alias> and |
33 | C<excludes> to ordinary roles: |
34 | |
35 | with 'MyRole::InstrumentMethod' => { |
36 | method_name => 'dbh_do', |
37 | log_to => 'query.log', |
38 | }; |
39 | |
f2ef3547 |
40 | You can still combine parameterized roles. You just need to specify parameters |
41 | immediately after the role they belong to: |
42 | |
43 | with ( |
44 | 'My::Parameterized::Role' => { |
45 | needs_better_example => 1, |
46 | }, |
47 | 'My::Other::Role', |
48 | ); |
49 | |
93c2fd30 |
50 | =head3 C<parameter> |
51 | |
a4ac31fa |
52 | Inside your parameterized role, you specify a set of parameters. This is |
53 | exactly like specifying the attributes of a class. Instead of C<has> you use |
54 | the keyword C<parameter>, but your parameters can use any options to C<has>. |
55 | |
56 | parameter 'delegation' => ( |
a4ac31fa |
57 | isa => 'HashRef|ArrayRef|RegexpRef', |
58 | predicate => 'has_delegation', |
59 | ); |
60 | |
f2ef3547 |
61 | You do have to declare what parameters you accept, just like you have to |
62 | declare what attributes you accept for regular Moose objects. |
a4ac31fa |
63 | |
93c2fd30 |
64 | =head3 C<role> |
65 | |
a4ac31fa |
66 | C<role> takes a block of code that will be used to generate your role with its |
c190fb29 |
67 | parameters bound. Here is where you declare parameterized components: use |
f2ef3547 |
68 | C<has>, method modifiers, and so on. The C<role> block receives an argument, |
69 | which contains the parameters specified by C<with>. You can access the |
70 | parameters just like regular attributes on that object. |
a4ac31fa |
71 | |
72 | Each time you compose this parameterized role, the role {} block will be |
73 | executed. It will receive a new parameter object and produce an entirely new |
f2ef3547 |
74 | role. That's the whole point, after all. |
a4ac31fa |
75 | |
76 | Due to limitations inherent in Perl, you must declare methods with |
0ebe965e |
77 | C<< method name => sub { ... } >> instead of the usual C<sub name { ... }>. |
78 | Your methods may, of course, close over the parameter object. This means that |
79 | your methods may use parameters however they wish! |
a4ac31fa |
80 | |
d2abd756 |
81 | =head1 USES |
82 | |
83 | Ideally these will become fully-explained examples in something resembling |
84 | L<Moose::Cookbook>. But for now, only a braindump. |
85 | |
86 | =over 4 |
87 | |
88 | =item Configure a role's attributes |
89 | |
90 | You can rename methods with core Moose, but now you can rename attributes. You |
91 | can now also choose type, default value, whether it's required, B<traits>, etc. |
92 | |
93 | parameter traits => ( |
d2abd756 |
94 | isa => 'ArrayRef[Str]', |
95 | default => sub { [] }, |
96 | ); |
97 | |
f2ef3547 |
98 | parameter type => ( |
99 | isa => 'Str', |
100 | default => 'Any', |
d2abd756 |
101 | ); |
102 | |
f2ef3547 |
103 | role { |
104 | my $p = shift; |
105 | |
106 | has action => ( |
107 | traits => $p->traits, |
108 | isa => $p->type, |
109 | ... |
110 | ); |
111 | } |
112 | |
d2abd756 |
113 | =item Inform a role of your class' attributes and methods |
114 | |
115 | Core roles can require only methods with specific names. Now your roles can |
116 | require that you specify a method name you wish the role to instrument, or |
117 | which attributes to dump to a file. |
118 | |
119 | parameter instrument_method => ( |
d2abd756 |
120 | isa => 'Str', |
121 | required => 1, |
122 | ); |
123 | |
f2ef3547 |
124 | role { |
125 | my $p = shift; |
126 | around $p->instrument_method => sub { ... }; |
127 | } |
d2abd756 |
128 | |
129 | =item Arbitrary execution choices |
130 | |
131 | Your role may be able to provide configuration in how the role's methods |
132 | operate. For example, you can tell the role whether to save intermediate |
133 | states. |
134 | |
135 | parameter save_intermediate => ( |
d2abd756 |
136 | isa => 'Bool', |
137 | default => 0, |
138 | ); |
139 | |
f2ef3547 |
140 | role { |
141 | my $p = shift; |
142 | method process => sub { |
143 | ... |
144 | if ($p->save_intermediate) { ... } |
145 | ... |
146 | }; |
147 | } |
d2abd756 |
148 | |
149 | =item Deciding a backend |
150 | |
151 | Your role may be able to freeze and thaw your instances using L<YAML>, L<JSON>, |
152 | L<Storable>. Which backend to use can be a parameter. |
153 | |
154 | parameter format => ( |
fa2e6c00 |
155 | isa => (enum ['Storable', 'YAML', 'JSON']), |
d2abd756 |
156 | default => 'Storable', |
157 | ); |
158 | |
f2ef3547 |
159 | role { |
160 | my $p = shift; |
161 | if ($p->format eq 'Storable') { |
162 | method freeze => \&Storable::freeze; |
163 | method thaw => \&Storable::thaw; |
164 | } |
165 | elsif ($p->format eq 'YAML') { |
166 | method freeze => \&YAML::Dump; |
167 | method thaw => \&YAML::Load; |
168 | } |
169 | ... |
d2abd756 |
170 | } |
d2abd756 |
171 | |
172 | =back |
173 | |
93c2fd30 |
174 | =cut |
175 | |