2010-09-10 9 views
17

Ho un codice che chiama la funzione. Ma non conosco il modulo a cui appartiene questa funzione. Mi serve per modificare questa funzione.In Perl, come posso verificare da quale modulo è stata importata una determinata funzione?

Come posso verificarlo?

+3

Quale problema stai cercando di risolvere conoscendo questo? Potrebbe esserci un modo per sistemarlo prima che accada. :) –

+0

La modifica di funzioni da altre classi può essere comune in Ruby, ma è una tecnica nera in Perl che dovrebbe essere riservata per * estremamente * rare situazioni. Perché hai bisogno di fare questo? – Ether

+2

@ 'brian d foy' Tre anni dopo sto provando a scrivere un test unitario per confermare che ottengo correttamente una versione di Perl pura di una funzione in una condizione, o una versione XS in un'altra condizione, e all'improvviso ho quello che sento è un caso d'uso legittimo per il quesito di questo PO. ;) – DavidO

risposta

3

Se la funzione è stata automaticamente importato da un altro modulo con Exporter, lo si può trovare nella variabile globale @EXPORT di questo modulo:

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

è possibile fornire un elenco di funzioni a use. In questo modo sarete sempre sapere a quale pacchetto appartiene una funzione:

use Encode  qw[ encode ]; # encode() imported from the Encode module 
use Data::Dumper qw[];   # no functions imported from Data::Dumper 
28

Il modulo Devel::Peek è molto utile per ottenere tutti i tipi di informazioni sulle variabili. Una delle cose che puoi fare con esso è il dump di un riferimento ad una subroutine e ottenere il nome del glob è venuto da:

$ 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) 

la parte GVGV::GV in là è il bit importante.

Una soluzione alternativa sarebbe Sub::Identify, che in realtà fornisce solo i nomi per i riferimenti ai codici che gli si assegnano. Tuttavia, conoscere lo Devel::Peek è utile anche in molte altre situazioni, quindi l'ho menzionato per primo.

+4

Questo è molto meglio di quello che avrei fatto. Avrei aggiunto a '()' dopo ogni modulo utilizzato fino a quando il codice non è riuscito a compilare. –

8

Il debugger di Perl può scavare nel modo desiderato. Per esempio:

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

Lo fa utilizzando 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 

si potrebbe esercitare con

#! /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"; 

uscita:

Foo::bar

Si noti che l'esempio precedente dà Foo:bar un nome diverso, ma si ottiene sia il pacchetto in cui si trova il sub subordinato con alias sia il suo nome.

1

è possibile passare a Sub::Identify::sub_fullname qualsiasi riferimento subroutine e vi mostrerà il modulo in cui questo sub è stato definito:

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

foo(); 

Per i dettagli vedere Sub::Identify

Problemi correlati