Add release date
[gitmo/Moose.git] / lib / Moose / Cookbook / Roles / Recipe2.pod
CommitLineData
2e3d0a0a 1
2=pod
3
4=head1 NAME
5
021b8139 6Moose::Cookbook::Roles::Recipe2 - Advanced Role Composition - method exclusion and aliasing
2e3d0a0a 7
8=head1 SYNOPSIS
9
10 package Restartable;
11 use Moose::Role;
12
13 has 'is_paused' => (
14 is => 'rw',
9711d93b 15 isa => 'Bool',
2e3d0a0a 16 default => 0,
17 );
18
19 requires 'save_state', 'load_state';
20
c79239a2 21 sub stop { 1 }
2e3d0a0a 22
c79239a2 23 sub start { 1 }
2e3d0a0a 24
25 package Restartable::ButUnreliable;
26 use Moose::Role;
27
a39ea7dc 28 with 'Restartable' => {
29 alias => {
30 stop => '_stop',
31 start => '_start'
32 }
33 };
2e3d0a0a 34
35 sub stop {
36 my $self = shift;
37
38 $self->explode() if rand(1) > .5;
39
40 $self->_stop();
41 }
42
43 sub start {
44 my $self = shift;
45
46 $self->explode() if rand(1) > .5;
47
48 $self->_start();
49 }
50
51 package Restartable::ButBroken;
52 use Moose::Role;
53
54 with 'Restartable' => { excludes => [ 'stop', 'start' ] };
55
56 sub stop {
57 my $self = shift;
58
59 $self->explode();
60 }
61
62 sub start {
63 my $self = shift;
64
65 $self->explode();
66 }
67
68=head1 DESCRIPTION
69
aa8d5e2d 70In this example, we demonstrate how to exercise fine-grained control
71over what methods we consume from a role. We have a C<Restartable>
72role which provides an C<is_paused> attribute, and two methods,
73C<stop> and C<start>.
2e3d0a0a 74
aa8d5e2d 75Then we have two more roles which implement the same interface, each
76putting their own spin on the C<stop> and C<start> methods.
2e3d0a0a 77
78In the C<Restartable::ButUnreliable> role, we want to provide a new
79implementation of C<stop> and C<start>, but still have access to the
80original implementation. To do this, we alias the methods from
81C<Restartable> to private methods, and provide wrappers around the
82originals (1).
83
aa8d5e2d 84 with 'Restartable' => {
85 alias => {
86 stop => '_stop',
87 start => '_start'
88 }
89 };
90
2e3d0a0a 91In the C<Restartable::ButBroken> role, we want to provide an entirely
aa8d5e2d 92new behavior for C<stop> and C<start>. We exclude them entirely when
2e3d0a0a 93composing the C<Restartable> role into C<Restartable::ButBroken>.
94
95It's worth noting that the C<excludes> parameter also accepts a single
96string as an argument if you just want to exclude one method.
97
aa8d5e2d 98 with 'Restartable' => { excludes => [ 'stop', 'start' ] };
99
2e3d0a0a 100=head1 CONCLUSION
101
aa8d5e2d 102Exclusion and renaming are a power tool that can be handy, especially
103when building roles out of other roles. In this example, all of our
104roles implement the C<Restartable> role. Each role provides same API,
105but each has a different implementation under the hood.
2e3d0a0a 106
107You can also use the method aliasing and excluding features when
108composing a role into a class.
109
110=head1 FOOTNOTES
111
112=over 4
113
114=item (1)
115
116The mention of wrapper should tell you that we could do the same thing
117using method modifiers, but for the sake of this example, we don't.
118
119=back
120
121=head1 AUTHOR
122
123Dave Rolsky E<lt>autarch@urth.orgE<gt>
124
125=head1 COPYRIGHT AND LICENSE
126
2840a3b2 127Copyright 2006-2009 by Infinity Interactive, Inc.
2e3d0a0a 128
129L<http://www.iinteractive.com>
130
131This library is free software; you can redistribute it and/or modify
132it under the same terms as Perl itself.
133
c79239a2 134=begin testing
135
136{
137 my $unreliable = Moose::Meta::Class->create_anon_class(
138 superclasses => [],
139 roles => [qw/Restartable::ButUnreliable/],
140 methods => {
141 explode => sub { }, # nop.
142 'save_state' => sub { },
143 'load_state' => sub { },
144 },
145 )->new_object();
146 ok( $unreliable, 'made anon class with Restartable::ButUnreliable role' );
147 can_ok( $unreliable, qw/start stop/ );
148}
149
150{
151 my $cnt = 0;
152 my $broken = Moose::Meta::Class->create_anon_class(
153 superclasses => [],
154 roles => [qw/Restartable::ButBroken/],
155 methods => {
156 explode => sub { $cnt++ },
157 'save_state' => sub { },
158 'load_state' => sub { },
159 },
160 )->new_object();
161
162 ok( $broken, 'made anon class with Restartable::ButBroken role' );
163
164 $broken->start();
165
166 is( $cnt, 1, '... start called explode' );
167
168 $broken->stop();
169
170 is( $cnt, 2, '... stop also called explode' );
171}
172
173=end testing
174
2e3d0a0a 175=cut