列出Perl程序中所有子程序的名称

4

我在我的Perl程序中使用了更多的模块。

例子:
use File::copy;

同样地,File模块包含Basename、Path、stat等内容。 我想要列出File包模块中所有的子例程(函数)名称。

在Python中有dir(module_name)函数可以实现这一功能, 它会列出该模块中使用的所有函数... 例如: #!/usr/bin/python

# Import built-in module math
import math

content = dir(math)

print content

像Python一样告诉Perl中的任何代码


2
这可以帮到您吗?:发现Perl模块所有子程序的最佳方法是什么? - Eirik Birkeland
1
请查看Devel::Examine::Subs - Håkon Hægland
“所以同样的,文件模块包含基本名称、路径和状态”。不,它并没有。不存在文件模块,也不存在File::Basename和File::Path模块之间的关系。 - ikegami
3个回答

4

如果您想查看Perl命名空间的内容,可以使用%modulename::

对于main,可以使用%main::%::

例如:

#!/usr/bin/perl
use strict;
use warnings;

use Data::Dumper;

sub fish {};
sub carrot {};

print "Stuff defined in Dumper:\n"; 
print Dumper \%Data::Dumper::;

print "Stuff defined:\n";
print Dumper \%::;

虽然这覆盖了很多内容,包括编译指示。但是您可以通过测试它是否为代码引用来检查例如子程序。

foreach my $thing ( keys %:: ) {
   if ( defined &$thing ) { 
        print "sub $thing\n";
   }
}

参考上面的示例,这将打印:

sub Dumper
sub carrot
sub fish

关于你最初的问题:

#!/usr/bin/perl
use strict;
use warnings;

use Data::Dumper;
use File::Copy;

print "File::Copy has subs of:\n";
foreach my $thing ( keys %File::Copy:: ) {
   if ( defined &$thing ) { 
        print "sub $thing\n";
   }
}

很遗憾,你不能像整个File::命名空间一样做同样的事情,因为有许多不同的模块可能已经安装/加载,但也可能没有。

你需要使用例如CPAN来检查 -

perl -MCPAN -e shell
i /^File::/

这将列出大约717个模块,这些模块被分组到File::树中。

您可以在CPAN上查找此信息。或者,如果您只需要核心模块,则可能使用Module::CoreList的某个变体就可以满足您的需求。

例如:

#!/usr/bin/perl
use strict;
use warnings;

use Module::CoreList;

foreach my $module ( Module::CoreList->find_modules(qr/^File::/) ) {
    if ( eval { require $module =~ s|::|/|gr . ".pm" } ) {
        print "Module: $module contains\n";
        my $key_str = "\%$module\:\:";

        my %stuff = eval $key_str;
        foreach my $thing ( sort keys %stuff ) {
            my $full_sub_path = "$module::$thing";
            if ( eval {"defined &$full_sub_path"} ) {
                if ( defined &$thing ) {
                    print "$thing <- $full_sub_path imported by default\n";
                }
                else {
                    print "\t$full_sub_path might be loadable\n";
                }
            }
        }
    }
    else {
        print "Module: $module couldn't be loaded\n";
    }
}

由于必须在运行时eval各个部分以测试模块是否实际存在且可加载,所以有点混乱。奇怪的是,File::Spec::VMS在我的Win32系统上不存在。想不出为什么.... :).

应该注意的是 - 仅仅因为您可以从模块中导入子模块(默认情况下未导出)并不意味着这是一个好主意。按照惯例,任何以_为前缀的子模块都不应在外部使用等。


你显然很快需要午餐了。 :) - simbabque
1
喂我西摩!(是的,快到午餐时间了)。 - Sobrique
非常感谢,Sobrique。 - Deepankumar

2

我的Devel::Examine::Subs模块可以完成这个任务,还有更多功能。请注意,它可以捕获方法和函数,两者都是无关紧要的。它纯粹基于使用PPI找到的子程序。

use warnings;
use strict;

use Devel::Examine::Subs;

my $des = Devel::Examine::Subs->new;

my $subs = $des->module(module => 'File::Copy');

for (@$subs){
    print "$_\n";
}

输出:

_move
move
syscopy
carp
mv
_eq
_catname
cp
copy
croak

或者是一个文件/完整目录。对于目录中的所有Perl文件(递归),只需将目录传递给file参数,路径结尾不需要加文件名:

my $des = Devel::Examine::Subs->new(file => '/path/to/file.pm');

my $subs = $des->all;

1
如果您只想打印它,请使用Data::Dumper模块和以下方法,CGI用作示例:
use strict;
use warnings;

use CGI;
use Data::Dumper;

my $object = CGI->new();

{
    no strict 'refs';
    print "Instance METHOD IS  " . Dumper( \%{ref ($object)."::" }) ;
}

此句话的意思是:注意,它是 File::Copy,而不是 File::copy。

2
File::Copy不是面向对象的,OP正在寻找子例程。然而,为了获取一个类(即包/命名空间)的所有方法,更有意义的做法是使用Data::Printer,它内置了这个功能。p $object将给出一个漂亮的列表,列出它拥有的所有方法和属性。 - simbabque
1
我真的很喜欢 Data::Printer 模块的外观,@simbabque... 我可以看到它在特定故障排除方面比其他模块有许多优点。 - stevieb

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接