2009-12-30 3 views
3

Я работаю над инструментом сериализации, используя Moose для чтения и записи файла, который соответствует нестандартному формату. Сейчас я определяю, как загрузить следующий элемент на основе значений по умолчанию для объектов в классе, но у него есть свои недостатки. Вместо этого я хотел бы использовать информацию в метаклассе атрибута для генерации нового значения правильного типа. Я подозреваю, что есть способ определить, что такое ограничение isa, и получить от него генератор, но я не видел особых методов в Moose :: Meta :: Attribute или Class :: MOP :: Attribute, которые могли бы мне помочь.Как создать экземпляр значения из мета-объекта атрибута с помощью Moose?

Вот еще несколько примеров. Скажем, у меня есть следующий класс:

package Example; 
use Moose; 

use My::Trait::Order; 
use My::Class; 

with 'My::Role::Load', 'My::Role::Save'; 

has 'foo' => (
    traits => [ 'Order' ], 
    isa => 'Num', 
    is => 'rw', 
    default => 0, 
    order => 1, 
); 

has 'bar' => (
    traits => [ 'Order' ], 
    isa => 'ArrayRef[Str]', 
    is => 'rw', 
    default => sub { [ map { "" } 1..8 ] } 
    order => 2, 
); 

has 'baz' => (
    traits => [ 'Order' ], 
    isa => 'Custom::Class', 
    is => 'rw', 
    default => sub { Custom::Class->new() }, 
    order => 3, 
); 

__PACKAGE__->meta->make_immutable; 
1; 

(Дальнейшее объяснение: My::Role::Load и My::Role::Save выполнять роль сериализации для этого типа файла Они перебирать атрибуты класса они добавляются, и посмотреть на атрибуте. . классы для заказа сериализации в)

в My::Role::Load роли, я могу перебрать мета объекта для класса, глядя на все атрибуты, доступных мне, и выбрать только те, которые имеют свой заказ черты:

package My::Role::Load; 
use Moose;  

... 

sub load { 
    my ($self, $path) = @_; 

    foreach my $attribute ($self->meta->get_all_attributes) { 
     if (does_role($attribute, 'My::Trait::Order')) { 
      $self->load_attribute($attribute) # do the loading 
     } 
    } 
} 

Теперь мне нужно знать isa атрибута, который представляет собой мета-атрибут. Прямо сейчас, я проверить, что, получив экземпляр этого, и испытывать его с чем-то, что вроде как это:

use 5.010_001; # need smartmatch fix. 
... 
sub load_attribute { 
    my ($self, $attribute, $fh) = @_; 
    my $value = $attribute->get_value($self); # <-- ERROR PRONE PROBLEM HERE! 
    if (ref($value) && ! blessed($value)) { # get the arrayref types. 
     given (ref($value)) { 
      when('ARRAY') { 
       $self->load_array($attribute); 
      } 
      when('HASH') { 
       $self->load_hash($attribute); 
      } 
      default { 
       confess "unable to serialize ref of type '$_'"; 
      } 
     } 
    } 
    else { 
     when (\&blessed) { 
      confess "don't know how to load it if it doesn't 'load'." 
       if ! $_->can('load'); 
      $_->load(); 
     } 
     default { 
      $attribute->set_value($self, <$fh>); 
     } 
    } 
} 

Но, как вы можете видеть на # <-- ERROR PRONE PROBLEM HERE!, весь этот процесс зависит от наличия значение в атрибут для начала! Если значение равно undef, у меня нет указаний относительно , который загружается. Я хотел бы заменить $attribute->get_value($self) на способ получения информации о типе значения, которое нужно загрузить. Моя проблема в том, что документы, с которыми я связан выше для Class::MOP::Attribute и Moose::Meta::Attribute, похоже, не имеют способа получить объект типа, который должен получить атрибут.

Информация о типе для атрибута - это в основном то, к чему я пытаюсь добраться.

(Примечание для будущих читателей:.. Здесь ответ заставил меня начать, но это не окончательное решение в себя Вам придется копаться в Moose::Meta::TypeConstraint классов на самом деле делать то, что я ищу здесь)

ответ

3

Не уверен, что я следую за вами, и, возможно, принуждения могут делать то, что вы хотите?

Однако, чтобы получить атрибуты ISA:

{ 
    package Foo; 
    use Moose; 

    has 'bar' => (isa => 'Str', is => 'rw'); 
} 


my $foo = Foo->new; 

say $foo->meta->get_attribute('bar')->type_constraint; # => 'Str' 

/I3az/

+0

Type_constraint - aha! Я думаю, что все! –

+0

Хорошо, спасибо за то, что вы на правильном пути. Пора спросить лучшую форматированную версию вопроса. :) –

+0

Рад помочь. Я только знал об атрибуте $ attribute-> type_constraint, когда я прочитал это превосходное сообщение в блоге Sartak: http://blog.sartak.org/2009/06/mooses-mop-schematize.html – draegtun

1

Я не совсем уверен, что понимаю (возможно, вы можете включить некоторый псевдокод, который демонстрирует то, что вы ищете), но похоже, что вы могли бы получить нужное поведение, указав новый атрибут атрибута: настройте свой атрибут так что куча методов в делетете класса для объекта атрибута (isa => 'MySerializer', handles => [ qw(methods) ]).

Возможно, вам также понадобится подкласс Moose::Meta::Class (или лучше, добавьте к нему роль), который увеличивает поведение add_attribute().

Edit: Если вы посмотрите на источник Moose::Meta::Attribute (в частности, метод _process_options), вы увидите, что опция isa обрабатывается Moose::Util::TypeConstraints вернуть фактический тип должен быть сохранен в type_constraint поле в объекте. Это будет объект Moose::Meta::TypeConstraint::Class, который вы можете совершать, например, is_a_type_of().

Это поле доступно через type_constraint method в Moose :: Meta :: Attribute. См. Moose::Meta::TypeConstraint для всех доступных вам интерфейсов для проверки типа атрибутов.

2

Из любопытства, почему не использовать/расширить MooseX::Storage? Он выполняет сериализацию и имеет около двух с половиной лет. По крайней мере MooseX :: Storage поможет вам, показывая, как написано (проверенный и готовый) механизм сериализации для Moose.