From: Dave Rolsky Date: Tue, 29 Jul 2008 15:51:18 +0000 (+0000) Subject: Add code to handle registered metaclass traits. X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=commitdiff_plain;h=d47dbfa961ddb060260441bbda2f0d39201e4ac3;p=gitmo%2FMoose.git Add code to handle registered metaclass traits. Add metaclass trait docs. --- diff --git a/lib/Moose.pm b/lib/Moose.pm index 3d6fd32..cd0a460 100644 --- a/lib/Moose.pm +++ b/lib/Moose.pm @@ -222,7 +222,19 @@ use Moose::Util (); my $meta = $class->meta(); - Moose::Util::apply_all_roles_with_method($meta, 'apply_to_metaclass_instance', $traits); + # We can only call does_role() on Moose::Meta::Class objects, + # and we can only do that on $meta->meta() if it has already + # had at least one trait applied to it. By default + # $meta->meta() returns a Class::MOP::Class object (not a + # Moose::Meta::Class). + my @traits + = grep { $meta->meta()->can('does_role') ? not $meta->meta()->does_role($_) : 1 } + map { Moose::Util::resolve_metatrait_alias( Class => $_ ) } + @$traits; + + return unless @traits; + + Moose::Util::apply_all_roles_with_method($meta, 'apply_to_metaclass_instance', \@traits); } sub import { @@ -809,6 +821,40 @@ to work. Here is an example: no Moose; # keywords are removed from the Person package +=head1 METACLASS TRAITS + +When you import Moose, you can also specify a list of traits to be +applied to the class's metaclass object with the C<-traits> flag: + + package Person; + use Moose -traits => [ 'My::Trait::Debug' ]; + +These traits will be applied to your class's metaclass instance. For +example, in this case, when you call C<< Person->meta() >>, you will +get back an object of the C class which I +does the C role. + +=head2 Registering Traits + +You can refer to traits by short names as long as you register them in +advance. To register a trait, you must create a package of the form +C<< Moose::Meta::Class::Custom::Trait:: >>, where +"TraitName" is the short name of your trait. This package should +contain a single subroutine, C, which +returns the package name which actually implements the traits. + +For example, for a trait named C, we could do the +following: + + package My::Trait::Debug; + use Moose::Role; + + sub debug { ... } + + package Moose;:Meta::Class::Custom::Trait::Debug; + + sub register_implementation { 'My::Trait::Debug' } + =head1 EXTENDING AND EMBEDDING MOOSE Moose also offers some options for extending or embedding it into your own diff --git a/t/050_metaclasses/012_metaclass_traits.t b/t/050_metaclasses/012_metaclass_traits.t index 44fdb18..48fcaf5 100644 --- a/t/050_metaclasses/012_metaclass_traits.t +++ b/t/050_metaclasses/012_metaclass_traits.t @@ -28,8 +28,8 @@ is( Foo->meta()->simple(), 5, use Moose::Role; - # This needs to happen at begin time so it happens before we apply - # traits to Bar + # This needs to happen at compile time so it happens before we + # apply traits to Bar BEGIN { has 'attr' => ( is => 'ro', @@ -58,8 +58,6 @@ is( Bar->meta()->attr(), 'something', use Moose::Role; - # This needs to happen at begin time so it happens before we apply - # traits to Bar BEGIN { has 'attr2' => ( is => 'ro', @@ -120,3 +118,26 @@ ok( Quux->meta()->has_attribute('size'), 'Quux has size attribute' ); ok( ! Quux->meta()->get_attribute('size')->writer(), 'size attribute does not have a writer' ); + +{ + package My::Class::Whatever; + + use Moose::Role; + + sub whatever { 42 } + + package Moose::Meta::Class::Custom::Trait::Whatever; + + sub register_implementation { + return 'My::Class::Whatever'; + } +} + +{ + package RanOutOfNames; + + use Moose -traits => [ 'Whatever' ]; +} + +ok( RanOutOfNames->meta()->meta()->has_method('whatever'), + 'RanOutOfNames->meta() has whatever method' );