Perl:修复Moose属性并输入强制问题

时间:2010-10-15 19:51:52

标签: perl moose coercion

我最近将Moose升级到v1.15,发现我使用的一组模块不再有效。我得到的错误是:

You cannot coerce an attribute (source) unless its type (GOBO::Node) has a coercion at
/opt/local/lib/perl5/site_perl/5.12.0/darwin-multi-2level/Moose/Meta/Role/Application/ToClass.pm line 142

我可以看到几种可能的错误来源,并对如何解决问题的建议表示感谢。

GOBO :: Node的第一部分代码如下:

package GOBO::Node;
[...]
extends 'GOBO::Base';
with 'GOBO::Labeled';
with 'GOBO::Attributed';

coerce 'GOBO::Node'
  => from 'Str'
  => via { new GOBO::Node(id=>$_) };

has 'source' => (is => 'rw', isa => 'GOBO::Node');

此程序包使用的角色还具有GOBO :: Nodes属性,错误消息中提到的属性“source”就是其中之一。

  • 在创建新节点时,在GOBO :: Node中强制执行的部分原因似乎是一个快捷方式。使用BUILDARGS而不是胁迫会更好吗?

  • 如果我想要几个包能够使用它,我应该在哪里施加强制?如果我将强制添加到(例如)GOBO :: Attributed,我会收到一条警告,表明它已经存在。但是,如果没有强制,我会收到上面关于无法强迫的警告。

  • 有一个单独的子类型包;创建GOBO :: Node的子类型会更好吗 - 例如。 GOBO :: Node :: ProtoNode - 和一个强制,并使用属性应该是GOBO ::节点?

感谢您对此问题的任何帮助或建议!

2 个答案:

答案 0 :(得分:9)

您粘贴的示例代码实际上并未触发错误。写在那里的source属性不会试图强制任何东西。但我假设你提到的一个角色有一个定义了coerce => 1的属性。

在驼鹿类型中,因此强制是全球性的。当与Moose动态构建一个类的事实相结合时,你最终会遇到你在这里看到的奇怪行为。在首次使用GOBO::Node类型之前,您需要将强制定义移动到某个地方。通常,这是通过创建一个子类型包(您已经注意到它已经拥有)并尽早包含(通过use)来完成的。

只需将GOBO::Node强制定义移动到这个子类型包中,并确保它在任何地方都需要强制使用才能解决您的问题。

回答您的其他问题:

  • 一般情况下,我建议对BUILDARGS使用强制,因为它是一个更精细的工具。您在此处显示的用法是正确强制使用的教科书示例,因此没有真正的理由来改变它。

  • 如上所述,典型的答案是在单独的命名空间(MyApp::TypeLibrary)中构建一个库包,然后将该包包含在您希望类型可用的类的顶部。 Perl不会重新编译它已经编译的包,这意味着在这种情况下不会触发你已经存在的强制错误。

  • 根据您提供的示例,无需创建新的子类型,GOBO :: Node应该已经可以使用,并且没有新的子类型,这实际上与最后一个相同。是使用子类型库。

我希望有所帮助。

答案 1 :(得分:6)

常见的解决方案是使用单独的文件来声明类型约束及其强制。如果您需要确保加载特定的类 - 例如强迫它 - 在你的强制职能中要求它。

所以,比如:

package GOBO::Types;
use Moose::Util::TypeConstraints;
class_type 'GOBO::Node';
coerce 'GOBO::Node',
    from 'Str',
    via { require GOBO::Node; GOBO::Node->new(id => $_) };

您可以在任何地方使用此类型库,而无需担心加载顺序,并且您可以确保已经定义了所有类型 - 如果您的类型不是class_type,则尤其重要,因为如何Moose尝试解析尚未定义的类型约束名称。

在这里使用强制而不是BUILDARGS绝对是正确的做法;它更可重复使用。