В Perl, как я могу проверить, из какого модуля была импортирована данная функция? - PullRequest
20 голосов
/ 10 сентября 2010

У меня есть код, который вызывает функцию. Но я не знаю, к какому модулю принадлежит эта функция. Мне нужно, чтобы изменить эту функцию.

Как я могу это проверить?

Ответы [ 4 ]

30 голосов
/ 10 сентября 2010

Модуль Devel::Peek очень удобен для получения всевозможной информации о переменных.Одна из вещей, которые вы можете сделать с этим, - сбросить ссылку на подпрограмму и получить имя глобуса, из которого она получена:

$  perl -MDevel::Peek -MList::Util=first -e'Dump(\&first)'
SV = IV(0x1094e20) at 0x1094e28
  REFCNT = 1
  FLAGS = (TEMP,ROK)
  RV = 0x11183b0
  SV = PVCV(0x10ff1f0) at 0x11183b0
    REFCNT = 3
    FLAGS = (POK,pPOK)
    PROTOTYPE = "&@"
    COMP_STASH = 0x0
    XSUB = 0x7f7ecbdc61b0
    XSUBANY = 0
    GVGV::GV = 0x11183c8        "List::Util" :: "first"
    FILE = "ListUtil.c"
    DEPTH = 0
    FLAGS = 0x800
    OUTSIDE_SEQ = 0
    PADLIST = 0x0
    OUTSIDE = 0x0 (null)

часть GVGV::GV содержит важный бит.

Альтернативное решение будет Sub::Identify, которое на самом деле дает вам только имена для ссылок на код, которые вы передаете ему.Однако знание о Devel::Peek удобно и во многих других ситуациях, поэтому я упомянул об этом в первую очередь.

10 голосов
/ 10 сентября 2010

Отладчик Perl может копать так, как вы хотите.Например:

main::(-e:1):  0
  DB<1> sub foo {}

  DB<2> x \&foo
0  CODE(0xca6898)
   -> &main::foo in (eval 5)[/usr/share/perl/5.10/perl5db.pl:638]:2-2

Это делается с помощью Devel :: Peek :

=head2 C<CvGV_name_or_bust> I<coderef>

Calls L<Devel::Peek> to try to find the glob the ref lives in; returns
C<undef> if L<Devel::Peek> can't be loaded, or if C<Devel::Peek::CvGV> can't
find a glob for this ref.

Returns C<< I<package>::I<glob name> >> if the code ref is found in a glob.

=cut

sub CvGV_name_or_bust {
    my $in = shift;
    return unless ref $in;
    $in = \&$in;            # Hard reference...
    eval { require Devel::Peek; 1 } or return;
    my $gv = Devel::Peek::CvGV($in) or return;
    *$gv{PACKAGE} . '::' . *$gv{NAME};
} ## end sub CvGV_name_or_bust

Вы можете использовать его с

#! /usr/bin/perl

use warnings;
use strict;

package Foo;

sub bar {}

package main;

BEGIN { *baz = \&Foo::bar }

sub CvGV_name_or_bust { ... }

print CvGV_name_or_bust(\&baz), "\n";

Вывод:

Foo::bar

Обратите внимание, что приведенный выше пример дает Foo:bar другое имя, но вы получаете как пакет, в котором находится псевдоним, так и его имя.

3 голосов
/ 10 сентября 2010

Если функция была автоматически импортирована из другого модуля с использованием Exporter, ее можно найти в глобальной переменной @EXPORT этого модуля:

perl -MEncode -e 'print join "\n", @Encode::EXPORT'
decode   
decode_utf8
...   

Вы можете предоставить список функций для use,Таким образом, вы всегда будете знать, к какому пакету относится функция:

use Encode       qw[ encode ]; # encode() imported from the Encode module
use Data::Dumper qw[];         # no functions imported from Data::Dumper
1 голос
/ 18 января 2018

Вы можете передать Sub::Identify::sub_fullname любую ссылку подпрограммы, и она покажет вам модуль, в котором была определена эта подпрограмма:

use Sub::Identify qw/sub_fullname/;
sub foo {
    print sub_fullname( \&foo );  # main::foo
    print sub_fullname( sub{} );  # main::__ANON__
}

foo();

Подробнее см. Sub::Identify

...