Как объект получает доступ к таблице символов для текущего пакета? - PullRequest
1 голос
/ 30 ноября 2009

Как я могу получить доступ к таблице символов для текущего пакета, в котором был создан объект? Например, у меня есть что-то вроде этого:

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;

Если в реализации do_your_job я использую __PACKAGE__, он будет искать в пакете MyModule. Как я могу заставить это выглядеть в правильной упаковке?

РЕДАКТИРОВАТЬ: Я постараюсь сделать это яснее. Предположим, у меня есть следующий код:

package MyMod;

sub new {
    return bless {},$_[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;

Теперь $x должен как-то заметить, что main - это текущий пакет, и искать его в таблице символов. Я попытался использовать благословение Scalar::Util, но оно все равно дало мне MyModule вместо main. Надеюсь, теперь это немного понятнее.

Ответы [ 2 ]

6 голосов
/ 01 декабря 2009

Вы просто хотите caller

caller сообщает вам пакет, из которого он был вызван. (Здесь я добавил несколько стандартных 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;

Чтобы найти его и посмотреть, определено ли оно, а затем найти его, чтобы вызвать, он дублировал бы его, так как стандартный perl не выполняет Устранение Common Subexpression, поэтому вы также можете 1) получить его и 2) проверить определенность слот и 3) запустить его, если он определен.

Теперь, если вы создаете объект в одном пакете и используете его в другом, это не слишком поможет. Возможно, вам понадобится добавить дополнительное поле, например 'owning_package', в конструктор.

package MyMod;

#...
sub new { 
    #...
    $self->{owning_package} = caller || 'main';
    #...
}

Теперь $x->{owning_package} будет содержать 'main'.

1 голос
/ 01 декабря 2009

См. 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;

Выход:

C:\Temp> h
No, you can't!
...