¿Cómo accede un objeto a la tabla de símbolos para el paquete actual?
-
10-07-2019 - |
Pregunta
¿Cómo podría acceder a la tabla de símbolos para el paquete actual en el que se creó una instancia de un objeto? Por ejemplo, tengo algo como esto:
my $object = MyModule->new;
# this looks in the current package, to see if there's a function named run_me
# I'd like to know how to do this without passing a sub reference
$object->do_your_job;
Si en la implementación de do_your_job
uso __PACKAGE__
, buscará en el paquete MyModule
. ¿Cómo podría hacer que se vea en el paquete correcto?
EDITAR: intentaré aclarar esto. Supongamos que tengo el siguiente código:
package MyMod;
sub new {
return bless {}, ¿Cómo podría acceder a la tabla de símbolos para el paquete actual en el que se creó una instancia de un objeto? Por ejemplo, tengo algo como esto:
my $object = MyModule->new;
# this looks in the current package, to see if there's a function named run_me
# I'd like to know how to do this without passing a sub reference
$object->do_your_job;
Si en la implementación de do_your_job
uso __PACKAGE__
, buscará en el paquete MyModule
. ¿Cómo podría hacer que se vea en el paquete correcto?
EDITAR: intentaré aclarar esto. Supongamos que tengo el siguiente código:
<*>
Ahora, $ x
debería notar de alguna manera que main
es el paquete actual, y busca en su tabla de símbolos. Intenté usar Scalar :: Util
's bendito, pero todavía me dio MyModule
en lugar de main
. Con suerte, esto es un poco más claro ahora.
[0]
}
sub do_your_job {
my $self = shift;
# of course find_package_of is fictional here
# just for this example's sake, $pkg should be main
my $pkg = find_package_of($self);
if(defined &{ $pkg . '::run_me' }) {
# the function exists, call it.
}
}
package main;
sub run_me {
print "x should run me.\n";
}
my $x = MyMod->new;
# this should find the run_me sub in the current package and invoke it.
$x->do_your_job;
Ahora, $ x
debería notar de alguna manera que main
es el paquete actual, y busca en su tabla de símbolos. Intenté usar Scalar :: Util
's bendito, pero todavía me dio MyModule
en lugar de main
. Con suerte, esto es un poco más claro ahora.
Solución
Solo desea llamador
llamador
le dice el paquete desde el que se llamó. (Aquí agregué algunos perl estándar).
use Symbol qw<qualify_to_ref>;
#...
my $pkg = caller;
my $symb = qualify_to_ref( 'run_me', $pkg );
my $run_me = *{$symb}{CODE};
$run_me->() if defined $run_me;
Para buscarlo y ver si está definido y luego buscarlo para llamarlo, lo duplicaría ya que perl estándar no elimina la subexpresión común, por lo que también podría 1) recuperarlo y 2) verificar la definición de la ranura, y 3) ejecutarlo si está definido.
Ahora, si crea un objeto en un paquete y lo usa en otro, eso no será de mucha ayuda. Probablemente necesite agregar un campo adicional como 'owning_package'
en el constructor.
package MyMod;
#...
sub new {
#...
$self->{owning_package} = caller || 'main';
#...
}
Ahora $ x- > {owning_package}
contendrá 'main'
.
Otros consejos
Ver perldoc -f llamador :
#!/usr/bin/perl
package A;
use strict; use warnings;
sub do_your_job {
my ($self) = @_;
my ($pkg) = caller;
if ( my $sub = $pkg->can('run_me') ) {
$sub->();
}
}
package B;
use strict; use warnings;
sub test {
A->do_your_job;
}
sub run_me {
print "No, you can't!\n";
}
package main;
use strict; use warnings;
B->test;
Salida:
C:\Temp> h No, you can't!