2009-08-27 16 views
5

Mi scuso se si tratta di un duplicato; Potrei non sapere i termini corretti da cercare.C'è uno strumento per estrarre tutti i nomi di variabili, moduli e funzioni da un file di modulo Perl?

Ho il compito di analizzare un file di modulo Perl (.pm) che è un frammento di un'applicazione più grande. C'è uno strumento, un'app o uno script che semplicemente passerà attraverso il codice e estrarrà tutti i nomi delle variabili, i nomi dei moduli e le chiamate alle funzioni? Ancora meglio sarebbe qualcosa che identificherà se è stato dichiarato all'interno di questo file o è qualcosa di esterno.

Esiste un tale strumento? Ricevo solo un file, quindi non è qualcosa che posso eseguire - solo alcune analisi statiche di base, suppongo.

+4

Date un'occhiata qui: http://stackoverflow.com/questions/607282/whats-the-best-way-to-discover-all-subroutines-a-perl-module-has Esistono diversi metodi. –

risposta

9

Controlla il nuovo, ma ben consigliato Class::Sniff.

Dalla documentazione:

use Class::Sniff; 
my $sniff = Class::Sniff->new({class => 'Some::class'}); 

my $num_methods = $sniff->methods; 
my $num_classes = $sniff->classes; 
my @methods  = $sniff->methods; 
my @classes  = $sniff->classes; 

{ 
    my $graph = $sniff->graph; # Graph::Easy 
    my $graphviz = $graph->as_graphviz(); 

    open my $DOT, '|dot -Tpng -o graph.png' or die("Cannot open pipe to dot: $!"); 
    print $DOT $graphviz; 
} 

print $sniff->to_string; 
my @unreachable = $sniff->unreachable; 
foreach my $method (@unreachable) { 
    print "$method\n"; 
} 

questo modo si ottiene la maggior parte del tragitto. Alcuni variables, a seconda dell'ambito, potrebbero non essere disponibili.

+0

+1 Sembra che sia stato battuto per il premio per pistola più veloce e con una risposta migliore. Maledizione alla mia mancanza di conoscenza della CPAN! –

+1

L'unica ragione per cui lo so è perché l'ho chiesto qualche mese fa :) –

+0

Funzionerà su un file? Il modulo in questione (quello che devo analizzare) ha delle dipendenze che non posso soddisfare, perché non possiedo quel codice. – romandas

2

Ci sono risposte migliori a questa domanda, ma non vengono pubblicate, quindi rivendicherò la pistola più veloce in Occidente e andrò avanti e postare una "soluzione rapida".

Tale strumento esiste, infatti, ed è incorporato in Perl. È possibile accedere alla tabella dei simboli per qualsiasi spazio dei nomi utilizzando una speciale variabile hash. Per accedere al main namespace (quella di default):

for(keys %main::) { # alternatively %:: 
    print "$_\n"; 
} 

Se il pacchetto si chiama My/Package.pm, ed è quindi nel namespace My::Package, si cambierebbe %main::-%My::Package:: per ottenere lo stesso effetto. Vedere la voce perldoc perlmod sulle tabelle dei simboli: lo spiegano e elencano alcune alternative che potrebbero essere migliori o almeno si inizia a cercare il modulo giusto per il lavoro (questo è il motto di Perl - C'è più di un modulo da fare It).

+0

Non avrei bisogno di caricare il modulo per usarlo? – romandas

+0

Se si vuole fare questo senza caricare il modulo, probabilmente si dovrà usare un buon vecchio stile 'grep'. O 'ack', una riscrittura ampiamente estesa di' grep' in Perl, usando regex in Perl e con numerose funzioni migliorate. –

+0

'% main ::' avrà solo le variabili del pacchetto, le variabili lessicali (ad esempio quelle create con 'my') non sono memorizzate in esso. –

7

Altri strumenti CPAN disponibile è Class::Inspector

use Class::Inspector; 

# Is a class installed and/or loaded 
Class::Inspector->installed('Foo::Class'); 
Class::Inspector->loaded('Foo::Class'); 

# Filename related information 
Class::Inspector->filename('Foo::Class'); 
Class::Inspector->resolved_filename('Foo::Class'); 

# Get subroutine related information 
Class::Inspector->functions('Foo::Class'); 
Class::Inspector->function_refs('Foo::Class'); 
Class::Inspector->function_exists('Foo::Class', 'bar'); 
Class::Inspector->methods('Foo::Class', 'full', 'public'); 

# Find all loaded subclasses or something 
Class::Inspector->subclasses('Foo::Class'); 

Questo vi darà risultati simili a Class :: Sniff; potresti ancora dover elaborare un po 'da solo.

8

Se ho capito bene, stai cercando uno strumento per passare attraverso il codice sorgente Perl. Ho intenzione di suggerire PPI.

Ecco un esempio ciottoli fino dalla documentazione:

#!/usr/bin/perl 

use strict; 
use warnings; 

use PPI::Document; 
use HTML::Template; 

my $Module = PPI::Document->new($INC{'HTML/Template.pm'}); 

my $sub_nodes = $Module->find(
    sub { $_[1]->isa('PPI::Statement::Sub') and $_[1]->name } 
); 

my @sub_names = map { $_->name } @$sub_nodes; 

use Data::Dumper; 
print Dumper \@sub_names; 

noti che, questa stamperà:

 ... 
    'new', 
    'new', 
    'new', 
    'output', 
    'new', 
    'new', 
    'new', 
    'new', 
    'new', 
    ... 

perché più classi sono definite HTML/Template.pm. Chiaramente, un approccio meno ingenuo funzionerebbe con l'albero PDOM in modo gerarchico.

3

Se si desidera eseguirlo senza eseguire alcun codice che si sta analizzando, è abbastanza semplice farlo con PPI. Controlla il mio Module::Use::Extract; è un po 'di codice che mostra come estrarre qualsiasi tipo di elemento desiderato da PerlDOM di PPI.

Se vuoi farlo con il codice che hai già compilato, gli altri suggerimenti nelle risposte sono migliori.

0

Ho trovato una buona risposta a quello che stavo cercando in questo column di Randal Schwartz. Ha dimostrato usando il modulo B :: Xref per estrarre esattamente le informazioni che stavo cercando. Sostituendo semplicemente la one-liner valutata che ha usato con il nome file del modulo ha funzionato come un campione, e apparentemente B :: Xref viene fornito con ActiveState Perl, quindi non ho bisogno di alcun modulo aggiuntivo.

perl -MO=Xref module.pm 
Problemi correlati