6

如果这是重复的,我深表歉意;我可能不知道要搜索的正确术语。

我的任务是分析作为较大应用程序片段的 Perl 模块文件 (.pm)。是否有工具、应用程序或脚本可以简单地遍历代码并提取所有变量名、模块名和函数调用?更好的是可以识别它是在这个文件中声明的还是外部的。

这样的工具存在吗?我只得到一个文件,所以这不是我可以执行的——我猜只是一些基本的静态分析。

4

6 回答 6

10

查看新的,但强烈推荐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可能不可用。

于 2009-08-27T20:56:13.213 回答
8

如果我理解正确,您正在寻找一种工具来检查 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 树。

于 2009-08-27T21:33:25.570 回答
7

另一个可用的 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 类似的结果;您可能仍然需要自己进行一些处理。

于 2009-08-27T21:02:41.700 回答
3

如果您想在不执行任何正在分析的代码的情况下执行此操作,则使用PPI很容易做到这一点。查看我的Module::Use::Extract;这是一小段代码,向您展示了如何从 PPI 的 PerlDOM 中提取您想要的任何类型的元素。

如果你想用你已经编译的代码来做,答案中的其他建议会更好。

于 2009-08-28T19:17:56.807 回答
3

这个问题有更好的答案,但没有发布,所以我会声称是西方最快的枪,然后继续发布“快速修复”。

事实上,这样的工具是存在的,并且内置在 Perl 中。您可以使用特殊的散列变量访问任何命名空间的符号表。访问main命名空间(默认):

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

如果您的包名为 My/Package.pm,因此位于 namespaceMy::Package中,您将更改为%main::%My::Package::达到相同的效果。请参阅符号表上的perldoc perlmod条目 - 他们对此进行了解释,并列出了一些可能更好的替代方案,或者至少让您开始为工作找到合适的模块(这就是 Perl 的座右铭 - There's More Than One Module To做它)。

于 2009-08-27T20:57:53.647 回答
1

我在Randal Schwartz的这个专栏中找到了一个很好的答案。他演示了使用 B::Xref 模块来准确提取我正在寻找的信息。只是用模块的文件名替换他使用的评估单行就像一个冠军,显然 B::Xref 带有 ActiveState Perl,所以我不需要任何额外的模块。

perl -MO=Xref module.pm 
于 2009-08-28T20:44:21.597 回答