DEATH TO ALL zionist ELLIPSES
[gitmo/Moose.git] / lib / Moose / Cookbook / Roles / Recipe1.pod
CommitLineData
a7d0cd00 1
2=pod
3
4=head1 NAME
5
021b8139 6Moose::Cookbook::Roles::Recipe1 - The Moose::Role example
a7d0cd00 7
8=head1 SYNOPSIS
9e93dd19 9
446e850f 10 package Eq;
a7d0cd00 11 use Moose::Role;
a39ea7dc 12
446e850f 13 requires 'equal_to';
a39ea7dc 14
15 sub not_equal_to {
16 my ( $self, $other ) = @_;
9e93dd19 17 not $self->equal_to($other);
a7d0cd00 18 }
a39ea7dc 19
9e93dd19 20 package Comparable;
a7d0cd00 21 use Moose::Role;
a39ea7dc 22
446e850f 23 with 'Eq';
a39ea7dc 24
446e850f 25 requires 'compare';
a39ea7dc 26
446e850f 27 sub equal_to {
a39ea7dc 28 my ( $self, $other ) = @_;
446e850f 29 $self->compare($other) == 0;
a39ea7dc 30 }
31
446e850f 32 sub greater_than {
a39ea7dc 33 my ( $self, $other ) = @_;
446e850f 34 $self->compare($other) == 1;
a39ea7dc 35 }
36
446e850f 37 sub less_than {
a39ea7dc 38 my ( $self, $other ) = @_;
446e850f 39 $self->compare($other) == -1;
a7d0cd00 40 }
a39ea7dc 41
446e850f 42 sub greater_than_or_equal_to {
a39ea7dc 43 my ( $self, $other ) = @_;
446e850f 44 $self->greater_than($other) || $self->equal_to($other);
a39ea7dc 45 }
46
446e850f 47 sub less_than_or_equal_to {
a39ea7dc 48 my ( $self, $other ) = @_;
446e850f 49 $self->less_than($other) || $self->equal_to($other);
a39ea7dc 50 }
51
9e93dd19 52 package Printable;
9e93dd19 53 use Moose::Role;
a39ea7dc 54
55 requires 'to_string';
56
446e850f 57 package US::Currency;
a7d0cd00 58 use Moose;
a39ea7dc 59
9e93dd19 60 with 'Comparable', 'Printable';
a39ea7dc 61
62 has 'amount' => ( is => 'rw', isa => 'Num', default => 0 );
63
446e850f 64 sub compare {
a39ea7dc 65 my ( $self, $other ) = @_;
446e850f 66 $self->amount <=> $other->amount;
67 }
a39ea7dc 68
9e93dd19 69 sub to_string {
70 my $self = shift;
a39ea7dc 71 sprintf '$%0.2f USD' => $self->amount;
9e93dd19 72 }
cb26ee7e 73
a7d0cd00 74=head1 DESCRIPTION
75
efaf28e9 76Roles have two primary purposes: as interfaces, and as a means of code
77reuse. This recipe demonstrates the latter, with roles that define
78comparison and display code for objects.
cb26ee7e 79
19320607 80Let's start with C<Eq>. First, note that we've replaced C<use Moose>
695a3797 81with C<use Moose::Role>. We also have a new sugar function, C<requires>:
cb26ee7e 82
83 requires 'equal_to';
84
efaf28e9 85This says that any class which consumes this role must provide an
86C<equal_to> method. It can provide this method directly, or by
87consuming some other role.
cb26ee7e 88
efaf28e9 89The C<Eq> role defines its C<not_equal_to> method in terms of the
90required C<equal_to> method. This lets us minimize the methods that
91consuming classes must provide.
cb26ee7e 92
efaf28e9 93The next role, C<Comparable>, builds on the C<Eq> role. We include
94C<Eq> in C<Comparable> using C<with>, another new sugar function:
cb26ee7e 95
96 with 'Eq';
97
efaf28e9 98The C<with> function takes a list of roles to consume. In our example,
99the C<Comparable> role provides the C<equal_to> method required by
100C<Eq>. However, it could opt not to, in which case a class that
101consumed C<Comparable> would have to provide its own C<equal_to>. In
102other words, a role can consume another role I<without> providing any
103required methods.
cb26ee7e 104
efaf28e9 105The C<Comparable> role requires a method, C<compare>:
cb26ee7e 106
107 requires 'compare';
108
efaf28e9 109The C<Comparable> role also provides a number of other methods, all of
110which ultimately rely on C<compare>.
cb26ee7e 111
112 sub equal_to {
a39ea7dc 113 my ( $self, $other ) = @_;
cb26ee7e 114 $self->compare($other) == 0;
115 }
a39ea7dc 116
cb26ee7e 117 sub greater_than {
a39ea7dc 118 my ( $self, $other ) = @_;
cb26ee7e 119 $self->compare($other) == 1;
a39ea7dc 120 }
121
cb26ee7e 122 sub less_than {
a39ea7dc 123 my ( $self, $other ) = @_;
cb26ee7e 124 $self->compare($other) == -1;
125 }
a39ea7dc 126
cb26ee7e 127 sub greater_than_or_equal_to {
a39ea7dc 128 my ( $self, $other ) = @_;
cb26ee7e 129 $self->greater_than($other) || $self->equal_to($other);
a39ea7dc 130 }
131
cb26ee7e 132 sub less_than_or_equal_to {
a39ea7dc 133 my ( $self, $other ) = @_;
cb26ee7e 134 $self->less_than($other) || $self->equal_to($other);
135 }
136
efaf28e9 137Finally, we the C<Printable> role. This role exists solely to provide
138an interface. It has no methods, just a list of required methods. In
139this case, it just requires a C<to_string> method.
cb26ee7e 140
efaf28e9 141An interface role is useful because it defines both a method and a
142I<name>. We know that any class which does this role has a
143C<to_string> method, but we can also assume that this method has the
144semantics we want. Presumably, in real code we would define those
145semantics in the documentation for the C<Printable> role. (1)
146
147Finally, we have the C<US::Currency> class which consumes both the
148C<Comparable> and C<Printable> roles.
cb26ee7e 149
150 with 'Comparable', 'Printable';
151
efaf28e9 152It also defines a regular Moose attribute, C<amount>:
cb26ee7e 153
a39ea7dc 154 has 'amount' => ( is => 'rw', isa => 'Num', default => 0 );
cb26ee7e 155
efaf28e9 156Finally we see the implementation of the methods required by our
157roles. We have a C<compare> method:
cb26ee7e 158
159 sub compare {
a39ea7dc 160 my ( $self, $other ) = @_;
cb26ee7e 161 $self->amount <=> $other->amount;
162 }
163
efaf28e9 164By consuming the C<Comparable> role and defining this method, we gain
165the following methods for free: C<equal_to>, C<greater_than>,
166C<less_than>, C<greater_than_or_equal_to> and
cb26ee7e 167C<less_than_or_equal_to>.
168
efaf28e9 169Then we have our C<to_string> method:
cb26ee7e 170
171 sub to_string {
172 my $self = shift;
a39ea7dc 173 sprintf '$%0.2f USD' => $self->amount;
cb26ee7e 174 }
175
176=head1 CONCLUSION
177
9b3a690c 178Roles can be very powerful. They are a great way of encapsulating
efaf28e9 179reusable behavior, as well as communicating (semantic and interface)
180information about the methods our classes provide.
cb26ee7e 181
182=head1 FOOTNOTES
183
184=over 4
185
186=item (1)
187
efaf28e9 188Consider two classes, C<Runner> and C<Process>, both of which define a
189C<run> method. If we just require that an object implements a C<run>
190method, we still aren't saying anything about what that method
191I<actually does>. If we require an object that implements the
192C<Executable> role, we're saying something about semantics.
cb26ee7e 193
194=back
a7d0cd00 195
efaf28e9 196=head1 AUTHORS
a7d0cd00 197
198Stevan Little E<lt>stevan@iinteractive.comE<gt>
199
efaf28e9 200Dave Rolsky E<lt>autarch@urth.orgE<gt>
201
a7d0cd00 202=head1 COPYRIGHT AND LICENSE
203
2840a3b2 204Copyright 2006-2009 by Infinity Interactive, Inc.
a7d0cd00 205
206L<http://www.iinteractive.com>
207
208This library is free software; you can redistribute it and/or modify
209it under the same terms as Perl itself.
210
c79239a2 211=begin testing
212
1808c2da 213ok( US::Currency->does('Comparable'), 'US::Currency does Comparable' );
214ok( US::Currency->does('Eq'), 'US::Currency does Eq' );
215ok( US::Currency->does('Printable'), 'US::Currency does Printable' );
c79239a2 216
217my $hundred = US::Currency->new( amount => 100.00 );
218isa_ok( $hundred, 'US::Currency' );
219
220ok( $hundred->DOES("US::Currency"), "UNIVERSAL::DOES for class" );
221ok( $hundred->DOES("Comparable"), "UNIVERSAL::DOES for role" );
222
223can_ok( $hundred, 'amount' );
1808c2da 224is( $hundred->amount, 100, 'got the right amount' );
c79239a2 225
226can_ok( $hundred, 'to_string' );
227is( $hundred->to_string, '$100.00 USD',
1808c2da 228 'got the right stringified value' );
c79239a2 229
1808c2da 230ok( $hundred->does('Comparable'), 'US::Currency does Comparable' );
231ok( $hundred->does('Eq'), 'US::Currency does Eq' );
232ok( $hundred->does('Printable'), 'US::Currency does Printable' );
c79239a2 233
234my $fifty = US::Currency->new( amount => 50.00 );
235isa_ok( $fifty, 'US::Currency' );
236
237can_ok( $fifty, 'amount' );
1808c2da 238is( $fifty->amount, 50, 'got the right amount' );
c79239a2 239
240can_ok( $fifty, 'to_string' );
1808c2da 241is( $fifty->to_string, '$50.00 USD', 'got the right stringified value' );
242
243ok( $hundred->greater_than($fifty), '100 gt 50' );
244ok( $hundred->greater_than_or_equal_to($fifty), '100 ge 50' );
245ok( !$hundred->less_than($fifty), '!100 lt 50' );
246ok( !$hundred->less_than_or_equal_to($fifty), '!100 le 50' );
247ok( !$hundred->equal_to($fifty), '!100 eq 50' );
248ok( $hundred->not_equal_to($fifty), '100 ne 50' );
249
250ok( !$fifty->greater_than($hundred), '!50 gt 100' );
251ok( !$fifty->greater_than_or_equal_to($hundred), '!50 ge 100' );
252ok( $fifty->less_than($hundred), '50 lt 100' );
253ok( $fifty->less_than_or_equal_to($hundred), '50 le 100' );
254ok( !$fifty->equal_to($hundred), '!50 eq 100' );
255ok( $fifty->not_equal_to($hundred), '50 ne 100' );
256
257ok( !$fifty->greater_than($fifty), '!50 gt 50' );
258ok( $fifty->greater_than_or_equal_to($fifty), '!50 ge 50' );
259ok( !$fifty->less_than($fifty), '50 lt 50' );
260ok( $fifty->less_than_or_equal_to($fifty), '50 le 50' );
261ok( $fifty->equal_to($fifty), '50 eq 50' );
262ok( !$fifty->not_equal_to($fifty), '!50 ne 50' );
c79239a2 263
264## ... check some meta-stuff
265
266# Eq
267
268my $eq_meta = Eq->meta;
269isa_ok( $eq_meta, 'Moose::Meta::Role' );
270
1808c2da 271ok( $eq_meta->has_method('not_equal_to'), 'Eq has_method not_equal_to' );
c79239a2 272ok( $eq_meta->requires_method('equal_to'),
1808c2da 273 'Eq requires_method not_equal_to' );
c79239a2 274
275# Comparable
276
277my $comparable_meta = Comparable->meta;
278isa_ok( $comparable_meta, 'Moose::Meta::Role' );
279
1808c2da 280ok( $comparable_meta->does_role('Eq'), 'Comparable does Eq' );
c79239a2 281
282foreach my $method_name (
283 qw(
284 equal_to not_equal_to
285 greater_than greater_than_or_equal_to
286 less_than less_than_or_equal_to
287 )
288 ) {
289 ok( $comparable_meta->has_method($method_name),
1808c2da 290 'Comparable has_method ' . $method_name );
c79239a2 291}
292
293ok( $comparable_meta->requires_method('compare'),
1808c2da 294 'Comparable requires_method compare' );
c79239a2 295
296# Printable
297
298my $printable_meta = Printable->meta;
299isa_ok( $printable_meta, 'Moose::Meta::Role' );
300
301ok( $printable_meta->requires_method('to_string'),
1808c2da 302 'Printable requires_method to_string' );
c79239a2 303
304# US::Currency
305
306my $currency_meta = US::Currency->meta;
307isa_ok( $currency_meta, 'Moose::Meta::Class' );
308
309ok( $currency_meta->does_role('Comparable'),
1808c2da 310 'US::Currency does Comparable' );
311ok( $currency_meta->does_role('Eq'), 'US::Currency does Eq' );
c79239a2 312ok( $currency_meta->does_role('Printable'),
1808c2da 313 'US::Currency does Printable' );
c79239a2 314
315foreach my $method_name (
316 qw(
317 amount
318 equal_to not_equal_to
319 compare
320 greater_than greater_than_or_equal_to
321 less_than less_than_or_equal_to
322 to_string
323 )
324 ) {
325 ok( $currency_meta->has_method($method_name),
1808c2da 326 'US::Currency has_method ' . $method_name );
c79239a2 327}
328
329=end testing
330
a39ea7dc 331=cut