1Moose::Cookbook::Roles:U:sCeormpCaornatbrMlioebo_usCteoe:dd:eCRPoeeourkslbeo(Do3ok)c:u:mReonlteast:i:oCnomparable_CodeReuse(3)
2
3
4

NAME

6       Moose::Cookbook::Roles::Comparable_CodeReuse - Using roles for code
7       reuse
8

VERSION

10       version 2.2015
11

SYNOPSIS

13         package Eq;
14         use Moose::Role;
15
16         requires 'equal_to';
17
18         sub not_equal_to {
19             my ( $self, $other ) = @_;
20             not $self->equal_to($other);
21         }
22
23         package Comparable;
24         use Moose::Role;
25
26         with 'Eq';
27
28         requires 'compare';
29
30         sub equal_to {
31             my ( $self, $other ) = @_;
32             $self->compare($other) == 0;
33         }
34
35         sub greater_than {
36             my ( $self, $other ) = @_;
37             $self->compare($other) == 1;
38         }
39
40         sub less_than {
41             my ( $self, $other ) = @_;
42             $self->compare($other) == -1;
43         }
44
45         sub greater_than_or_equal_to {
46             my ( $self, $other ) = @_;
47             $self->greater_than($other) || $self->equal_to($other);
48         }
49
50         sub less_than_or_equal_to {
51             my ( $self, $other ) = @_;
52             $self->less_than($other) || $self->equal_to($other);
53         }
54
55         package Printable;
56         use Moose::Role;
57
58         requires 'to_string';
59
60         package US::Currency;
61         use Moose;
62
63         with 'Comparable', 'Printable';
64
65         has 'amount' => ( is => 'rw', isa => 'Num', default => 0 );
66
67         sub compare {
68             my ( $self, $other ) = @_;
69             $self->amount <=> $other->amount;
70         }
71
72         sub to_string {
73             my $self = shift;
74             sprintf '$%0.2f USD' => $self->amount;
75         }
76

DESCRIPTION

78       Roles have two primary purposes: as interfaces, and as a means of code
79       reuse. This recipe demonstrates the latter, with roles that define
80       comparison and display code for objects.
81
82       Let's start with "Eq". First, note that we've replaced "use Moose" with
83       "use Moose::Role". We also have a new sugar function, "requires":
84
85         requires 'equal_to';
86
87       This says that any class which consumes this role must provide an
88       "equal_to" method. It can provide this method directly, or by consuming
89       some other role.
90
91       The "Eq" role defines its "not_equal_to" method in terms of the
92       required "equal_to" method. This lets us minimize the methods that
93       consuming classes must provide.
94
95       The next role, "Comparable", builds on the "Eq" role. We include "Eq"
96       in "Comparable" using "with", another new sugar function:
97
98         with 'Eq';
99
100       The "with" function takes a list of roles to consume. In our example,
101       the "Comparable" role provides the "equal_to" method required by "Eq".
102       However, it could opt not to, in which case a class that consumed
103       "Comparable" would have to provide its own "equal_to". In other words,
104       a role can consume another role without providing any required methods.
105
106       The "Comparable" role requires a method,  "compare":
107
108         requires 'compare';
109
110       The "Comparable" role also provides a number of other methods, all of
111       which ultimately rely on "compare".
112
113         sub equal_to {
114             my ( $self, $other ) = @_;
115             $self->compare($other) == 0;
116         }
117
118         sub greater_than {
119             my ( $self, $other ) = @_;
120             $self->compare($other) == 1;
121         }
122
123         sub less_than {
124             my ( $self, $other ) = @_;
125             $self->compare($other) == -1;
126         }
127
128         sub greater_than_or_equal_to {
129             my ( $self, $other ) = @_;
130             $self->greater_than($other) || $self->equal_to($other);
131         }
132
133         sub less_than_or_equal_to {
134             my ( $self, $other ) = @_;
135             $self->less_than($other) || $self->equal_to($other);
136         }
137
138       Finally, we define the "Printable" role. This role exists solely to
139       provide an interface. It has no methods, just a list of required
140       methods.  In this case, it just requires a "to_string" method.
141
142       An interface role is useful because it defines both a method and a
143       name. We know that any class which does this role has a "to_string"
144       method, but we can also assume that this method has the semantics we
145       want. Presumably, in real code we would define those semantics in the
146       documentation for the "Printable" role. (1)
147
148       Finally, we have the "US::Currency" class which consumes both the
149       "Comparable" and "Printable" roles.
150
151         with 'Comparable', 'Printable';
152
153       It also defines a regular Moose attribute, "amount":
154
155         has 'amount' => ( is => 'rw', isa => 'Num', default => 0 );
156
157       Finally we see the implementation of the methods required by our roles.
158       We have a "compare" method:
159
160         sub compare {
161             my ( $self, $other ) = @_;
162             $self->amount <=> $other->amount;
163         }
164
165       By consuming the "Comparable" role and defining this method, we gain
166       the following methods for free: "equal_to", "greater_than",
167       "less_than", "greater_than_or_equal_to" and "less_than_or_equal_to".
168
169       Then we have our "to_string" method:
170
171         sub to_string {
172             my $self = shift;
173             sprintf '$%0.2f USD' => $self->amount;
174         }
175

CONCLUSION

177       Roles can be very powerful. They are a great way of encapsulating
178       reusable behavior, as well as communicating (semantic and interface)
179       information about the methods our classes provide.
180

FOOTNOTES

182       (1) Consider two classes, "Runner" and "Process", both of which define
183           a "run" method. If we just require that an object implements a
184           "run" method, we still aren't saying anything about what that
185           method actually does. If we require an object that implements the
186           "Executable" role, we're saying something about semantics.
187

AUTHORS

189       •   Stevan Little <stevan@cpan.org>
190
191       •   Dave Rolsky <autarch@urth.org>
192
193       •   Jesse Luehrs <doy@cpan.org>
194
195       •   Shawn M Moore <sartak@cpan.org>
196
197       •   יובל קוג'מן (Yuval Kogman) <nothingmuch@woobling.org>
198
199       •   Karen Etheridge <ether@cpan.org>
200
201       •   Florian Ragwitz <rafl@debian.org>
202
203       •   Hans Dieter Pearcey <hdp@cpan.org>
204
205       •   Chris Prather <chris@prather.org>
206
207       •   Matt S Trout <mstrout@cpan.org>
208
210       This software is copyright (c) 2006 by Infinity Interactive, Inc.
211
212       This is free software; you can redistribute it and/or modify it under
213       the same terms as the Perl 5 programming language system itself.
214
215
216
217perl v5.34.0                   Moo2s0e2:1:-C0o7o-k2b2ook::Roles::Comparable_CodeReuse(3)
Impressum