1 package Moose::Cookbook::Roles::Recipe2;
3 # ABSTRACT: Advanced Role Composition - method exclusion and aliasing
21 requires 'save_state', 'load_state';
27 package Restartable::ButUnreliable;
30 with 'Restartable' => {
35 -excludes => [ 'stop', 'start' ],
41 $self->explode() if rand(1) > .5;
49 $self->explode() if rand(1) > .5;
54 package Restartable::ButBroken;
57 with 'Restartable' => { -excludes => [ 'stop', 'start' ] };
73 In this example, we demonstrate how to exercise fine-grained control
74 over what methods we consume from a role. We have a C<Restartable>
75 role which provides an C<is_paused> attribute, and two methods,
78 Then we have two more roles which implement the same interface, each
79 putting their own spin on the C<stop> and C<start> methods.
81 In the C<Restartable::ButUnreliable> role, we want to provide a new
82 implementation of C<stop> and C<start>, but still have access to the
83 original implementation. To do this, we alias the methods from
84 C<Restartable> to private methods, and provide wrappers around the
87 Note that aliasing simply I<adds> a name, so we also need to exclude the
88 methods with their original names.
90 with 'Restartable' => {
95 -excludes => [ 'stop', 'start' ],
98 In the C<Restartable::ButBroken> role, we want to provide an entirely
99 new behavior for C<stop> and C<start>. We exclude them entirely when
100 composing the C<Restartable> role into C<Restartable::ButBroken>.
102 It's worth noting that the C<-excludes> parameter also accepts a single
103 string as an argument if you just want to exclude one method.
105 with 'Restartable' => { -excludes => [ 'stop', 'start' ] };
109 Exclusion and renaming are a power tool that can be handy, especially
110 when building roles out of other roles. In this example, all of our
111 roles implement the C<Restartable> role. Each role provides same API,
112 but each has a different implementation under the hood.
114 You can also use the method aliasing and excluding features when
115 composing a role into a class.
123 The mention of wrapper should tell you that we could do the same thing
124 using method modifiers, but for the sake of this example, we don't.
131 my $unreliable = Moose::Meta::Class->create_anon_class(
133 roles => [qw/Restartable::ButUnreliable/],
135 explode => sub { }, # nop.
136 'save_state' => sub { },
137 'load_state' => sub { },
140 ok( $unreliable, 'made anon class with Restartable::ButUnreliable role' );
141 can_ok( $unreliable, qw/start stop/ );
146 my $broken = Moose::Meta::Class->create_anon_class(
148 roles => [qw/Restartable::ButBroken/],
150 explode => sub { $cnt++ },
151 'save_state' => sub { },
152 'load_state' => sub { },
156 ok( $broken, 'made anon class with Restartable::ButBroken role' );
160 is( $cnt, 1, '... start called explode' );
164 is( $cnt, 2, '... stop also called explode' );