3

私は、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>);
        }
    }
}

ただし、でわかるように# <-- ERROR PRONE PROBLEM HERE!、このプロセス全体は、最初に属性に値があることに依存しています。値がundefの場合、をロードするかはわかりません。$attribute->get_value($self)代わりに、ロードする必要のある値のタイプに関する情報を取得する方法に置き換えたいと思います。私の問題は、上記でリンクしたドキュメントClass::MOP::AttributeMoose::Meta::Attribute、属性が取得するはずのオブジェクトのタイプを取得する方法がないように見えることです。

属性のタイプ情報は、基本的に私が取得しようとしているものです。

Moose::Meta::TypeConstraint(将来の読者への注意:ここでの答えは私を始めましたが、それ自体が最終的な解決策ではありません。私がここで探していることを実際に行うには、クラスを掘り下げる必要があります。)

4

3 に答える 3

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 /

于 2009-12-30T19:06:48.207 に答える
2

好奇心から、MooseX :: Storageを使用/拡張してみませんか?シリアル化を行い、約2年半あります。少なくともMooseX::Storageは、Moose用の(十分にテストされ、本番環境に対応した)シリアル化エンジンがどのように作成されているかを示すのに役立ちます。

于 2009-12-30T23:34:33.147 に答える
1

よくわかりませんが(おそらく、探しているものを示す疑似コードを含めることができます)、新しい属性特性を定義することで、必要な動作を得ることができるようです。クラスの一連のメソッドは、属性のオブジェクト(isa => 'MySerializer', handles => [ qw(methods) ])に委任します。

の動作を強化するMoose::Meta :: Classをサブクラス化する(または、より適切には、それにロールを追加する)必要がある場合もありadd_attribute()ます。

編集:Moose :: Meta :: Attribute(具体的には_process_optionsメソッド)のソースを見ると、isaオプションがMoose :: Util :: TypeConstraintstype_constraintによって処理され、フィールドに格納される実際のタイプが返されることがわかります。オブジェクト。これはMoose::Meta :: TypeConstraint :: Classオブジェクトになり、に対してのように呼び出すことができますis_a_type_of()

このフィールドはtype_constraint、Moose :: Meta::Attributeのメソッドを介して使用できます。属性のタイプをチェックするために使用できるすべてのインターフェースについては、Moose :: Meta::TypeConstraintを参照してください。

于 2009-12-30T18:28:22.157 に答える