开发者

Perl: fixing Moose attribute and type coercion problems

I recently upgraded Moose to v1.15 and found that a set of modules I use no longer worked. The error I get is:

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

I can see several possible sources of error and would be grateful for advice on how to fix the problem.

The first bit of code for GOBO::Node looks like this:

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');

The roles used by this package also have attributes that are GOBO::Nodes, and the attribute 'source' mentioned in the error message is one of them.

  • part of the reason for having the coercion in GOBO::Node seems to be as a shortcut when creating a new node. Would it be better to use BUILDARGS rather than coerce?

  • where should I put the coercion if I want several packages to be able to use it? If I add the coercion to (e.g.) GOBO::Attributed, I get a warning that it already exists. Without the coercion, though, I get the warning above about not being able to coerce.

  • ther开发者_开发技巧e is a separate package of subtypes; would it be better to create a subtype of GOBO::Node--e.g. GOBO::Node::ProtoNode--and a coercion, and use that for the attributes should be GOBO::Nodes?

Thank you for any help or advice on this problem!


The example code you pasted doesn't actually trigger the error. The source attribute as written there won't try to coerce anything. I assume however that one of the roles you mention has an attribute with coerce => 1 defined.

In Moose types, and thus coercions, are global. When combined with the the fact that Moose builds a class dynamically you end up with the strange behavior you're seeing here. You'll need to move the definition of the coercion to someplace before the first use of the GOBO::Node type. Typically this is done by creating a package of subtypes (which you note you already have) and including that as early as possible (via use).

Simply moving the GOBO::Node coercion definition into this package of subtypes, and making sure it's used everywhere the coercion is needed should fix your problem.

To answer your other questions:

  • In general I would recommend using coercion over BUILDARGS because it is a much finer grained tool. The usage you're showing here is a text book example of proper coercion usage, so no real reason to change that.

  • As stated above, the typical answer is to build a Library package in a seperate namespace (MyApp::TypeLibrary) and then include that package at the top of the classes you want your types available. Perl won't re-compile a package that it has already compiled, meaning the error you got about the coercion already existing won't be triggered in this case.

  • Based on the examples you've provided there is no need to create a new subtype, GOBO::Node should already work, and without a new subtype this is effectively the same answer as the last one. Yes use the subtype library.

I hope that helps.


The common solution is to have a separate file just to declare type constraints and their coercions. If you need to make sure that a particular class is loaded -- e.g. to coerce to it -- require it inside your coercion functions.

So, something like:

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

You can use this type library anywhere without worrying about loading order, and you can be sure that all your types will be defined already -- especially important if you have types that aren't class_type, because of how Moose tries to resolve type constraint names that it hasn't seen defined yet.

Using a coercion here instead of BUILDARGS is definitely the right thing to do; it's much more reusable.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜