2017-07-24 6 views
4

En tant que mentioned earlier today, j'essaie de définir des attributs sur une instance lorsque l'une de ses méthodes est appelée. Je veux aussi rendre cet attribut privé. Comme cela m'a été signalé, je ne peux pas définir cet attribut sur ro car cela interdit également l'accès en lecture à l'intérieur de la classe. Par conséquent, je l'ai maintenant mis à rw mais j'ai commencé à utiliser le module MooseX::Privacy. Ma déclaration d'attribut ressemble donc à ceci:Utilisation de Moose avant d'altérer les arguments de la méthode en conflit avec la confidentialité

has 'grow_params' => (
    is => 'rw', 
    isa => 'HashRef', 
    traits => [qw/Private/], 
); 

Cela fonctionne bien si je fais simplement quelque chose comme ceci:

sub grow { 
    my ($self, $params) = @_; 
    $self->grow_params($params); 
} 

Cependant, je veux faire quelques vérifications de paramètres. De la lecture de la documentation, il semble que le meilleur endroit pour le faire est before. Quand j'essaye ceci, cependant, je rencontre des problèmes.

Par exemple, avec before:

before 'grow_params' => sub { 
    my ($self, $params) = @_; 
    # Setting default value 
    $params->{'overripe'} = exists $params->{'overripe'} ? $params->{'overripe'} : 0; 
    # Making sure its boolean 
    confess "Argument 'overripe' has to be 0 or 1" 
    unless ($params->{'overripe'} == 0 || $params->{'overripe'} == 1); 
}; 

Cela conduit à l'erreur suivante:

Attribute grow_params is private at C:/strawberry/perl/site/lib/MooseX/Privacy/Meta/Attribute/Private.pm line 13. 

(j'ai aussi essayé de placer l'attribut à Protected, deviner que peut-être une sous-classe a été créée, mais en vain.) L'attribut est en effet privé, mais j'essaie de le modifier à partir de la classe cependant, non? La trace ressemble à ceci, donc je suppose que le paramètre actuel est essayé par Banana, ou est-ce que je manque quelque chose?

Attribute grow_params is private at c:/strawberry/perl/site/lib/MooseX/Privacy/Meta/Attribute/Private.pm line 13. 
     MooseX::Privacy::Meta::Attribute::Private::_check_private(Moose::Meta::Class::__ANON__::SERIAL::9=HASH(0x3fd4a00), "Class::MOP::Method::Wrapped", "grow_params", "Banana", "Banana") called at c:/strawberry/perl/site/lib/MooseX/Privacy/Meta/Attribute/Privacy.pm line 31 
     Banana::grow_params(Banana=HASH(0x25223e8), HASH(0xed97a8)) called at c:/strawberry/perl/site/lib/Class/MOP/Method/Wrapped.pm line 44 
     Banana::_wrapped_grow_params(Banana=HASH(0x25223e8), HASH(0xed97a8)) called at c:/strawberry/perl/site/lib/Class/MOP/Method/Wrapped.pm line 95 
     Banana::grow_params(Banana=HASH(0x25223e8), HASH(0xed97a8)) called at C:\xampp\htdocs\grinding\banana\/Banana.pm line 31 
     Banana::grow(Banana=HASH(0x25223e8), HASH(0xed97a8)) called at run.pl line 16 

Le code complet pour vous lancer.

# Banana.pm 
package Banana; 

use strict; 
use warnings; 
use Carp qw(confess); 

use Moose; 
use MooseX::Privacy; 

has ['peel', 'edible'] => (
    is => 'ro', 
    isa => 'Bool', 
    required => 1, 
); 

has 'color' => (
    is => 'ro', 
    isa => 'Str', 
    required => 1, 
); 

has 'grow_params' => (
    is => 'rw', 
    isa => 'HashRef', 
    traits => [qw/Private/], 
); 

sub grow { 
    my ($self, $params) = @_; 
    $self->grow_params($params); 
} 

before 'grow_params' => sub { 
    my ($self, $params) = @_; 
    # Setting default value 
    $params->{'overripe'} = exists $params->{'overripe'} ? $params->{'overripe'} : 0; 
    # Making sure its boolean 
    confess "Argument 'overripe' has to be 0 or 1" 
    unless ($params->{'overripe'} == 0 || $params->{'overripe'} == 1); 
}; 

1; 

# run.pl 
use strict; 
use warnings; 

use File::Basename qw(fileparse dirname); 
use Cwd qw(abs_path); 

# Add current directory to @INC 
use lib (fileparse(abs_path($0)))[1]; 

use Banana; 

my $chiquita = Banana->new({ 
    peel => 1, 
    edible => 0, 
    color => 'green' 
}); 

$chiquita->grow({ 
    size => 'medium', 
    color => 'yellow' 
}); 

Répondre

3

Si nous regardons dans la mise en œuvre de MooseX::Privacy, plus spécifiquement dans MooseX::Privacy::Meta::Attribute::Private v0.05, nous pouvons voir ce qui se passe.

sub _check_private { 
    my ($meta, $caller, $attr_name, $package_name) = @_; 
    confess "Attribute " . $attr_name . " is private" 
     unless $caller eq $package_name; 
} 

Ainsi, le problème doit être que $caller n'est pas égal à $package_name. Ce qui est un moyen d'exprimer la notion de confidentialité en termes de Perl, je suppose.

Qui est l'appelant d'une méthode before? J'ai légèrement changé le code pour imprimer $caller avant la vérification. Voici le coupable:

Class::MOP::Method::Wrapped

qui a à voir avec la façon dont les modificateurs de la méthode mise en œuvre (comme son nom l'indique).

La façon dont je le vois, vos attentes sont raisonnables et cela est un défaut MooseX::Privacy et la façon dont il oeuvre dans le fonctionnement interne de l'écosystème MOP.

+0

Bonne trouvaille, merci! J'ai envoyé un rapport de bug à cpan, mais voyant que le dernier bug (il y a 11 mois) n'a pas été répondu, je ne garde pas beaucoup d'espoir. –