Структурированные лося - PullRequest
       16

Структурированные лося

2 голосов
/ 01 декабря 2010

Я хотел бы создать структурированный тип в Moose, который можно использовать в качестве типа для другого атрибута Moose. Например, я хотел бы иметь возможность создать атрибут name, который имеет свои собственные атрибуты value и error.

Поэтому я хотел бы знать, как лучше всего этого достичь. Я создал рабочий пример, определив простой класс Moose для представления универсального объекта Field. Это имеет атрибуты value и error. Затем я создал еще один класс Moose для объекта Person. Это имеет атрибуты id и name, оба из которых имеют тип 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 я хотел бы иметь возможность прямого доступа к value и error атрибутам name и id этого человека без необходимости сначала создавать новый объект MyApp::Type::Field для каждого из атрибутов человека.

Или, иначе говоря, я бы предпочел, чтобы пользователю класса Person не приходилось делать это: $person->id( MyApp::Type::Field->new() );, прежде чем он смог использовать атрибут id.

Есть ли хороший чистый способ, которым я могу этого достичь?

Ответы [ 2 ]

1 голос
/ 01 декабря 2010

Вы также можете попробовать принуждение:

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 );
    
1 голос
/ 01 декабря 2010

Не могли бы вы просто предоставить default для свойств?

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

… или сделать эквивалент в BUILD.

...