+package Moose::Cookbook::Roles::Recipe2;
-=pod
+# ABSTRACT: Advanced Role Composition - method exclusion and aliasing
+
+__END__
-=head1 NAME
-Moose::Cookbook::Roles::Recipe2 - Advanced Role Composition - method exclusion and aliasing
+=pod
=head1 SYNOPSIS
requires 'save_state', 'load_state';
- sub stop { ... }
+ sub stop { 1 }
- sub start { ... }
+ sub start { 1 }
package Restartable::ButUnreliable;
use Moose::Role;
with 'Restartable' => {
- alias => {
+ -alias => {
stop => '_stop',
start => '_start'
- }
+ },
+ -excludes => [ 'stop', 'start' ],
};
sub stop {
package Restartable::ButBroken;
use Moose::Role;
- with 'Restartable' => { excludes => [ 'stop', 'start' ] };
+ with 'Restartable' => { -excludes => [ 'stop', 'start' ] };
sub stop {
my $self = shift;
=head1 DESCRIPTION
-Sometimes when you include a role in a class, you may want to leave
-out some of its methods. In this example, we have a role C<Restartable>
-which provides an C<is_paused> attribute, and two methods, C<stop> and
-C<start>. The implementation of those two methods is irrelevant.
+In this example, we demonstrate how to exercise fine-grained control
+over what methods we consume from a role. We have a C<Restartable>
+role which provides an C<is_paused> attribute, and two methods,
+C<stop> and C<start>.
-Then we have two more roles which also implement the same interface,
-each putting their own spin on the C<stop> and C<start> method.
+Then we have two more roles which implement the same interface, each
+putting their own spin on the C<stop> and C<start> methods.
In the C<Restartable::ButUnreliable> role, we want to provide a new
implementation of C<stop> and C<start>, but still have access to the
C<Restartable> to private methods, and provide wrappers around the
originals (1).
+Note that aliasing simply I<adds> a name, so we also need to exclude the
+methods with their original names.
+
+ with 'Restartable' => {
+ -alias => {
+ stop => '_stop',
+ start => '_start'
+ },
+ -excludes => [ 'stop', 'start' ],
+ };
+
In the C<Restartable::ButBroken> role, we want to provide an entirely
-new behavior for C<stop> and C<start>, so we exclude them when
+new behavior for C<stop> and C<start>. We exclude them entirely when
composing the C<Restartable> role into C<Restartable::ButBroken>.
-It's worth noting that the C<excludes> parameter also accepts a single
+It's worth noting that the C<-excludes> parameter also accepts a single
string as an argument if you just want to exclude one method.
+ with 'Restartable' => { -excludes => [ 'stop', 'start' ] };
+
=head1 CONCLUSION
-Method exclusion and renaming can come in handy, especially when
-building roles out of other roles. In this example, all of our roles
-implement the C<Restartable> role. Each role provides same API, but
-each has a different implementation under the hood.
+Exclusion and renaming are a power tool that can be handy, especially
+when building roles out of other roles. In this example, all of our
+roles implement the C<Restartable> role. Each role provides same API,
+but each has a different implementation under the hood.
You can also use the method aliasing and excluding features when
composing a role into a class.
=back
-=head1 AUTHOR
-
-Dave Rolsky E<lt>autarch@urth.orgE<gt>
-
-=head1 COPYRIGHT AND LICENSE
-
-Copyright 2006-2008 by Infinity Interactive, Inc.
-
-L<http://www.iinteractive.com>
-
-This library is free software; you can redistribute it and/or modify
-it under the same terms as Perl itself.
+=begin testing
+
+{
+ my $unreliable = Moose::Meta::Class->create_anon_class(
+ superclasses => [],
+ roles => [qw/Restartable::ButUnreliable/],
+ methods => {
+ explode => sub { }, # nop.
+ 'save_state' => sub { },
+ 'load_state' => sub { },
+ },
+ )->new_object();
+ ok( $unreliable, 'made anon class with Restartable::ButUnreliable role' );
+ can_ok( $unreliable, qw/start stop/ );
+}
+
+{
+ my $cnt = 0;
+ my $broken = Moose::Meta::Class->create_anon_class(
+ superclasses => [],
+ roles => [qw/Restartable::ButBroken/],
+ methods => {
+ explode => sub { $cnt++ },
+ 'save_state' => sub { },
+ 'load_state' => sub { },
+ },
+ )->new_object();
+
+ ok( $broken, 'made anon class with Restartable::ButBroken role' );
+
+ $broken->start();
+
+ is( $cnt, 1, '... start called explode' );
+
+ $broken->stop();
+
+ is( $cnt, 2, '... stop also called explode' );
+}
+
+=end testing
=cut