2016-08-10 2 views
2

はムースに基づいているPerlコードの次の断片を見る:たPerlムースアクセサは

$BusinessClass->meta->add_attribute($Key => { is  => $rorw, 
               isa  => $MooseType, 
               lazy  => 0, 
               required => 0, 
               reader => sub { $_[0]->ORM->{$Key} }, 
               writer => sub { $_[0]->ORM->newVal($Key, $_[1]) }, 
               predicate => "has_$Key", 
              }); 

Iがエラーを受け取る:

bad accessor/reader/writer/predicate/clearer format, must be a HASH ref at /usr/local/lib/perl5/site_perl/mach/5.20/Class/MOP/Class.pm line 899

エラーの理由がありますclear:リーダライタは関数の文字列名でなければなりません。

しかし、この特定のケースではどうすればよいですか?私は100のORMフィールドのそれぞれに対して新しい関数を作成したくありません(ORM属性はここでは連結されたハッシュです)。だから私はここで文字列を渡すことはできません、私は閉鎖が必要です。

私のコーディングの必要性は矛盾していました。私は何をすべきかわからない。


上記は、実コードの断片です。今私は、最小限の例を提示:私は書き込みせずに、「動的」(閉鎖状)のアクセサを作成する方法(何をするか分からない

$ ./test.pl 
bad accessor/reader/writer/predicate/clearer format, must be a HASH ref at /usr/lib/i386-linux-gnu/perl5/5.22/Class/MOP/Class.pm line 899 
    Class::MOP::Class::try {...} at /usr/share/perl5/Try/Tiny.pm line 92 
    eval {...} at /usr/share/perl5/Try/Tiny.pm line 83 
    Try::Tiny::try('CODE(0x9dc6cec)', 'Try::Tiny::Catch=REF(0x9ea0c60)') called at /usr/lib/i386-linux-gnu/perl5/5.22/Class/MOP/Class.pm line 904 
    Class::MOP::Class::_post_add_attribute('Moose::Meta::Class=HASH(0x9dc13f4)', 'Moose::Meta::Attribute=HASH(0x9dc6b5c)') called at /usr/lib/i386-linux-gnu/perl5/5.22/Class/MOP/Mixin/HasAttributes.pm line 39 
    Class::MOP::Mixin::HasAttributes::add_attribute('Moose::Meta::Class=HASH(0x9dc13f4)', 'Moose::Meta::Attribute=HASH(0x9dc6b5c)') called at /usr/lib/i386-linux-gnu/perl5/5.22/Moose/Meta/Class.pm line 572 
    Moose::Meta::Class::add_attribute('Moose::Meta::Class=HASH(0x9dc13f4)', 'af', 'HASH(0x9ea13a4)') called at test.pl line 18 

#!/usr/bin/perl 

my @Fields = qw(af sdaf gdsg ewwq fsf); # pretend that we have 100 fields 

# Imagine that this is a tied hash with 100 fields 
my %Data = map { $_ => rand } @Fields; 

package Test; 
use Moose; 

foreach my $Key (@Fields) { 
    __PACKAGE__->meta->add_attribute($Key => { is  => 'rw', 
              isa  => 'Str', 
              lazy  => 0, 
              required => 0, 
              reader => sub { $Data{$Key} }, 
              writer => sub { $Data{$Key} = $_[1] }, 
              }); 
} 

は、それが、その結果実行します100フィールドのそれぞれの個別の機能ですか?)

+0

これを実行できるように[mcve]を作成してください。 – simbabque

+0

@simbabque Done – porton

+1

作者はオブジェクトにではなくハッシュに直接書き込むことになっていますか? – simbabque

答えて

3

私は読者とライターの方法を変えることは、不健康なレベルの狂気を必要とすると思います。あなたがしたい場合は、アクセサーを作成するためにフードの下で使用されるthe source code of Class::MOP::Method::Accessorを見てください。

代わりに、aroundメソッド修飾子を使用してMoose生成リーダーに機能を上書き(またはアタッチ)することをお勧めします。サブクラスで動作させるには、aroundの代わりにClass::Method::Modifiersを使用します。

package Foo::Subclass; 
use Moose; 
extends 'Foo'; 

package Foo; 
use Moose; 

package main; 
require Class::Method::Modifiers; # no import because it would overwrite Moose 

my @Fields = qw(af sdaf gdsg ewwq fsf); # pretend that we have 100 fields 

# Imagine that this is a tied hash with 100 fields 
my %Data = map { $_ => rand } @Fields; 

my $class = 'Foo::Subclass'; 
foreach my $Key (@Fields) { 
    $class->meta->add_attribute(
     $Key => { 
      is  => 'rw', 
      isa  => 'Str', 
      lazy  => 0, 
      required => 0, 
     } 
    ); 

    Class::Method::Modifiers::around("${class}::$Key", sub { 
     my $orig = shift; 
     my $self = shift; 

     $self->$orig(@_); # just so Moose is up to speed 

     # writer 
     $Data{$Key} = $_[0] if @_; 

     return $Data{$Key}; 
    }); 
} 

次にテストを実行します。

package main; 
use Data::Printer; 
use v5.10; 

my $foo = Test->new; 
say $foo->sdaf; 
$foo->sdaf('foobar'); 
say $foo->sdaf; 

p %Data; 
p $foo; 

ここに私のマシンのSTDOUT/STDERRがあります。

{ 
    af  0.972962507120432, 
    ewwq 0.959195914302605, 
    fsf 0.719139421719849, 
    gdsg 0.140205658312095, 
    sdaf "foobar" 
} 
Foo::Subclass { 
    Parents  Foo 
    Linear @ISA Foo::Subclass, Foo, Moose::Object 
    public methods (6) : af, ewwq, fsf, gdsg, meta, sdaf 
    private methods (0) 
    internals: { 
     sdaf "foobar" 
    } 
} 
0.885114977459551 
foobar 

あなたが見ることができるように、ムースは本当にハッシュの内部の値を知っていませんが、あなたはアクセサを使用している場合、それはそれらを読み書きします。ライターを使用する場合、Mooseオブジェクトは新しい値でゆっくりと埋められますが、そうでなければ、Mooseオブジェクトの内部の値は本当に重要ではありません。

+0

実用的なコードでは、派生クラスのために機能する基本クラスの '$ BusinessClass-> meta-> add_attribute(...); 'を呼び出すので、素晴らしいソリューションですが、私にとってはうまくいきません。あなたの提案した '$ Key'は基本クラスで呼び出され、' add_attribute() 'が別の(派生した)クラスに対して呼び出されたためエラーが発生し、基本クラスに$ Key属性がありません。何をすべきか? – porton

+0

これは子クラスで動作するはずです。私はコンピュータを持っているときに試してみる。 – simbabque

+0

@porton私は答えを改訂しました。 'Test'は' Foo'に改名され、現在はサブクラスがあります。トリックはムースの周りを使用することではありません。 – simbabque