驼鹿结构类型

时间:2010-12-01 12:43:40

标签: perl moose

我想在Moose中创建一个结构化类型,可以用作另一个Moose属性的类型。例如,我希望能够创建一个name属性,该属性具有自己的valueerror属性。

因此,我想了解实现这一目标的最佳方法。我通过定义一个简单的Moose类来表示一个通用的Field对象,从而创建了一个工作示例。这具有valueerror属性。然后我为Person对象创建了另一个Moose类。它具有idname属性,两者都属于Field类型:

定义通用字段对象:

package MyApp::Type::Field;
use Moose;
use namespace::autoclean;

has 'value' => ( is => 'rw' );  
has 'error' => ( is => 'rw', isa => 'Str' );

__PACKAGE__->meta->make_immutable;
1;

定义使用字段对象的Person对象:

package MyApp::Person;
use Moose;
use namespace::autoclean;
use MyApp::Type::Field;

has 'id'   => ( is => 'rw', isa => 'MyApp::Type::Field' );    
has 'name' => ( is => 'rw', isa => 'MyApp::Type::Field' );

__PACKAGE__->meta->make_immutable;
1;

使用Person对象执行某些操作:

package MyApp::Test;

use Moose;
use namespace::autoclean;
use MyApp::Person;

my $person = MyApp::Person->new();

# This works.
$person->id( MyApp::Type::Field->new() );
$person->id->value( 1 );
$person->id->error( 'Not found' );

# This fails as the name object has not yet been defined.
$person->name->value( 'Dave' );
# Can't call method "value" on an undefined value at ...

__PACKAGE__->meta->make_immutable;
1;

这样做有效,但在MyApp::Test我希望能够直接访问此人valueerror的{​​{1}}和name属性首先必须为每个人的属性实例化一个新的id对象。

或者,换句话说,如果MyApp::Type::Field类的用户不必执行此操作,我会更喜欢它:Person,然后才能使用$person->id( MyApp::Type::Field->new() );属性。

有没有一种很好的清洁方式可以达到这个目的?

2 个答案:

答案 0 :(得分:1)

难道你不能简单地为属性提供default吗?

has 'id' => (
    is => 'rw',
    isa => 'MyApp::Type::Field',
    default => sub { MyApp::Type::Field->new }
);

...或在BUILD中执行等效操作。

答案 1 :(得分:1)

你也可以尝试强制:

coerce 'MyApp::Type::Field'
    => from 'Int'
    => via  { MyApp::Type::Field->new( value => shift ) }
    ;

这是唯一的:

$person->id( 1 );

设置它。虽然设置错误仍然需要按照你的方式进行。


我可能应该提到你需要做以下事情:

  • Moose::Util::TypeConstraints添加到您放置coerce的包中。
  • coerce标志添加到字段中:

    has id => ( is => 'rw', isa => 'MyApp::Type::Field', coerce => 1 );