有没有办法知道Moose中的触发器调用者属性?
例如,以Moose :: Manual :: Attributes:
为例has 'size' => (
is => 'rw',
trigger => \&_size_set,
);
sub _size_set {
my ( $self, $size, $old_size ) = @_;
my $msg = $self->name;
if ( @_ > 2 ) {
$msg .= " - old size was $old_size";
}
$msg .= " - size is now $size";
warn $msg;
}
_set_size 是否可以知道 size 属性调用它,而无需明确指定调用者属性的名称?
编辑:根据评论更新。
答案 0 :(得分:1)
创建一个添加一个参数的包装器可能更简单:
sub make_trigger {
my ($name, $sub) = @_;
return sub {
my $self = shift;
$self->$sub($name, @_);
};
}
has 'size' => (
is => 'rw',
trigger => make_trigger(size => \&_size_set),
);
sub _size_set {
my ( $self, $name, $size, $old_size ) = @_;
...
}
答案 1 :(得分:1)
正确这样做的方法是使用某种属性特征;一个传递名称,或者(最好)触发器所属属性的元类实例。人们甚至可以创建一个特征,允许我们询问类的元类是否属于属性触发器,如果是,则是哪一个。 (这将是透明的,并不会打破任何人对触发器如何工作的期望。)
最简单将是另一个例子中显示的触发器。
答案 2 :(得分:1)
这里是@RsrchBoy所说的"正确的方式" ...
use v5.14;
use strict;
use warnings;
BEGIN {
package MooseX::WhatTheTrig::Trait::Attribute
{
use Moose::Role;
use Scope::Guard qw(guard);
after _process_trigger_option => sub
{
my $class = shift;
my ($name, $opts) = @_;
return unless exists $opts->{trigger};
my $orig = delete $opts->{trigger};
$opts->{trigger} = sub
{
my $self = shift;
my $guard = guard {
$self->meta->_set_triggered_attribute(undef);
};
$self->meta->_set_triggered_attribute($name);
$self->$orig(@_);
};
}
}
package MooseX::WhatTheTrig::Trait::Class
{
use Moose::Role;
has triggered_attribute => (
is => 'ro',
writer => '_set_triggered_attribute',
);
}
}
package Example
{
use Moose -traits => ['MooseX::WhatTheTrig::Trait::Class'];
has [qw(foo bar)] => (
traits => ['MooseX::WhatTheTrig::Trait::Attribute'],
is => 'rw',
trigger => sub {
my ($self, $new, $old) = @_;
$_ //= 'undef' for $old, $new;
my $attr = $self->meta->triggered_attribute;
say "Changed $attr for $self from $old to $new!";
}
);
}
my $obj = Example->new(foo => 1, bar => 2);
$obj->foo(3);
$obj->bar(4);
你会注意到" foo"和" bar"属性共享一个触发器,但触发器能够区分这两个属性。
Moose :: Exporter有一些糖可以让它变得不那么难看。我可能会把它变成CPAN模块。