为什么我的代码中Moose角色应用程序与方法修饰符不起作用?

3

我有一个角色和几个混入该角色的类。角色类会加载所有实现类,以便引用Blah的任何代码都无需输入大量的'use'语句。

package Blah;
use Moose::Role;

use Blah::A;
use Blah::B;
(etc...)

requires '...';
requires 'foo';
around 'foo' => sub { ... }

一个典型的Blah子类:

package Blah::A;
use Moose;
with 'Blah';

sub foo { ... }

__PACKAGE__->meta->make_immutable;

由于每个子类'foo'方法都以相同的代码位开始,该角色还通过方法修饰符实现了这些功能。
问题在于:Moose不会将方法修饰符应用于任何Blah::*类。即使我删除这些类的make_immutable调用,情况仍然如此。我认为角色应用完全是在运行时完成的,因此即使Blah::*类在Blah之前加载,修改器也应该被应用?
我正在寻找解决方法或替代方法。目前,除了方法修饰符之外,Blah本质上是一个抽象基类,这就是我使用角色的原因 - 但是也许类层次结构会更好?提前感谢您的帮助。
2个回答

4

你的调用顺序有点奇怪——为什么你要在应用于 Blah::A 的角色内部使用 Blah::A?

我建议将这些 use 行提取出来,移到它们实际需要的地方(在调用者中)。先让代码正常工作,然后,如果你有很多 use 行在各个地方杂乱无章,你可以将它们移动到一个 Includes 文件中。

但是,回答你的假设——角色应用不是在运行时完成的,而是在遇到 with 行的任何时间完成的。如果你在编译时使用一个模块,那么该文件会立即被编译,并执行 with 行(这会强制编译角色,然后运行它)。当然,你也可以在运行时应用角色(例如,请参见 Moose::Util 中的 apply_all_roles),但这不是这里正在发生的事情。


收到,谢谢。使用行有点烦人,但我想我会编写一个工厂模块来代替重载角色模块 :) - rjh
@rjh:是的,你只是太早加载了那些目标模块,在角色完成构建并应用于它们之前。 - Ether

-1

我认为你简单地误解了文件包含和角色组合之间的区别。

在底层,use语句只是调用require,然后推断出的包的import()语句,并将所有这些内容包装在一个BEGIN {}块中。

它不会将函数安装为元类方法,使用Class::MOP(CMOP)。我不确定声明方法和导入方法之间的区别,或者CMOP如何区分它们,但这仅因为调用了add_method而起作用。我想从irc.perl.org/#moose获得更多信息,但我被禁止了。希望这个例子能告诉你需要什么,或者给你更多信息来制定更好的问题。

package Class;
use Moose;
use Carp qw(carp);

### You have to add the method onto the class.
Class->meta->add_method( 'carp' => \&carp );

around 'carp' => sub { warn "this won't trigger" };

package main;

my $c = Class->new;
$c->carp('foo');

如果可能的话,我会将您正在使用的那些包重写为Moose友好的角色,然后只需让当前角色使用with语句调用新角色。角色将处理其他角色提供的方法周围的方法修饰符。

1
Evan,我认为你完全错过了问题的关键。他正在使用一个角色(Blah是Moose::Role)。他的问题与循环使用语句(使用当前定义的角色的类是不好的M'kay?)和时间有关(正如ether所指出的那样,组合发生在看到“with”时,并且可能会引起问题)。我无法看出你在这里的示例与问题有任何关系,因为他既没有使用导入,也没有展示完全覆盖around修饰符的方法的示例,就像你在这里所做的那样。Rjh可以自由进入#moose获取更多信息。 - perigrin
上场打球,我假设问题是特定于“use”用例的,因为如果删除“use”和“requires”,那段代码将可以工作。实例化Blah::A,我相信“around”会起作用。也许我试图推断太多了。 - Evan Carroll

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接