diff options
author | Lorry Tar Creator <lorry-tar-importer@lorry> | 2015-06-06 17:50:16 +0000 |
---|---|---|
committer | Lorry Tar Creator <lorry-tar-importer@lorry> | 2015-06-06 17:50:16 +0000 |
commit | 5ac2026f7eed78958d69d051e7a8e993dcf51205 (patch) | |
tree | 298c3d2f08bdfe5689998b11892d72a897985be1 /lib/Moose/Manual/Roles.pod | |
download | Moose-tarball-5ac2026f7eed78958d69d051e7a8e993dcf51205.tar.gz |
Moose-2.1405HEADMoose-2.1405master
Diffstat (limited to 'lib/Moose/Manual/Roles.pod')
-rw-r--r-- | lib/Moose/Manual/Roles.pod | 422 |
1 files changed, 422 insertions, 0 deletions
diff --git a/lib/Moose/Manual/Roles.pod b/lib/Moose/Manual/Roles.pod new file mode 100644 index 0000000..3000e39 --- /dev/null +++ b/lib/Moose/Manual/Roles.pod @@ -0,0 +1,422 @@ +# PODNAME: Moose::Manual::Roles +# ABSTRACT: Roles, an alternative to deep hierarchies and base classes + +__END__ + +=pod + +=encoding UTF-8 + +=head1 NAME + +Moose::Manual::Roles - Roles, an alternative to deep hierarchies and base classes + +=head1 VERSION + +version 2.1405 + +=head1 WHAT IS A ROLE? + +A role encapsulates some piece of behavior or state that can be shared between +classes. It is something that classes I<do>. It is important to understand that +I<roles are not classes>. You cannot inherit from a role, and a role cannot be +instantiated. We sometimes say that roles are I<consumed>, either by classes +or other roles. + +Instead, a role is I<composed> into a class. In practical terms, this +means that all of the methods, method modifiers, and attributes defined in a role are +added directly to (we sometimes say "flattened into") the class that +consumes the role. These attributes and methods then appear as if they +were defined in the class itself. A subclass of the consuming class +will inherit all of these methods and attributes. + +Moose roles are similar to mixins or interfaces in other languages. + +Besides defining their own methods and attributes, roles can also +require that the consuming class define certain methods of its +own. You could have a role that consisted only of a list of required +methods, in which case the role would be very much like a Java +interface. + +Note that attribute accessors also count as methods for the +purposes of satisfying the requirements of a role. + +=head1 A SIMPLE ROLE + +Creating a role looks a lot like creating a Moose class: + + package Breakable; + + use Moose::Role; + + has 'is_broken' => ( + is => 'rw', + isa => 'Bool', + ); + + sub break { + my $self = shift; + + print "I broke\n"; + + $self->is_broken(1); + } + +Except for our use of L<Moose::Role>, this looks just like a class +definition with Moose. However, this is not a class, and it cannot be +instantiated. + +Instead, its attributes and methods will be composed into classes +which use the role: + + package Car; + + use Moose; + + with 'Breakable'; + + has 'engine' => ( + is => 'ro', + isa => 'Engine', + ); + +The C<with> function composes roles into a class. Once that is done, +the C<Car> class has an C<is_broken> attribute and a C<break> +method. The C<Car> class also C<does('Breakable')>: + + my $car = Car->new( engine => Engine->new ); + + print $car->is_broken ? 'Busted' : 'Still working'; + $car->break; + print $car->is_broken ? 'Busted' : 'Still working'; + + $car->does('Breakable'); # true + +This prints: + + Still working + I broke + Busted + +We could use this same role in a C<Bone> class: + + package Bone; + + use Moose; + + with 'Breakable'; + + has 'marrow' => ( + is => 'ro', + isa => 'Marrow', + ); + +See also L<Moose::Cookbook::Roles::Comparable_CodeReuse> for an example. + +It's possible to compose existing roles into new roles. For example, we can +have a C<HandleWithCare> class which applies both the C<Breakable> and +C<Package> roles to any class which consumes it: + + package HandleWithCare; + + use Moose::Role; + + with 'Breakable', 'Package'; + +=head1 REQUIRED METHODS + +As mentioned previously, a role can require that consuming classes +provide one or more methods. Using our C<Breakable> example, let's +make it require that consuming classes implement their own C<break> +methods: + + package Breakable; + + use Moose::Role; + + requires 'break'; + + has 'is_broken' => ( + is => 'rw', + isa => 'Bool', + ); + + after 'break' => sub { + my $self = shift; + + $self->is_broken(1); + }; + +If we try to consume this role in a class that does not have a +C<break> method, we will get an exception. + +You can see that we added a method modifier on C<break>. We want +classes that consume this role to implement their own logic for +breaking, but we make sure that the C<is_broken> attribute is always +set to true when C<break> is called. + + package Car + + use Moose; + + with 'Breakable'; + + has 'engine' => ( + is => 'ro', + isa => 'Engine', + ); + + sub break { + my $self = shift; + + if ( $self->is_moving ) { + $self->stop; + } + } + +=head2 Roles Versus Abstract Base Classes + +If you are familiar with the concept of abstract base classes in other +languages, you may be tempted to use roles in the same way. + +You I<can> define an "interface-only" role, one that contains I<just> +a list of required methods. + +However, any class which consumes this role must implement all of the +required methods, either directly or through inheritance from a +parent. You cannot delay the method requirement check so that they can +be implemented by future subclasses. + +Because the role defines the required methods directly, adding a base +class to the mix would not achieve anything. We recommend that you +simply consume the interface role in each class which implements that +interface. + +=head2 Required Attributes + +As mentioned before, a role's required method may also be satisfied by an +attribute accessor. However, the call to C<has> which defines an attribute +happens at runtime. This means that you must define the attribute I<before> +consuming the role, or else the role will not see the generated accessor. + + package Breakable; + + use Moose::Role; + + requires 'stress'; + + package Car; + + use Moose; + + has 'stress' => ( + is => 'rw', + isa => 'Int', + ); + + with 'Breakable'; + +=head1 USING METHOD MODIFIERS + +Method modifiers and roles are a very powerful combination. Often, a +role will combine method modifiers and required methods. We already +saw one example with our C<Breakable> example. + +Method modifiers increase the complexity of roles, because they make +the role application order relevant. If a class uses multiple roles, +each of which modify the same method, those modifiers will be applied +in the same order as the roles are used: + + package MovieCar; + + use Moose; + + extends 'Car'; + + with 'Breakable', 'ExplodesOnBreakage'; + +Assuming that the new C<ExplodesOnBreakage> role I<also> has an +C<after> modifier on C<break>, the C<after> modifiers will run one +after the other. The modifier from C<Breakable> will run first, then +the one from C<ExplodesOnBreakage>. + +=head1 METHOD CONFLICTS + +If a class composes multiple roles, and those roles have methods of +the same name, we will have a conflict. In that case, the composing +class is required to provide its I<own> method of the same name. + + package Breakdancer; + + use Moose::Role; + + sub break { + + } + +If we compose both C<Breakable> and C<Breakdancer> in a class, we must +provide our own C<break> method: + + package FragileDancer; + + use Moose; + + with 'Breakable', 'Breakdancer'; + + sub break { ... } + +A role can be a collection of other roles: + + package Break::Bundle; + + use Moose::Role; + + with ('Breakable', 'Breakdancer'); + +When a role consumes another a role, the I<consuming> role's methods silently +win in any conflict, and the consumed role's methods are simply ignored. + +=head1 METHOD EXCLUSION AND ALIASING + +If we want our C<FragileDancer> class to be able to call the methods +from both its roles, we can alias the methods: + + package FragileDancer; + + use Moose; + + with 'Breakable' => { -alias => { break => 'break_bone' } }, + 'Breakdancer' => { -alias => { break => 'break_dance' } }; + +However, aliasing a method simply makes a I<copy> of the method with +the new name. We also need to exclude the original name: + + with 'Breakable' => { + -alias => { break => 'break_bone' }, + -excludes => 'break', + }, + 'Breakdancer' => { + -alias => { break => 'break_dance' }, + -excludes => 'break', + }; + +The excludes parameter prevents the C<break> method from being composed +into the C<FragileDancer> class, so we don't have a conflict. This +means that C<FragileDancer> does not need to implement its own +C<break> method. + +This is useful, but it's worth noting that this breaks the contract +implicit in consuming a role. Our C<FragileDancer> class does both the +C<Breakable> and C<BreakDancer>, but does not provide a C<break> +method. If some API expects an object that does one of those roles, it +probably expects it to implement that method. + +In some use cases we might alias and exclude methods from roles, but +then provide a method of the same name in the class itself. + +Also see L<Moose::Cookbook::Roles::Restartable_AdvancedComposition> for an example. + +=head1 OVERLOADING + +When a Moose role uses overloading, that overloading is composed into any +classes that consume the role. This includes the setting of the C<fallback> +value for that role's overloading. Just as with methods and attributes, when a +role consumes another role, that other role's overloading settings are applied +to the role. + +Just as with methods, there can be conflicts with overloading implementations +between multiple roles when they are all consumed by a class. If two roles +both provide different overloading implementations for a given operator, that +is a conflict. If two roles both implement overloading and have different +C<fallback> values, that is also considered a conflict. These conflicts are +detected when multiple roles are being composed into a class together. + +When a role consumes another role, the consuming role's overloading fallback +and operator implementations silently "win" the conflict. + +=head1 ROLE EXCLUSION + +A role can say that it cannot be combined with some other role. This +should be used with great caution, since it limits the re-usability of +the role. + + package Breakable; + + use Moose::Role; + + excludes 'BreakDancer'; + +=head1 ADDING A ROLE TO AN OBJECT INSTANCE + +You may want to add a role to an object instance, rather than to a class. For +example, you may want to add debug tracing to one instance of an object while +debugging a particular bug. Another use case might be to dynamically change +objects based on a user's configuration, as a plugin system. + +The best way to do this is to use the C<apply_all_roles()> function from +L<Moose::Util>: + + use Moose::Util qw( apply_all_roles ); + + my $car = Car->new; + apply_all_roles( $car, 'Breakable' ); + +This function can apply more than one role at a time, and will do so using the +normal Moose role combination system. We recommend using this function to +apply roles to an object. This is what Moose uses internally when you call +C<with>. + +=head1 AUTHORS + +=over 4 + +=item * + +Stevan Little <stevan.little@iinteractive.com> + +=item * + +Dave Rolsky <autarch@urth.org> + +=item * + +Jesse Luehrs <doy@tozt.net> + +=item * + +Shawn M Moore <code@sartak.org> + +=item * + +יובל קוג'מן (Yuval Kogman) <nothingmuch@woobling.org> + +=item * + +Karen Etheridge <ether@cpan.org> + +=item * + +Florian Ragwitz <rafl@debian.org> + +=item * + +Hans Dieter Pearcey <hdp@weftsoar.net> + +=item * + +Chris Prather <chris@prather.org> + +=item * + +Matt S Trout <mst@shadowcat.co.uk> + +=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 |