Existe uma ferramenta para extrair todos os nomes de variáveis, módulos e funções de um arquivo de módulo Perl?
-
20-09-2019 - |
Pergunta
Minhas desculpas se isso é uma duplicata; Talvez eu não conheça os termos adequados para procurar.
Tenho a tarefa de analisar um arquivo de módulo Perl (.pm) que é um fragmento de um aplicativo maior. Existe uma ferramenta, aplicativo ou script que simplesmente passarão pelo código e retiram todos os nomes de variáveis, nomes de módulos e chamadas de função? Melhor ainda seria algo que identificaria se foi declarado dentro desse arquivo ou é algo externo.
Essa ferramenta existe? Eu só recebo o único arquivo, então isso não é algo que eu possa executar - apenas algumas análises estáticas básicas, eu acho.
Solução
Confira o novo, mas bem recomendado Class::Sniff
.
Dos documentos:
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";
}
Isso o levará a maior parte do caminho até lá. Algum variables
, dependendo do escopo, pode não estar disponível.
Outras dicas
Se eu entendi corretamente, você está procurando uma ferramenta para passar pelo código -fonte Perl. Eu vou sugerir PPI.
Aqui está um exemplo de destaque dos documentos:
#!/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;
Observe que isso será lançado:
...
'new',
'new',
'new',
'output',
'new',
'new',
'new',
'new',
'new',
...
porque várias classes são definidas em HTML/Template.pm
. Claramente, uma abordagem menos ingênua funcionaria com a árvore do PDOM de maneira hierárquica.
Outra ferramenta CPAN disponível é Classe :: Inspetor
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' );
Isso lhe dará resultados semelhantes à classe :: Sniff; Você ainda pode ter que fazer algum processamento por conta própria.
Há melhores respostas para essa pergunta, mas elas não estão sendo publicadas, então reivindicarei a arma mais rápida no oeste e irei em frente e postar uma 'rápida fixação'.
Essa ferramenta existe, de fato, e é incorporada ao Perl. Você pode acessar a tabela de símbolos para qualquer espaço para nome usando uma variável de hash especial. Para acessar o main
namespace (o padrão):
for(keys %main::) { # alternatively %::
print "$_\n";
}
Se o seu pacote for chamado My/Package.pm, e, portanto, estiver no espaço para nome My::Package
, você mudaria %main::
para %My::Package::
para alcançar o mesmo efeito. Veja o Perlmod Perlmod Entrada nas tabelas de símbolos - elas explicam e listam algumas alternativas que podem ser melhores, ou pelo menos você começar a encontrar o módulo certo para o trabalho (esse é o lema Perl - há mais de um módulo para fazê -lo).
Se você quiser fazer isso sem executar nenhum código que esteja analisando, é bastante fácil fazer isso com PPI. Confira o meu Módulo :: Use :: Extract; É um pouco de código mostra como extrair qualquer tipo de elemento que você deseja do PerlDom da PPI.
Se você deseja fazer isso com o código que já compilou, as outras sugestões nas respostas são melhores.
Encontrei uma resposta muito boa para o que estava procurando neste coluna Por Randal Schwartz. Ele demonstrou usar o módulo B :: XREF para extrair exatamente as informações que eu estava procurando. Apenas substituindo a linha de uma linha avaliada que ele usou com o nome do arquivo do módulo funcionou como um campeão e, aparentemente, B :: XREF vem com o Activestate Perl, então eu não precisava de módulos adicionais.
perl -MO=Xref module.pm