2014-03-25 3 views
2

무언가가 아닌 기존 코드를 다루고 있으며이를 무스 클래스로 확장하려고합니다. 이것은 레거시 코드의 단순화 :무스 - 객체 해시의 기본 속성 위치를 수정하십시오.

package My::Legacy; 

sub create { 
    my ($class, $args) = @_; 

    my $fields = { _fields => {}}; 
    foreach my $key (keys %$args) { 
    $fields->{_fields}->{$key} = $args->{$key} 
    } 
    bless $fields, $class; 
} 

1; 

내 :: 레거시 클래스는 모든 CRUD 작업, 캐싱 및 기타 물건을 처리합니다. 모든 작업은 내부 _field 해시에 포함 된 값에서 수행되므로 값을 업데이트하려면 예를 들어 _field 해시에 있어야합니다. My :: Legacy 클래스는이를 위해 setter/getter를 제공합니다.

내 :: 레거시가 그것에 의해 제공되는 "설탕"할 몇 가지 클래스에 의해 서브 클래스된다 내 :: 유산 :: ObjectA, 내 :: 유산 :: ObjectB

추가로 추가해야하며 무스를 사용하여 연장하고 싶습니다. 문제는 ... 내가 속성을 설정합니다 때마다, 나는 내가 가지고있는 경우, 예를 들어, 그래서 내부 _fields에 동기화 해시 값을 유지해야 할 것

package My::Legacy::MyMooseObj; 

use Moose; 
use MooseX::NonMoose; 
use namespace::autoclean; 

has _fields => (
    isa   => HashRef, 
    is   => 'rw', 
    default  => sub { {} }, 
); 

has attr_a => (
    isa => 'Int', 
    is => 'ro', 
); 

has attr_b => (
    isa => 'Str', 
    is => 'ro', 
); 


__PACKAGE__->meta->make_immutable; 

입니다 ... 그리고 수행

my $MyMooseObj = My::Legacy::MyMooseObj->new(); 
$MyMooseObj->attr_a(15); 

... 나는 내가이 모양 객체를 덤프 그래서 만약 attr_a이뿐만 아니라 _fields을 설정할 수 싶어 같은 :

bless({ 
      '_fields' => { 
          'attr_a' => 15, 
         }, 
      'attr_a' => 15, 
      }, 'My::Legacy::MyMooseObj'); 

나는 이것이 _fields의 모든 시간이 설정되어 해시 값을 작성하기 위해 각 속성에 트리거를 추가하는 것입니다 달성하기 위해 마련 방법 :이 때마다 때문에 조금 성가신

 has attr_b => (
     isa => 'Str', 
     is => 'ro', 
     trigger => sub { # Write in the _fields attribute attr_b value! }, 
    ); 

트리거를 설정했는지 확인해야하는 새 특성을 추가합니다./

더 좋은 방법을 생각해보십시오. 무언가를 읽거나 쓰려면 기본적으로 객체 해시의 "루트"에없는 속성을 쓰는 방법이 있습니까 (내 경우에는 속성을 읽고 쓰려면 _fields)? 당신이 비록 전체 __PACKAGE__->meta->make_immutable을 할 경우

답변

1

이 더 많거나 적은 당신이 원하는 무엇을 ... MooseX :: FunkyAttributes의 현재 버전

use strict; 
use warnings; 

{ 
    package My::Legacy::MyMooseObj; 

    use Moose; 
    use MooseX::FunkyAttributes; 
    use namespace::autoclean; 

    has _fields => (
     isa   => 'HashRef', 
     is   => 'rw', 
     default  => sub { {} }, 
     lazy  => 1, # you want this, for the rest to work 
    ); 

    has attr_a => (
     isa   => 'Int', 
     is   => 'ro', 
     traits  => [ FunkyAttribute ], 
     custom_get => sub { $_->_fields->{attr_a} }, 
     custom_set => sub { $_->_fields->{attr_a} = $_[-1] }, 
     custom_has => sub { exists($_->_fields->{attr_a}) }, 
    ); 

    has attr_b => (
     isa   => 'Str', 
     is   => 'rw', 
     traits  => [ FunkyAttribute ], 
     custom_get => sub { $_->_fields->{attr_b} }, 
     custom_set => sub { $_->_fields->{attr_b} = $_[-1] }, 
     custom_has => sub { exists($_->_fields->{attr_b}) }, 
    ); 
} 

my $obj = My::Legacy::MyMooseObj->new(attr_a => 42); 
$obj->attr_b(666); 

print $obj->dump; 

는 생성자가 제대로 작동하지 않습니다. 메타 프로그래밍에 조금 더 깊이 탐구 :-(

...

use strict; 
use warnings; 

{ 
    package My::Legacy::MyMooseObj; 

    use Moose; 
    use MooseX::FunkyAttributes; 
    use namespace::autoclean; 

    has _fields => (
     isa   => 'HashRef', 
     is   => 'rw', 
     default  => sub { {} }, 
     lazy  => 1, # you want this, for the rest to work 
    ); 

    sub funky_has { 
     my ($attr, %opts) = @_; 
     has $attr => (
      is   => 'ro', 
      traits  => [ FunkyAttribute ], 
      custom_get => sub { $_->_fields->{$attr} }, 
      custom_set => sub { $_->_fields->{$attr} = $_[-1] }, 
      custom_has => sub { exists($_->_fields->{$attr}) }, 
      %opts, 
     ); 
    } 

    funky_has attr_a => (isa => 'Int'); 
    funky_has attr_b => (isa => 'Str', is => 'rw'); 
} 

my $obj = My::Legacy::MyMooseObj->new(attr_a => 42); 
$obj->attr_b(666); 

print $obj->dump; 
+0

문제는 내가 모든 속성에 "특성", "custom_get", "custom_set", "custom_has"를 추가해야 할 것이다 "동기화"하고 싶습니다. 그래서 처음에했던 방식으로 타이핑을하지 않아도됩니다. __PACKAGE __-> meta-> make_immutable을 유지할 수 있습니까? – barbasa

+0

당신은 충분히 * meta * 다른 예제를 추가하겠습니다 ... – tobyink

+0

와우! 슈퍼 깔끔한! 고마워요 ...나는 확실히 생각하기 시작한다 _meta_ : – barbasa