2009-09-12 4 views
18

Si vous avez un attribut qui a besoin d'être modifié à chaque fois qu'il est défini, y a-t-il une façon simple d'écrire l'accesseur et de contourner directement le contenu de $self, comme dans cet exemple?Dans Moose, comment modifier un attribut à chaque fois qu'il est défini?

package Foo; 
use Moose; 

has 'bar' => (
    isa => 'Str', 
    reader => 'get_bar', 
); 

sub set_bar { 
    my ($self, $bar) = @_; 
    $self->{bar} = "modified: $bar"; 
} 

Je considère trigger, mais il semblait exiger la même approche.

Travailler directement avec la référence de hachage dans $self considéré comme une mauvaise pratique dans Moose, ou est-ce que je m'inquiète d'un non-problème?

Répondre

8

Je ne sais pas quel genre de modification dont vous avez besoin, mais vous pourriez être en mesure de réaliser ce que vous avez besoin de en utilisant la coercition de type:

package Foo; 
use Moose; 

use Moose::Util::TypeConstraints; 

subtype 'ModStr' 
    => as 'Str' 
    => where { /^modified: /}; 

coerce 'ModStr' 
    => from 'Str' 
    => via { "modified: $_" }; 

has 'bar' => ( 
    isa => 'ModStr', 
    is => 'rw', 
    coerce => 1, 
); 

Si vous utilisez cette approche, toutes les valeurs ne seront pas modifiées. Tout ce qui passe la validation en tant que ModStr sera utilisé directement:

my $f = Foo->new(); 
$f->bar('modified: bar'); # Set without modification 

Cette faiblesse pourrait être OK ou il pourrait rendre cette approche inutilisable. Dans les bonnes circonstances, cela pourrait même être un avantage.

6

Je pense en utilisant la référence de hachage est très bien dans un trigger comme celui-ci:

package Foo; 
use Moose; 

has 'bar' => ( 
    isa => 'Str', 
    is => 'rw', 
    trigger => sub { $_[0]->{bar} = "modified: $_[1]" }, 
); 

Le déclencheur déclenche également lorsque bar arg passé avec le constructeur. Cela ne se produira pas si vous définissez votre propre méthode set_bar ou avec un modificateur de méthode. Re: référence de hachage - En général, je pense qu'il vaut mieux s'en tenir aux setters/getters d'attribut sauf si (comme avec le trigger ci-dessus) il n'y a pas d'alternative facile.

BTW vous pouvez trouver ce recent post about triggers par nothingmuch intéressant.

+0

Découvrez les attributs Moose :: Manual :: sur les triggers - http://search.cpan.org/~drolsky/Moose-0.88/lib/Moose/Manual/Attributes.pod#Triggers –

3

Si vous êtes directement concerné par le hachage, vous pouvez spécifier un autre éditeur, puis l'utiliser dans votre propre éditeur public.

package Foo; 
use Moose; 

has 'bar' => (
    isa => 'Str', 
    reader => 'get_bar', 
    writer => '_set_bar', 
); 

sub set_bar { 
    my $self = shift; 
    my @args = @_; 
    # play with args; 
    return $self->_set_bar(@args); 
} 

Ce, ou les déclencheurs, me frapper comme une bonne approche en fonction du moment et de la façon dont vous devez être manipuler les arguments.

(disclaimer: code non testé écrit de la mémoire, la navigation SO sur un netbook avec un accès bord squameuse)

+0

Ceci est un bon nettoyage solution bien que cela ne fonctionnera pas avec les constructeurs. – mikegrb

+0

@mikegrb: Je ne sais pas exactement ce que vous voulez faire des constructeurs, mais vous pouvez spécifier où une valeur est assignée via un constructeur en utilisant le modificateur d'attribut 'init_arg', et/ou vous pouvez faire des vérifications dans' BUILDARGS 'méthode. – Ether

9

Vous pouvez utiliser le modificateur de méthode 'around'. Quelque chose comme ceci:

has 'bar' => (
    isa => 'Str', 
    reader => 'get_bar', 
    writer => 'set_bar' 
); 

around 'set_bar' => sub { 
    my ($next, $self, $bar) = @_; 
    $self->$next("Modified: $bar"); 
}; 

Et oui, travailler directement avec les valeurs de hachage est considéré comme une mauvaise pratique.

Aussi, ne supposez pas que l'option que j'ai présentée est nécessairement la bonne. Utiliser les sous-types et la coercition sera la bonne solution la plupart du temps - si vous pensez à votre paramètre en termes de type qui peut être réutilisé dans votre application, cela conduira à une conception bien meilleure que le type de modifications arbitraires qui peuvent être fait en utilisant 'autour'. Voir la réponse de @daotoad.

+1

Pour que cela fonctionne, vous devez déclarer un écrivain lors de la définition de l'attribut. Par exemple, a 'bar' => (est => 'rw', isa => 'Str', écrivain => 'set_bar') – draegtun

+0

re: valeurs de hachage "mauvaise pratique": Son amende dans les déclencheurs et les exemples que j'ai vu (sur la liste de diffusion Moose) ne le réaffirmer. – draegtun

+0

draegtun: à moins que Moose ne l'ait modifié, l'auteur par défaut est le nom de l'attribut. Vous pouvez faire le tour si vous ne voulez pas spécifier l'auteur. –

Questions connexes