Accesadores de Perl Moose generados sobre la marcha
attributes (1)
Creo que cambiar los métodos de lectura y escritura de este tipo requiere un nivel insalubre de locura. Si lo desea, eche un vistazo al código fuente de Class :: MOP :: Method :: Accessor , que se usa debajo del capó para crear los accesors.
En cambio, sugiero simplemente sobrescribir (o adjuntar) la funcionalidad a los lectores generados por Moose utilizando un modificador de método around
. Para que funcione con subclases, puede usar Class :: Method :: Modifiers en lugar de Moose around
.
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};
});
}
Y luego ejecuta una prueba.
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;
Aquí está el STDOUT / STDERR de mi máquina.
{
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
Como puede ver, Moose realmente no sabe acerca de los valores dentro del hash, pero si usa los accessors, los leerá y escribirá. El objeto Moose se llenará lentamente con nuevos valores cuando use el escritor, pero de lo contrario los valores dentro del objeto Moose realmente no importan.
Vea el siguiente fragmento de código de Perl que se basa en Moose:
$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",
});
Recibo el error:
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
La razón del error es clara: el lector y el escritor deben ser nombres de cadena de funciones.
Pero, ¿qué hacer en este caso específico? No quiero crear una nueva función para cada uno de los cien campos ORM (el atributo ORM aquí es un hash vinculado). Así que no puedo pasar una cadena aquí, necesito un cierre.
Por lo tanto, mis necesidades de codificación resultaron en una contradicción. No se que hacer.
Lo anterior fue un fragmento de código real. Ahora presento un ejemplo mínimo:
#!/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] },
});
}
Ejecutarlo da como resultado:
$ ./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
No sé qué hacer (cómo crear accesos "dinámicos" (similares a los cierres), sin escribir una función individual para cada uno de los 100 campos?)