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