This commit is contained in:
230
CPAN/Moose/Cookbook/Roles/Restartable_AdvancedComposition.pod
Normal file
230
CPAN/Moose/Cookbook/Roles/Restartable_AdvancedComposition.pod
Normal file
@@ -0,0 +1,230 @@
|
||||
# PODNAME: Moose::Cookbook::Roles::Restartable_AdvancedComposition
|
||||
# ABSTRACT: Advanced Role Composition - method exclusion and aliasing
|
||||
|
||||
__END__
|
||||
|
||||
=pod
|
||||
|
||||
=encoding UTF-8
|
||||
|
||||
=head1 NAME
|
||||
|
||||
Moose::Cookbook::Roles::Restartable_AdvancedComposition - Advanced Role Composition - method exclusion and aliasing
|
||||
|
||||
=head1 VERSION
|
||||
|
||||
version 2.2207
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
package Restartable;
|
||||
use Moose::Role;
|
||||
|
||||
has 'is_paused' => (
|
||||
is => 'rw',
|
||||
isa => 'Bool',
|
||||
default => 0,
|
||||
);
|
||||
|
||||
requires 'save_state', 'load_state';
|
||||
|
||||
sub stop { 1 }
|
||||
|
||||
sub start { 1 }
|
||||
|
||||
package Restartable::ButUnreliable;
|
||||
use Moose::Role;
|
||||
|
||||
with 'Restartable' => {
|
||||
-alias => {
|
||||
stop => '_stop',
|
||||
start => '_start'
|
||||
},
|
||||
-excludes => [ 'stop', 'start' ],
|
||||
};
|
||||
|
||||
sub stop {
|
||||
my $self = shift;
|
||||
|
||||
$self->explode() if rand(1) > .5;
|
||||
|
||||
$self->_stop();
|
||||
}
|
||||
|
||||
sub start {
|
||||
my $self = shift;
|
||||
|
||||
$self->explode() if rand(1) > .5;
|
||||
|
||||
$self->_start();
|
||||
}
|
||||
|
||||
package Restartable::ButBroken;
|
||||
use Moose::Role;
|
||||
|
||||
with 'Restartable' => { -excludes => [ 'stop', 'start' ] };
|
||||
|
||||
sub stop {
|
||||
my $self = shift;
|
||||
|
||||
$self->explode();
|
||||
}
|
||||
|
||||
sub start {
|
||||
my $self = shift;
|
||||
|
||||
$self->explode();
|
||||
}
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
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 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
|
||||
original implementation. To do this, we alias the methods from
|
||||
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>. 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
|
||||
string as an argument if you just want to exclude one method.
|
||||
|
||||
with 'Restartable' => { -excludes => [ 'stop', 'start' ] };
|
||||
|
||||
=head1 CONCLUSION
|
||||
|
||||
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.
|
||||
|
||||
=head1 FOOTNOTES
|
||||
|
||||
=over 4
|
||||
|
||||
=item (1)
|
||||
|
||||
The mention of wrapper should tell you that we could do the same thing
|
||||
using method modifiers, but for the sake of this example, we don't.
|
||||
|
||||
=back
|
||||
|
||||
=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
|
||||
|
||||
=head1 AUTHORS
|
||||
|
||||
=over 4
|
||||
|
||||
=item *
|
||||
|
||||
Stevan Little <stevan@cpan.org>
|
||||
|
||||
=item *
|
||||
|
||||
Dave Rolsky <autarch@urth.org>
|
||||
|
||||
=item *
|
||||
|
||||
Jesse Luehrs <doy@cpan.org>
|
||||
|
||||
=item *
|
||||
|
||||
Shawn M Moore <sartak@cpan.org>
|
||||
|
||||
=item *
|
||||
|
||||
יובל קוג'מן (Yuval Kogman) <nothingmuch@woobling.org>
|
||||
|
||||
=item *
|
||||
|
||||
Karen Etheridge <ether@cpan.org>
|
||||
|
||||
=item *
|
||||
|
||||
Florian Ragwitz <rafl@debian.org>
|
||||
|
||||
=item *
|
||||
|
||||
Hans Dieter Pearcey <hdp@cpan.org>
|
||||
|
||||
=item *
|
||||
|
||||
Chris Prather <chris@prather.org>
|
||||
|
||||
=item *
|
||||
|
||||
Matt S Trout <mstrout@cpan.org>
|
||||
|
||||
=back
|
||||
|
||||
=head1 COPYRIGHT AND LICENSE
|
||||
|
||||
This software is copyright (c) 2006 by Infinity Interactive, Inc.
|
||||
|
||||
This is free software; you can redistribute it and/or modify it under
|
||||
the same terms as the Perl 5 programming language system itself.
|
||||
|
||||
=cut
|
||||
Reference in New Issue
Block a user