즉시 생성 된 Perl 무스 접근 자



attributes moose (1)

무스에 기반한 다음 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",
                                            });

오류가 나타납니다.

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

오류의 원인은 분명합니다. reader 및 writer는 함수의 문자열 이름이어야합니다.

이 특별한 경우에 어떻게해야할까요? 나는 100 개의 ORM 필드 각각에 대해 새로운 함수를 만들고 싶지 않다. (여기에 ORM 속성은 묶인 해시이다.) 여기에 문자열을 전달할 수 없기 때문에 폐쇄가 필요합니다.

따라서 필자의 코딩 요구는 모순이되었다. 나는 무엇을해야할지 모른다.

위 코드는 실제 코드 조각입니다. 이제 나는 최소한의 예를 제시한다.

#!/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] },
                                           });
}

실행 결과는 다음과 같습니다.

$ ./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

100 개 필드 각각에 대해 개별 함수를 작성하지 않고 "동적"(클로저 형) 접근자를 만드는 방법을 알지 못합니다.


나는 독자와 작가의 방법을 바꾸는 것이 건강에 좋지 않은 수준의 정신 이상을 요구한다고 생각합니다. 원할 경우, Class :: MOP :: Method :: Accessor의 소스 코드를 살펴 보자. 이 소스 코드 는 접근자를 만드는 데 사용된다.

대신, around 메소드 수정자를 사용하여 무스 생성 독자에게 기능을 덮어 쓰는 (또는 첨부하는) 방법을 제안합니다. 이 클래스를 하위 클래스와 함께 사용하려면 무스 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 객체는 새 값으로 천천히 채워지지만, 그렇지 않으면 Moose 객체 내부의 값은 별 문제가되지 않습니다.