2010-10-22 6 views
6

Piszę moduł dla obiektu łosia. Chciałbym pozwolić użytkownikowi używającemu tego obiektu (lub sobie ...) dodać pola w locie, tak jak tego chce. Nie mogę zdefiniować tych pól a priori, ponieważ po prostu nie wiem, co one będą.Jak mogę elastycznie dodawać dane do obiektów na Moose?

Obecnie prostu dodaje jedno pole o nazwie Extra typu hashref która jest ustawiona na rw, dzięki czemu użytkownicy mogą po prostu umieścić rzeczy w tym hash:

# $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}; 

To działa. Ale ... czy to powszechna praktyka? Jakieś inne (być może bardziej eleganckie) pomysły?

Uwaga Nie chcę tworzyć kolejnego modułu, który rozszerza ten, to naprawdę tylko do rzeczy w locie, które chciałbym dodać.

Odpowiedz

6

to pewnie zrobić za pośrednictwem rodzimych cech:

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 { {} } 

na obiekcie chcesz korzystać z tego jak następuje:

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 

Typowym zastosowaniem literami dla rzeczy jak to dodając opcjonalny introspekcji danych do wyjątków i klas wiadomości.

+0

+1 To naprawdę fajne! –

+0

Czy mogę skasować akcesor, jeśli próbuję odczytać (nie ustawić) nieistniejącego pola? –

+0

Możesz zawinąć accessor 'custom_field' z modyfikatorem dookoła, sprawdź args i rechot, jeśli 'has_custom_field' zwraca false. – phaylon

4

Jeśli nie zamieniłeś klasy niezmiennej (jest to performance penalty, ponieważ nie robię tego, oprócz moich obaw dotyczących zmiany definicji klas w locie), powinieneś być w stanie to zrobić, pobierając klasę meta dla obiekt (używając $meta = $object->meta) i używając metody add_attribute w 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"; 

wyjściowa:

42 
5
+0

+1 Interesujące. Dzięki. Zazwyczaj ustawiam klasę na niezmienną (zgodnie z najlepszymi praktykami Moose'a). –

3

Tylko w przypadku, gdy chcesz dodać metodę do obiektu, a nie do całej klasy, a następnie spojrzeć na coś podobnego MooseX::SingletonMethod.

E.g.

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! 

Więc powyżej metody baz dodaje się tylko do obiektu $foo a nie klasy Foo.

Hmmm ... Zastanawiam się, czy mogę zaimplementować MooseX :: SingletonAttribute?


Niektóre poprzednie SO odpowiedzieć używając MooseX::SingletonMethod:

a także tego blogu może wykorzystania i/lub odsetek: Easy Anonymous Objects

/I3az/

+0

+1 Dzięki, dobrze się nauczyć o 'MooseX :: SingletonMethod'. –

Powiązane problemy