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