驼鹿触发来电者

时间:2014-03-10 16:51:40

标签: perl triggers moose

有没有办法知道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 属性调用它,而无需明确指定调用者属性的名称?

编辑:根据评论更新。

3 个答案:

答案 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模块。