From: Shawn M Moore Date: Sat, 24 May 2008 19:49:17 +0000 (+0000) Subject: Describe how easy to is to create a (or reproduce an existing) metaclass using a... X-Git-Tag: 0_55~143 X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=commitdiff_plain;h=d9a8643f96b5e0e86d29da44b0169c71f0373a91;p=gitmo%2FMoose.git Describe how easy to is to create a (or reproduce an existing) metaclass using a trait, but that it's not easy the other way around. traits++ --- diff --git a/lib/Moose/Cookbook/Recipe22.pod b/lib/Moose/Cookbook/Recipe22.pod index 1087cc2..a0868a6 100644 --- a/lib/Moose/Cookbook/Recipe22.pod +++ b/lib/Moose/Cookbook/Recipe22.pod @@ -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 diff --git a/t/000_recipes/022_attribute_trait.t b/t/000_recipes/022_attribute_trait.t index 5986ca0..223fb65 100644 --- a/t/000_recipes/022_attribute_trait.t +++ b/t/000_recipes/022_attribute_trait.t @@ -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');