包中的perl list subs,不包括从其他包中导入的subs

时间:2012-09-20 00:41:43

标签: perl package subroutine

有几种方法可以列出包中的所有潜艇:

sub list_methods {
    my $package = shift;
    no strict 'refs';
    return grep { defined &{"$package\::$_"} } keys %{"$package\::"}
}

但是,如果包“使用”其他包,例如'File :: Basename',那么也会列出像'fileparse'这样的子包。 我试图'需要'包而不是'使用'它们,问题可以解决。另一方面,如果我'需要'包,我必须指定潜艇的完整路径。

你有什么想法吗?

2 个答案:

答案 0 :(得分:3)

use B qw( svref_2object );

sub list_nonimported_subs {
    my ($pkg_name) = @_;
    my $pkg = do { no strict 'refs'; *{ $pkg_name . '::' } };

    my @nonimported_subs;
    for my $name (keys %$pkg) {
       my $glob = $pkg->{$name};
       my $code = *$glob{CODE}
          or next;

       my $cv = svref_2object($code);
       my $orig_pkg_name = $cv->GV->STASH->NAME;
       next if $orig_pkg_name ne $pkg_name;

       push @nonimported_subs, $name;
    }

    return @nonimported_subs;
}

有一个标志会告诉我们是否导入了一个glob中的CV,但是我找不到如何使用B来获取它,所以我检查了sub的__PACKAGE__与正在检查的包

不可能判断某事是否是某种方法,所以我概括了该子的名称。

答案 1 :(得分:2)

PPI将解析源代码,因此甚至不需要加载模块:

use PPI;

my $source = $INC{'Some/Module.pm'};  # or whatever
my $Document = PPI::Document->new($source) or die "oops";
for my $sub ( @{ $Document->find('PPI::Statement::Sub') || [] } ) {
    unless ( $sub->forward ) {
        print $sub->name, "\n";
    }
}