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