Describe how easy to is to create a (or reproduce an existing) metaclass using a...
Shawn M Moore [Sat, 24 May 2008 19:49:17 +0000 (19:49 +0000)]
lib/Moose/Cookbook/Recipe22.pod
t/000_recipes/022_attribute_trait.t

index 1087cc2..a0868a6 100644 (file)
@@ -159,6 +159,27 @@ C<< $attribute->has_label >>.
 
 That's all. Everything else is the same!
 
+=head1 METACLASS + TRAIT
+
+"But wait!" you protest. "I've already written all of my extensions as
+attribute metaclasses. I don't want to break all that code out there."
+
+All is not lost. If you rewrite your extension as a trait, then you can
+easily get a regular metaclass extension out of it. You just compose the trait
+in the attribute metaclass, as normal.
+
+    package MyApp::Meta::Attribute::Labeled;
+    use Moose;
+    extends 'Moose::Meta::Attribute';
+    with 'MyApp::Meta::Attribute::Trait::Labeled';
+
+    package Moose::Meta::Attribute::Custom::Labeled;
+    sub register_implementation { 'MyApp::Meta::Attribute::Labeled' }
+
+Unfortunately, going the other way (providing a trait created from a metaclass)
+is more tricky. Thus, defining your extensions as traits is just plain better
+than defining them as subclassed metaclasses.
+
 =head1 CONCLUSION
 
 If you're extending your attributes, it's easier and more flexible to provide
index 5986ca0..223fb65 100644 (file)
@@ -3,7 +3,7 @@
 use strict;
 use warnings;
 
-use Test::More tests => 2;
+use Test::More tests => 3;
 use Test::Exception;
 
 BEGIN {
@@ -76,5 +76,64 @@ is($app->dump, q{name: Google
 The site's URL: http://google.com
 }, '... got the expected dump value');
 
+# using the trait directly in a regular metaclass
+{
+    package MyApp::Meta::Attribute::Labeled;
+    use Moose;
+    extends 'Moose::Meta::Attribute';
+    with 'MyApp::Meta::Attribute::Trait::Labeled';
+
+    package Moose::Meta::Attribute::Custom::Labeled;
+    sub register_implementation { 'MyApp::Meta::Attribute::Labeled' }
+
+    package MyApp::Website2;
+    use Moose;
+
+    has url => (
+        metaclass => 'Labeled',
+        isa       => 'Str',
+        is        => 'rw',
+        label     => "The site's URL",
+    );
+
+    has name => (
+        is  => 'rw',
+        isa => 'Str',
+    );
+
+    sub dump {
+        my $self = shift;
 
+        my $dump_value = '';
+        
+        # iterate over all the attributes in $self
+        my %attributes = %{ $self->meta->get_attribute_map };
+        foreach my $name (sort keys %attributes) {
+    
+            my $attribute = $attributes{$name};
+            
+            # print the label if available
+            if ($attribute->isa('MyApp::Meta::Attribute::Labeled')
+                && $attribute->has_label) {
+                    $dump_value .= $attribute->label;
+            }
+            # otherwise print the name
+            else {
+                $dump_value .= $name;
+            }
+
+            # print the attribute's value
+            my $reader = $attribute->get_read_method;
+            $dump_value .= ": " . $self->$reader . "\n";
+        }
+        
+        return $dump_value;
+    }
+
+}
+
+my $app2 = MyApp::Website2->new(url => "http://google.com", name => "Google");
+is($app2->dump, q{name: Google
+The site's URL: http://google.com
+}, '... got the expected dump value');