2009-07-07 4 views
21

J'ai écrit un ensemble de classes et d'interfaces implémentées en Moose utilisant également des rôles. Ce que j'ai de la difficulté à comprendre, ce sont les différences exactes à la fois dans l'utilisation et la mise en œuvre des traits de Moose par rapport aux rôles.En quoi les rôles et les traits diffèrent-ils chez les orignaux?

Les Moose documentation états:

Il est important de comprendre que les rôles et les traits sont la même chose. Un rôle peut être utilisé comme un trait, et un trait est un rôle. La seule chose qui distingue les deux est qu'un trait est emballé d'une manière qui permet à Moose de résoudre un nom court en un nom de classe. En d'autres termes, avec un trait, l'appelant peut se référer à lui par un nom court comme "Big", et Moose le résoudra en une classe comme MooseX :: Embiggen :: Meta :: Attribute :: Rôle :: Big.

Je crois comprendre que les traits et les rôles sont «identiques». Cependant, lors de la mise en œuvre d'un test de base de l'idée en utilisant la syntaxe use Moose -traits 'Foo' ne semble pas faire ce que je m'attendais. Je dois sûrement manquer quelque chose ici.

Ce premier exemple échoue avec « Impossible de localiser la méthode « foo » »

package MyApp::Meta::Class::Trait::HasTable; 
use Moose::Role; 
sub foo { warn 'foo' } 

package Moose::Meta::Class::Custom::Trait::HasTable; 
sub register_implementation { 'MyApp::Meta::Class::Trait::HasTable' } 

package MyApp::User; 
use Moose -traits => 'HasTable'; 
__PACKAGE__->foo(); #Can't locate object method 'foo' 

Par rapport à celui-ci (qui fonctionne):

package MyApp::Meta::Class::Trait::HasTable; 
use Moose::Role; 
sub foo { warn 'foo' } 

package Moose::Meta::Class::Custom::Trait::HasTable; 
sub register_implementation { 'MyApp::Meta::Class::Trait::HasTable' } 

package MyApp::User; 
use Moose; 
with 'MyApp::Meta::Class::Trait::HasTable'; 
__PACKAGE__->foo(); #foo 

Répondre

12

C'est la seule différence dans la façon dont Moose utilise les termes "Trait" et "Role". La documentation et les API de Moose utilisent souvent le terme «traits» comme «Rôles appliqués aux métaclasses». Dans votre réponse révisée, votre premier exemple applique la métaclasse MyApp::User via le -traits, le deuxième exemple l'applique à la classe .

Si vous changez votre premier exemple à:

package MyApp::Meta::Class::Trait::HasTable; 
use Moose::Role; 
sub foo { warn 'foo' } 

package Moose::Meta::Class::Custom::Trait::HasTable; 
sub register_implementation { 'MyApp::Meta::Class::Trait::HasTable' } 

package MyApp::User; 
use Moose -traits => 'HasTable'; 
__PACKAGE__->meta->foo(); 

Vous verrez « foo at [script]. line 3. » Ce qui est exactement ce qu'il devait faire.

MISE À JOUR: Apparemment, je ne suis pas exactement correct ici. Les traits sont des rôles appliqués aux instances. Le hook -traits applique HasTable à l'instance de métaclasse pour MyApp :: User. J'ai mis à jour les documents Moose pertinents.

+0

Merci, cela explique le comportement que je voyais. – Danny

+1

J'ai mis à jour le texte dans Extending/Recipe1.pod pour essayer de refléter un peu cette différence. Notez également que pour confondre les choses, les choses ressemblant à des rôles sont appelées Traits dans d'autres langues comme Scala. Ces traits sont définis dans certains documents qui ont éclairé l'origine de la mise en œuvre du rôle de Moose, mais manquent des caractéristiques de l'état (c.-à-d. Ce sont des méthodes seulement et n'ont pas d'attributs). – perigrin

0

Vous ne définissez pas paquet 'x :: Foo' avec n'importe quel rôle. droit Ripped du documentation, nous voyons que register_implementation renvoie le nom d'un package réellement défini:

package MyApp::Meta::Class::Trait::HasTable; 
use Moose::Role; 

has table => (
    is => 'rw', 
    isa => 'Str', 
); 

package Moose::Meta::Class::Custom::Trait::HasTable; 
sub register_implementation { 'MyApp::Meta::Class::Trait::HasTable' } 

package MyApp::User; 
use Moose -traits => 'HasTable'; 

__PACKAGE__->meta->table('User'); 

Le « raccourci » est atteint par Moose recherche "Moose::Meta::Class::Trait::$trait_name" (lorsqu'il est appelé dans un « contexte de classe »), non seulement repasser un nom plus court.

+0

S'il vous plaît voir ma révision à ma question, j'ai essayé d'ajouter plus de détails. – Danny

Questions connexes