In che modo un oggetto accede alla tabella dei simboli per il pacchetto corrente?
-
10-07-2019 - |
Domanda
Come posso accedere alla tabella dei simboli per il pacchetto corrente in cui è stato istanziato un oggetto? Ad esempio, ho qualcosa del genere:
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;
Se nell'implementazione di do_your_job
utilizzo __PACKAGE__
, cercherà nel pacchetto MyModule
. Come potrei farlo sembrare nel pacchetto giusto?
EDIT: proverò a chiarire questo aspetto. Supponiamo che io abbia il seguente codice:
package MyMod;
sub new {
return bless {}, Come posso accedere alla tabella dei simboli per il pacchetto corrente in cui è stato istanziato un oggetto? Ad esempio, ho qualcosa del genere:
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;
Se nell'implementazione di do_your_job
utilizzo __PACKAGE__
, cercherà nel pacchetto MyModule
. Come potrei farlo sembrare nel pacchetto giusto?
EDIT: proverò a chiarire questo aspetto. Supponiamo che io abbia il seguente codice:
<*>
Ora, $ x
dovrebbe in qualche modo notare che main
è il pacchetto corrente e cerca nella sua tabella dei simboli. Ho provato a usare il benedetto Scalar :: Util
, ma mi ha comunque dato MyModule
invece di main
. Spero che ora sia un po 'più chiaro.
[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;
Ora, $ x
dovrebbe in qualche modo notare che main
è il pacchetto corrente e cerca nella sua tabella dei simboli. Ho provato a usare il benedetto Scalar :: Util
, ma mi ha comunque dato MyModule
invece di main
. Spero che ora sia un po 'più chiaro.
Soluzione
Vuoi solo chiamante
chiamante
ti dice il pacchetto da cui è stato chiamato. (Qui ho aggiunto un po 'di standard perl.)
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;
Per cercarlo e vedere se è definito e poi cercarlo per chiamarlo, lo duplicherebbe come standard perl non fa l'eliminazione della sottoespressione comune, quindi potresti anche 1) recuperarlo e 2) verificare la definizione di lo slot e 3) eseguirlo se è definito.
Ora se crei un oggetto in un pacchetto e lo usi in un altro, non sarà di grande aiuto. Probabilmente dovrai aggiungere un campo aggiuntivo come 'owning_package'
nel costruttore.
package MyMod;
#...
sub new {
#...
$self->{owning_package} = caller || 'main';
#...
}
Ora $ x- > {owning_package}
conterrà 'main'
.
Altri suggerimenti
Vedi perldoc -f caller :
#!/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;
Output:
C:\Temp> h No, you can't!