2010-10-22 32 views
6

Tôi đang viết một mô-đun cho một đối tượng con nai sừng tấm. Tôi muốn cho phép người dùng sử dụng đối tượng này (hoặc bản thân mình ...) thêm một số trường khi đang di chuyển như mong muốn. Tôi không thể định nghĩa các trường này là một ưu tiên vì tôi chỉ đơn giản là không biết chúng sẽ là gì.Tôi có thể linh hoạt thêm dữ liệu vào các đối tượng Moose như thế nào?

Tôi hiện chỉ đơn giản là thêm vào một trường duy nhất gọi là thêm loại hashref đó là được thiết lập để rw, vì vậy người dùng có thể dễ dàng đưa công cụ trong băm rằng:

# $obj is a ref to my Moose object  
$obj->extra()->{new_thingie}="abc123"; # adds some arbitrary stuff to the object 
say $obj->extra()->{new_thingie}; 

này hoạt động. Nhưng ... đây có phải là một thực tế phổ biến? Bất kỳ ý tưởng nào khác (có thể thanh lịch hơn)?

Lưu ý Tôi không muốn tạo mô-đun khác để mở rộng mô-đun này, điều này thực sự chỉ dành cho nội dung trực tuyến mà tôi muốn thêm.

Trả lời

6

tôi có lẽ sẽ làm điều này thông qua những đặc điểm tự nhiên:

has custom_fields => (
    traits  => [qw(Hash)], 
    isa  => 'HashRef', 
    builder => '_build_custom_fields', 
    handles => { 
     custom_field   => 'accessor', 
     has_custom_field  => 'exists', 
     custom_fields  => 'keys', 
     has_custom_fields => 'count', 
     delete_custom_field => 'delete', 
    }, 
); 

sub _build_custom_fields { {} } 

Trên một đối tượng bạn muốn sử dụng này như sau:

my $val = $obj->custom_field('foo');   # get field value 
$obj->custom_field('foo', 23);     # set field to value 

$obj->has_custom_field('foo');     # does a specific field exist? 
$obj->has_custom_fields;      # are there any fields? 

my @names = $obj->custom_fields;    # what fields are there? 
my $value = $obj->delete_custom_field('foo'); # remove field value 

Một use-case phổ biến đối với những thứ như thế này là thêm tùy chọn dữ liệu không thể hiểu được đối với các lớp ngoại lệ và thông báo.

+0

+1 Điều đó thực sự tuyệt vời! –

+0

Tôi có thể làm cho trình thu thập thông tin truy cập nếu tôi cố gắng đọc (không được đặt) một trường không tồn tại không? –

+0

Bạn có thể bọc trình truy cập 'custom_field' bằng công cụ sửa đổi xung quanh, kiểm tra arg và thu gọn nếu 'has_custom_field' trả về false. – phaylon

4

Nếu bạn không làm cho lớp không thay đổi (có performance penalty vì không làm điều đó, ngoài những lo ngại của tôi về việc thay đổi định nghĩa lớp khi đang di chuyển), bạn sẽ có thể làm điều đó bằng cách lấy lớp meta cho đối tượng (sử dụng $meta = $object->meta) và sử dụng phương thức add_attribute trong Class::MOP::Class.

#!/usr/bin/perl 

package My::Class; 

use Moose; 
use namespace::autoclean; 

package main; 

my $x = My::Class->new; 
my $meta = $x->meta; 
$meta->add_attribute(
    foo => (
     accessor => 'foo', 
    ) 
); 

$x->foo(42); 

print $x->foo, "\n"; 

my $y = My::Class->new({ foo => 5 }); 
print $y->foo, "\n"; 

Output:

42 
5
+0

+1 Thú vị. Cảm ơn. Tôi thường đặt lớp học thành bất biến (theo các phương pháp hay nhất của Moose). –

3

Chỉ trong trường hợp bạn muốn thêm một phương pháp để một đối tượng và không cho cả lớp sau đó có một cái nhìn tại một cái gì đó giống như MooseX::SingletonMethod.

Ví dụ:

use 5.012; 
use warnings; 

{ 
    package Foo; 
    use MooseX::SingletonMethod; 
    sub bar { 'bar' }  # method available to all objects 
} 

my $foo = Foo->new; 

$foo->add_singleton_method(baz => sub { 'baz!' }); 

$foo->baz;  # => baz! 

Vì vậy, trong so với phương pháp baz chỉ bổ sung vào đối tượng $foo và không đến lớp Foo.

Hmmm ... Tôi tự hỏi liệu tôi có thể triển khai MooseX :: SingletonAttribute?


Một số trước câu trả lời SO sử dụng MooseX::SingletonMethod:

Và cũng bài viết trên blog này có thể sử dụng và/hoặc lãi: Easy Anonymous Objects

/I3az/

+0

+1 Cảm ơn, tốt để tìm hiểu về 'MooseX :: SingletonMethod'. –

Các vấn đề liên quan