X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=blobdiff_plain;f=lib%2FMoose%2FManual%2FRoles.pod;h=594fac44d0dea8ff7aa4a702d6e5adabef99b136;hb=37ffa2615b5f485473b2e4dfab344e2fca470cfa;hp=374b3ae5460df5a82b451fef2885563abe81610d;hpb=9438350fb7ba28421857a41c6372f7a8fbd92c12;p=gitmo%2FMoose.git diff --git a/lib/Moose/Manual/Roles.pod b/lib/Moose/Manual/Roles.pod index 374b3ae..594fac4 100644 --- a/lib/Moose/Manual/Roles.pod +++ b/lib/Moose/Manual/Roles.pod @@ -1,21 +1,25 @@ -=pod +package Moose::Manual::Roles; + +# ABSTRACT: Roles, an alternative to deep hierarchies and base classes -=head1 NAME +__END__ -Moose::Manual::Roles - Roles, an Alternative to Deep Hierarchies and Base Classes +=pod =head1 WHAT IS A ROLE? -A role is something that classes do. Usually, a role encapsulates some -piece of behavior or state that can be shared between classes. It is -important to understand that I. Roles do not -participate in inheritance, and a role cannot be instantiated. +A role encapsulates some piece of behavior or state that can be shared between +classes. It is something that classes I. It is important to understand that +I. You cannot inherit from a role, and a role cannot be +instantiated. We sometimes say that roles are I, either by classes +or other roles. Instead, a role is I into a class. In practical terms, this -means that all of the methods 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 show up in the -class as if they were defined directly in the class. +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. @@ -25,6 +29,9 @@ 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: @@ -46,7 +53,7 @@ Creating a role looks a lot like creating a Moose class: $self->is_broken(1); } -Except for our use of C, this looks just like a class +Except for our use of L, this looks just like a class definition with Moose. However, this is not a class, and it cannot be instantiated. @@ -70,9 +77,9 @@ method. The C class also C: my $car = Car->new( engine => Engine->new ); - print $car->is_broken ? 'Still working' : 'Busted'; + print $car->is_broken ? 'Busted' : 'Still working'; $car->break; - print $car->is_broken ? 'Still working' : 'Busted'; + print $car->is_broken ? 'Busted' : 'Still working'; $car->does('Breakable'); # true @@ -95,6 +102,8 @@ We could use this same role in a C class: isa => 'Marrow', ); +See also L for an example. + =head1 REQUIRED METHODS As mentioned previously, a role can require that consuming classes @@ -122,18 +131,14 @@ methods: If we try to consume this role in a class that does not have a C method, we will get an exception. -Note that attribute-generated accessors do not satisfy the requirement -that the named method exists. Similarly, a method modifier does not -satisfy this requirement either. This may change in the future. - -You can also see that we added a method modifier on -C. Basically, we want consuming classes to implement their own -logic for breaking, but we make sure that the C attribute -is always set to true when C is called. +You can see that we added a method modifier on C. We want +classes that consume this role to implement their own logic for +breaking, but we make sure that the C attribute is always +set to true when C is called. package Car - use Moose; + use Moose; with 'Breakable'; @@ -150,6 +155,48 @@ is always set to true when C is called. } } +=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 define an "interface-only" role, one that contains I +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 which defines an attribute +happens at runtime. This means that you must define the attribute I +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 @@ -180,7 +227,7 @@ 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 method of the same name. - package Breakdances; + package Breakdancer; use Moose::Role @@ -199,6 +246,14 @@ provide our own C method: sub break { ... } +A role can be a collection of other roles: + + package Break::Bundle; + + use Moose::Role; + + with ('Breakable', 'Breakdancer'); + =head1 METHOD EXCLUSION AND ALIASING If we want our C class to be able to call the methods @@ -208,22 +263,22 @@ from both its roles, we can alias the methods: use Moose; - with 'Breakable' => { alias => { break => 'break_bone' } }, - 'Breakdancer' => { alias => { break => 'break_dance' } }; + with 'Breakable' => { -alias => { break => 'break_bone' } }, + 'Breakdancer' => { -alias => { break => 'break_dance' } }; However, aliasing a method simply makes a I of the method with the new name. We also need to exclude the original name: with 'Breakable' => { - alias => { break => 'break_bone' }, - exclude => 'break', + -alias => { break => 'break_bone' }, + -excludes => 'break', }, 'Breakdancer' => { - alias => { break => 'break_dance' }, - exclude => 'break', + -alias => { break => 'break_dance' }, + -excludes => 'break', }; -The exclude parameter prevents the C method from being composed +The excludes parameter prevents the C method from being composed into the C class, so we don't have a conflict. This means that C does not need to implement its own C method. @@ -234,17 +289,41 @@ C and C, but does not provide a C method. If some API expects an object that does one of those roles, it probably expects it to implement that method. -=head1 AUTHOR +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 for an example. + +=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 -Dave Rolsky Eautarch@urth.orgE +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. -=head1 COPYRIGHT AND LICENSE +The best way to do this is to use the C function from +L: -Copyright 2008 by Infinity Interactive, Inc. + use Moose::Util qw( apply_all_roles ); -L + my $car = Car->new; + apply_all_roles( $car, 'Breakable' ); -This library is free software; you can redistribute it and/or modify -it under the same terms as Perl itself. +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. =cut