Существует ли инструмент для извлечения всех переменных, модулей и функций из файла модуля Perl? - PullRequest
6 голосов
/ 28 августа 2009

Мои извинения, если это дубликат; Возможно, я не знаю подходящих терминов для поиска.

Мне поручено проанализировать файл модуля Perl (.pm), который является фрагментом более крупного приложения. Есть ли инструмент, приложение или сценарий, который будет просто проходить через код и извлекать все имена переменных, имена модулей и вызовы функций? Еще лучше было бы то, что идентифицировало бы, было ли это объявлено в этом файле или является чем-то внешним.

Существует ли такой инструмент? Я получаю только один файл, так что это не то, что я могу выполнить - просто некоторый базовый статический анализ, я думаю.

Ответы [ 6 ]

10 голосов
/ 28 августа 2009

Проверьте новые, но хорошо рекомендуется Class::Sniff.

Из документов:

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";
}

Это даст вам большую часть пути туда. Некоторые variables, в зависимости от объема, могут быть недоступны.

8 голосов
/ 28 августа 2009

Если я правильно понимаю, вы ищете инструмент для просмотра исходного кода Perl. Я собираюсь предложить PPI .

Вот пример из документов:

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

Обратите внимание, что это выдаст:

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

, поскольку в HTML/Template.pm определены несколько классов. Ясно, что менее наивный подход будет работать с деревом PDOM иерархическим способом.

7 голосов
/ 28 августа 2009

Другие доступные инструменты CPAN: 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' );

Это даст вам результаты, аналогичные Class :: Sniff; вам, возможно, все равно придется выполнить некоторую обработку самостоятельно.

3 голосов
/ 28 августа 2009

Если вы хотите сделать это без выполнения какого-либо кода, который вы анализируете, это довольно легко сделать с помощью PPI . Проверьте мой Модуль :: Использование :: Извлечение ; это небольшой фрагмент кода, показывающий, как извлечь любой элемент из PerlDOM PPI.

Если вы хотите сделать это с кодом, который вы уже скомпилировали, другие предложения в ответах лучше.

3 голосов
/ 28 августа 2009

Есть лучшие ответы на этот вопрос, но они не публикуются, поэтому я запрошу самое быстрое оружие на Западе и отправлю «быстрое исправление».

Такой инструмент фактически существует и встроен в Perl. Вы можете получить доступ к таблице символов для любого пространства имен с помощью специальной хеш-переменной. Чтобы получить доступ к пространству имен main (по умолчанию):

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

Если ваш пакет называется My / Package.pm и, таким образом, находится в пространстве имен My::Package, вы должны изменить %main:: на %My::Package:: для достижения того же эффекта. Посмотрите запись perldoc perlmod в таблицах символов - они объясняют это, и они перечисляют несколько альтернатив, которые могут быть лучше, или, по крайней мере, помогут вам найти правильный модуль для работы (это девиз Perl - Для этого нужно больше, чем один модуль).

1 голос
/ 29 августа 2009

Я нашел довольно хороший ответ на то, что искал в этой колонке Рэндала Шварца. Он продемонстрировал использование модуля B :: Xref для извлечения именно той информации, которую я искал. Простая замена оцененной однострочной строки, которую он использовал, именем файла модуля работала как чемпион, и, очевидно, B :: Xref поставляется с ActiveState Perl, поэтому мне не нужны были дополнительные модули.

perl -MO=Xref module.pm 
...