0

有几种方法可以列出包中的所有子项:

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

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

你有什么想法吗?

4

2 回答 2

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 来获取它,所以我检查__PACKAGE__了 sub 与正在检查的包的比较。

无法判断某个东西是否是方法,所以我概括了 sub 的名称。

于 2012-09-20T01:27:45.027 回答
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";
    }
}
于 2012-09-20T01:59:15.960 回答