X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=blobdiff_plain;f=lib%2FMoose%2FCookbook%2FMeta%2FRecipe3.pod;h=22ab7b636b6bc9609bb635c86fbf1b6445ae3cf5;hb=fe66eda17ca7486c6e84ba5d669dca7f559256f3;hp=985ce5f1b77549a1fd09dda3907f098c93263078;hpb=546a18e9816515d23c9e5350dfe2b83fc6036f5b;p=gitmo%2FMoose.git diff --git a/lib/Moose/Cookbook/Meta/Recipe3.pod b/lib/Moose/Cookbook/Meta/Recipe3.pod index 985ce5f..22ab7b6 100644 --- a/lib/Moose/Cookbook/Meta/Recipe3.pod +++ b/lib/Moose/Cookbook/Meta/Recipe3.pod @@ -65,26 +65,43 @@ __END__ my $app = MyApp::Website->new( url => "http://google.com", name => "Google" ); -=head1 BUT FIRST +=head1 SUMMARY -This recipe is a variation on -L. Please read that recipe first. +In this recipe, we begin to delve into the wonder of meta-programming. +Some readers may scoff and claim that this is the arena of only the +most twisted Moose developers. Absolutely not! Any sufficiently +twisted developer can benefit greatly from going more meta. -=head1 MOTIVATION +Our goal is to allow each attribute to have a human-readable "label" +attached to it. Such labels would be used when showing data to an end +user. In this recipe we label the C attribute with "The site's +URL" and create a simple method showing how to use that label. -In L, we created an attribute -metaclass which lets you provide a label for attributes. +=head1 META-ATTRIBUTE OBJECTS -Using a metaclass 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. +All the attributes of a Moose-based object are actually objects themselves. +These objects have methods and attributes. Let's look at a concrete example. -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. + has 'x' => ( isa => 'Int', is => 'ro' ); + has 'y' => ( isa => 'Int', is => 'rw' ); + +Internally, the metaclass for C has two L +objects. There are several methods for getting meta-attributes out of a +metaclass, one of which is C. This method is called on the +metaclass object. + +The C method returns a list of attribute names. You can +then use C to get the L object itself. + +Once you have this meta-attribute object, you can call methods on it like +this: + + print $point->meta->get_attribute('x')->type_constraint; + => Int + +To add a label to our attributes there are two steps. First, we need a new +attribute metaclass trait that can store a label for an attribute. Second, we +need to apply that trait to our attributes. =head1 TRAITS @@ -106,9 +123,7 @@ metaclass instead of a user-level class. =head1 DISSECTION -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. +We start by creating a package for our trait. package MyApp::Meta::Attribute::Trait::Labeled; use Moose::Role; @@ -119,9 +134,11 @@ metaclass. predicate => 'has_label', ); -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. +You can see that a trait is just a L. In this case, our role +contains a single attribute, C