【问题标题】:How do I create an instance of value from the attribute's meta object with Moose?如何使用 Moose 从属性的元对象创建值的实例?
【发布时间】:2009-12-30 18:16:53
【问题描述】:

我正在开发一个序列化工具,使用 Moose 来读取和写入符合非标准格式的文件。现在,我根据类中对象的默认值确定如何加载下一项,但这有其自身的缺点。相反,我希望能够使用属性元类中的信息来生成正确类型的新值。我怀疑有一种方法可以确定“isa”限制是什么并从中派生一个生成器,但我在 Moose::Meta::Attribute 或 Class::MOP::Attribute 中没有看到可以帮助我的特定方法。

这里有一个更进一步的例子。假设我有以下课程:

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::LoadMy::Role::Save 实现了此文件类型的序列化角色。它们遍历它们所附加到的类的属性,并查看属性类以获取序列化顺序。 )

My::Role::Load 角色中,我可以遍历该类的元对象,查看我可用的所有属性,并仅选择那些具有我的 Order 特征的属性:

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

但是,正如您在# &lt;-- ERROR PRONE PROBLEM HERE! 看到的那样,整个过程依赖于属性中的值!如果该值为 undef,我不知道要加载 什么。我想用一种方法替换$attribute-&gt;get_value($self),以获取有关需要加载的值类型的信息。我的问题是,我在上面为 Class::MOP::AttributeMoose::Meta::Attribute 链接的文档似乎没有任何方法可以获取该属性应该获取的对象类型。

属性的类型信息基本上就是我想要得到的。

(给未来的读者注意:这里的答案让我开始了,但它本身并不是最终的解决方案。你必须深入研究Moose::Meta::TypeConstraint 类才能真正做到我在这里寻找的东西。)

【问题讨论】:

    标签: perl serialization moose metaclass


    【解决方案1】:

    不确定我是否遵循您所追求的目标,也许强制可以做您想做的事?

    然而获取属性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/

    【讨论】:

    • Type_constraint - 啊哈!我想就是这样!
    • 好的,感谢您让我走上正轨。是时候问一个格式更好的问题了。 :)
    • 很高兴能提供帮助。当我阅读 Sartak 的这篇出色的博客文章时,我才知道 $attribute->type_constraint:blog.sartak.org/2009/06/mooses-mop-schematize.html
    【解决方案2】:

    出于好奇,为什么不使用/扩展MooseX::Storage?它进行序列化,并且有大约两年半的时间。至少 MooseX::Storage 将通过展示如何编写 Moose 的(经过良好测试和生产就绪的)序列化引擎来帮助您。

    【讨论】:

      【解决方案3】:

      我不太确定我是否理解(也许您可以包含一些伪代码来演示您正在寻找的内容),但听起来您可以通过定义一个新的属性特征来获得您想要的行为:设置您的属性以便类上的一堆方法委托给属性的对象 (isa =&gt; 'MySerializer', handles =&gt; [ qw(methods) ])。

      您可能还需要对Moose::Meta::Class 进行子类化(或者更好的是,为其添加一个角色)以增强add_attribute() 的行为。

      编辑:如果您查看Moose::Meta::Attribute 的源代码(特别是_process_options 方法),您将看到isa 选项由Moose::Util::TypeConstraints 处理以返回要存储在@ 中的实际类型987654330@ 对象中的字段。这将是一个Moose::Meta::TypeConstraint::Class 对象,您可以针对该对象进行is_a_type_of() 之类的调用。

      此字段可通过 Moose::Meta::Attribute 中的 type_constraint 方法获得。请参阅Moose::Meta::TypeConstraint 了解所有可用于检查属性类型的接口。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-04-29
        • 2013-10-15
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-04-08
        相关资源
        最近更新 更多