如何将Moose方法修改器应用于基于方法属性的方法?

时间:2013-08-30 08:36:58

标签: perl moose

我想在我的课程中为一些方法应用一个Moose'fake'方法修饰符。我想在角色中提供修饰符方法。我可以这样做:

package MyApp::Role;

use Moose::Role

before [qw(foo bar)] => sub {
    ...
};

package MyApp;

use Moose;
with (MyApp::Role);

sub foo { ... }

sub bar { ... }

sub baz { ... } # this method is unaffected

但是,必须维护角色中的相关方法列表将其与消费类联系起来,这似乎是错误的。我想以更聪明的方式做到这一点,比如方法属性:

package MyApp;

use Moose;
with (MyApp::Role);

sub foo :SomeFlag { ... }

sub bar :SomeFlag { ... }

sub baz { ... } # this method is unaffected

我不熟悉如何识别方法属性或如何动态地将方法修饰符应用于它们。

或者,也许有更好的方法可以做到这一点?

1 个答案:

答案 0 :(得分:5)

让我们使用Attribute::Handlers - 这是一种使用属性的相当明智的方法。我们必须在基类中定义一个函数,它本身具有属性:ATTR(CODE)。这需要一些论据:

  1. 子(或其他变量)来自的包。
  2. 一个globref,或者字符串ANON
  3. 对值的引用(此处为:coderef)。
  4. 属性的名称。
  5. 属性的可选数据。
  6. 调用属性的(编译)阶段。
  7. 声明子文件的文件名。
  8. 声明子的行号。
  9. 所以我们可以做的是编写一个应用before的处理程序:

    use strict; use warnings; use feature 'say';
    
    BEGIN {
        package MyRole;
        use Moose::Role;
        use Attribute::Handlers;
    
        sub SomeFlag :ATTR(CODE) {
            my ($package, $globref, $code, $attr, $data, $phase, $filename, $line) = @_;
    
            ref($globref) eq 'GLOB'
                or die "Only global subroutines can be decorated with :SomeFlag"
                        . " at $filename line $line.\n";
    
            # use the MOP to install the method modifier
            $package->meta->add_before_method_modifier(
                *$globref{NAME} => sub {
                    warn "Just about to call a flagged sub!";
                },
            );
        }
    }
    
    BEGIN {
        package MyApp;
        use Moose;
        # important: SomeFlag must be available before the attrs are handled (CHECK phase)
        BEGIN { with 'MyRole' };
    
        sub foo :SomeFlag { say "Hi from foo sub!" }
        sub bar :SomeFlag { say "Hi from bar sub!" }
        sub baz           { say "Hi from baz sub!" }
    }
    
    package main;
    
    my $o = MyApp->new;
    $o->$_ for qw/foo bar baz/;
    

    我把所有这些都塞进了一个文件中,但这显然不是必要的(只需添加所需的use)。

    输出:

    Just about to call a flagged sub! at so.pl line 16.
    Hi from foo sub!
    Just about to call a flagged sub! at so.pl line 16.
    Hi from bar sub!
    Hi from baz sub!