fixed the test for method modifiers
[gitmo/Moose.git] / lib / Moose / Cookbook / Recipe10.pod
CommitLineData
a7d0cd00 1
2=pod
3
4=head1 NAME
5
496b74ab 6Moose::Cookbook::Recipe10 - The Moose::Role example
a7d0cd00 7
8=head1 SYNOPSIS
9e93dd19 9
446e850f 10 package Eq;
a7d0cd00 11 use Moose::Role;
12
446e850f 13 requires 'equal_to';
a7d0cd00 14
446e850f 15 sub not_equal_to {
16 my ($self, $other) = @_;
9e93dd19 17 not $self->equal_to($other);
a7d0cd00 18 }
19
9e93dd19 20 package Comparable;
a7d0cd00 21 use Moose::Role;
22
446e850f 23 with 'Eq';
a7d0cd00 24
446e850f 25 requires 'compare';
a7d0cd00 26
446e850f 27 sub equal_to {
28 my ($self, $other) = @_;
29 $self->compare($other) == 0;
30 }
a7d0cd00 31
446e850f 32 sub greater_than {
33 my ($self, $other) = @_;
34 $self->compare($other) == 1;
35 }
a7d0cd00 36
446e850f 37 sub less_than {
38 my ($self, $other) = @_;
39 $self->compare($other) == -1;
a7d0cd00 40 }
41
446e850f 42 sub greater_than_or_equal_to {
43 my ($self, $other) = @_;
44 $self->greater_than($other) || $self->equal_to($other);
45 }
a7d0cd00 46
446e850f 47 sub less_than_or_equal_to {
48 my ($self, $other) = @_;
49 $self->less_than($other) || $self->equal_to($other);
9e93dd19 50 }
51
52 package Printable;
9e93dd19 53 use Moose::Role;
54
55 requires 'to_string';
a7d0cd00 56
446e850f 57 package US::Currency;
a7d0cd00 58 use Moose;
59
9e93dd19 60 with 'Comparable', 'Printable';
a7d0cd00 61
9e93dd19 62 has 'amount' => (is => 'rw', isa => 'Num', default => 0);
446e850f 63
64 sub compare {
65 my ($self, $other) = @_;
66 $self->amount <=> $other->amount;
67 }
a7d0cd00 68
9e93dd19 69 sub to_string {
70 my $self = shift;
71 sprintf '$%0.2f USD' => $self->amount
72 }
cb26ee7e 73
a7d0cd00 74=head1 DESCRIPTION
75
cb26ee7e 76In this recipe we examine the role support provided in Moose. "Roles" may be
77described in many ways, but there are two main ways in which they are used: as
78interfaces, and as a means of code reuse. This recipe demonstrates the
79construction and incorporation of roles that define comparison and display of
80objects.
81
82Let's start by examining B<Eq>. You'll notice that instead of the familiar C<use
83Moose> you might be expecting, here we use C<Moose::Role> to make it clear that
84this is a role. We encounter a new keyword, C<requires>:
85
86 requires 'equal_to';
87
88What this does is to indicate that any class which "consumes" (that is to say,
89"includes using C<with>", as we'll see a little later) the B<Eq> role I<must>
90include an C<equal_to> method, whether this is provided by the class itself, one
91of its superclasses, or another role consumed by the class (1).
92
93In addition to requiring an C<equal_to> method, B<Eq> defines a C<not_equal_to>
94method, which simply inverts the result of C<equal_to>. Defining additional
95methods in this way, by using only a few base methods that target classes must
96define, is a useful pattern to provide maximum functionality with minimum
97effort.
98
99After the minimal B<Eq>, we next move on to B<Comparable>. The first thing you
100will notice is another new keyword, C<with>:
101
102 with 'Eq';
103
104C<with> is used to provide a list of roles which this class (or role) consumes.
105Here, B<Comparable> only consumes one role (B<Eq>). In effect, it is as if we
106defined a C<not_equal_to> method within Comparable, and also promised to fulfill
107the requirement of an C<equal_to> method.
108
109B<Comparable> itself states that it requires C<compare>. Again, it means that
110any classes consuming this role must implement a C<compare> method.
111
112 requires 'compare';
113
114B<Comparable> defines an C<equal_to> method which satisfies the B<Eq> role's
115requirements. This, along with a number of other methods (C<greater_than>,
116C<less_than>, C<greater_than_or_equal_to>, and C<less_than_or_equal_to>) is
117simply defined in terms of C<compare>, once again demonstrating the pattern of
118defining a number of utility methods in terms of only a single method that the
119target class need implement.
120
121 sub equal_to {
122 my ($self, $other) = @_;
123 $self->compare($other) == 0;
124 }
125
126 sub greater_than {
127 my ($self, $other) = @_;
128 $self->compare($other) == 1;
129 }
130
131 sub less_than {
132 my ($self, $other) = @_;
133 $self->compare($other) == -1;
134 }
135
136 sub greater_than_or_equal_to {
137 my ($self, $other) = @_;
138 $self->greater_than($other) || $self->equal_to($other);
139 }
140
141 sub less_than_or_equal_to {
142 my ($self, $other) = @_;
143 $self->less_than($other) || $self->equal_to($other);
144 }
145
146Next up is B<Printable>. This is a very simple role, akin to B<Eq>. It merely
147requires a C<to_string> method.
148
149Finally, we come to B<US::Currency>, a class that allows us to reap the benefits
150of our hard work. This is a regular Moose class, so we include the normal C<use
151Moose>. It consumes both B<Comparable> and B<Printable>, as the following line
152shows:
153
154 with 'Comparable', 'Printable';
155
156It also defines a regular Moose attribute, C<amount>, with a type constraint of
157C<Num> and a default of C<0>:
158
159 has 'amount' => (is => 'rw', isa => 'Num', default => 0);
160
161Now we come to the core of the class. First up, we define a C<compare> method:
162
163 sub compare {
164 my ($self, $other) = @_;
165 $self->amount <=> $other->amount;
166 }
167
168As you can see, it simply compares the C<amount> attribute of this object with
169the C<amount> attribute of the other object passed to it. With the single
170definition of this method, we gain the following methods for free: C<equal_to>,
171C<greater_than>, C<less_than>, C<greater_than_or_equal_to> and
172C<less_than_or_equal_to>.
173
174We end the class with a definition of the C<to_string> method, which formats the
175C<amount> attribute for display:
176
177 sub to_string {
178 my $self = shift;
179 sprintf '$%0.2f USD' => $self->amount
180 }
181
182=head1 CONCLUSION
183
184This recipe has shown that roles can be very powerful and immensely useful, and
185save a great deal of repetition.
186
187=head1 FOOTNOTES
188
189=over 4
190
191=item (1)
192
193At present, method requirements from roles cannot be satisfied by attribute
194accessors. This is a limitation of Moose, and will most likely be rectified in a
195future release.
196
197=back
a7d0cd00 198
a7d0cd00 199=head1 AUTHOR
200
201Stevan Little E<lt>stevan@iinteractive.comE<gt>
202
203=head1 COPYRIGHT AND LICENSE
204
778db3ac 205Copyright 2006-2008 by Infinity Interactive, Inc.
a7d0cd00 206
207L<http://www.iinteractive.com>
208
209This library is free software; you can redistribute it and/or modify
210it under the same terms as Perl itself.
211
212=cut