From: Dave Rolsky Date: Thu, 12 Feb 2009 15:58:13 +0000 (+0000) Subject: Revised recipe 3 X-Git-Tag: 0.69~17 X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=commitdiff_plain;h=4515e88e3ba10050b9f48d53ed625949807a3ed6;p=gitmo%2FMoose.git Revised recipe 3 --- diff --git a/lib/Moose/Cookbook/Meta/Recipe3.pod b/lib/Moose/Cookbook/Meta/Recipe3.pod index 9f2645b..bf3bc74 100644 --- a/lib/Moose/Cookbook/Meta/Recipe3.pod +++ b/lib/Moose/Cookbook/Meta/Recipe3.pod @@ -65,51 +65,48 @@ Moose::Cookbook::Meta::Recipe3 - Labels implemented via attribute traits =head1 BUT FIRST -This recipe is a continuation of +This recipe is a variation on L. Please read that recipe first. =head1 MOTIVATION In L, we created an attribute -metaclass that gives attributes a "label" that can be set in -L. That works well until you want a second meta-attribute, -or until you want to adjust the behavior of the attribute. You could -define a specialized attribute metaclass to use in every attribute. -However, you may want different attributes to have different -behaviors. You might end up with a unique attribute metaclass for -B, with a lot of code copying and pasting! - -Or, if you've been drinking deeply of the Moose kool-aid, you'll have a role -for each of the behaviors. One role would give a label meta-attribute. Another -role would signify that this attribute is not directly modifiable via the -REST interface. Another role would write to a logfile when this attribute -was read. - -Unfortunately, you'd still be left with a bunch of attribute metaclasses that -do nothing but compose a bunch of roles. If only there were some way to specify -in L a list of roles to apply to the attribute metaclass... +metaclass which lets you provide a label for attributes. + +Using a metaclss works fine until you realize you want to add a label +I an expiration, or some other combination of new behaviors. You +could create yet another metaclass which subclasses those two, but +that makes a mess, especially if you want to mix and match behaviors +across many attributes. + +Fortunately, Moose provides a much saner alternative, which is to +encapsulate each extension as a role, not a class. We can make a role +which adds a label to an attribute, and could make another to +implement expiration. =head1 TRAITS -Roles that apply to metaclasses have a special name: traits. Don't let the -change in nomenclature fool you, B. +Roles that apply to metaclasses have a special name: traits. Don't let +the change in nomenclature fool you, B. -L provides a C option. It takes a list of trait names to -compose into an anonymous metaclass. That means you do still have a bunch of -attribute metaclasses that do nothing but compose a bunch of roles, but they're -managed automatically by Moose. You don't need to declare them in advance, or -worry whether changing one will affect some other attribute. +L allows you to pass a C parameter for an +attribute. This parameter takes a list of trait names which are +composed into an anonymous metaclass, and that anonymous metaclass is +used for the attribute. -What can traits do? Anything roles can do. They can add or refine attributes, -wrap methods, provide more methods, define an interface, etc. The only -difference is that you're now changing the attribute metaclass instead of a -user-level class. +Yes, we still have lots of metaclasses in the background, but they're +managed by Moose for you. + +Traits can do anything roles can do. They can add or refine +attributes, wrap methods, provide more methods, define an interface, +etc. The only difference is that you're now changing the attribute +metaclass instead of a user-level class. =head1 DISSECTION -A side-by-side look of the code examples in this recipe and recipe 2 should -indicate that defining and using a trait is very similar to defining and using -a new attribute metaclass. +A side-by-side look of the code examples in this recipe and recipe 2 +show that defining and using a trait is very similar to a full-blown +metaclass. package MyApp::Meta::Attribute::Trait::Labeled; use Moose::Role; @@ -120,21 +117,19 @@ a new attribute metaclass. predicate => 'has_label', ); -Instead of subclassing L, we define a role. Traits -don't need any special methods or attributes. You just focus on whatever it is -you actually need to get done. Here we're adding a new meta-attribute for use -in our application. +Instead of subclassing L, we define a role. As +with our metaclass in L, +registering our role allows us to refer to it by a short name. package Moose::Meta::Attribute::Custom::Trait::Labeled; sub register_implementation { 'MyApp::Meta::Attribute::Trait::Labeled' } -Much like when we define a new attribute metaclass, we can provide a shorthand -name for the trait. Moose looks at the C method in +Moose looks for the C method in C to find the full name of the trait. -Now we begin writing our application logic. I'll only cover what has changed -since recipe 2. +For the rest of the code, we will only cover what is I from +L. has url => ( traits => [qw/Labeled/], @@ -143,9 +138,11 @@ since recipe 2. label => "The site's URL", ); -L provides a C option. Just pass the list of trait names and -it will compose them together to form the (anonymous) attribute metaclass used -by the attribute. We provide a label for the attribute in the same way. +Instead of passing a C parameter, this time we pass +C. This contains a list of trait names. Moose will build an +anonymous attribute metaclass from these traits and use it for this +attribute. Passing a C