开发者

How can I dynamicaly get a list of methods in a (non Moose) Perl library?

How can I dynamicaly get a list of methods in a (non Moose) Perl library?

I'm trying to wrap a non Moose class in a Moose class using delegation. Currently I am hard coding the list of methods I am delegating. Its n开发者_StackOverflow中文版ot a big deal, but I was wondering if there some more elegant way.


Impossible. There's no way to distinguish if a sub is a method or not. If you're ok with listing the subs instead, you could use

grep exists(&{ 'Foo::Bar::'.$_ }), keys %Foo::Bar::

Of course, that doesn't scan the inheritance tree. If you want to do that, you can get the list of packages to scan using

mro::get_linear_isa('Foo::Bar')


Well, strictly speaking it is impossible to distinguish between the subs and methods, as ikegami has mentioned.

But if you get creative you can always use PadWalker's peek_sub and closed_over to sorta kinda distinguish a sub from a method in the vast majority of cases, although of course both false positives and false negatives are possible:

use strict;
use warnings;

use PadWalker;

my $self;

sub test_sub
{
    my $x = shift;
    print $self;
}

sub test_method
{
    my $self = shift;
}

sub is_method
{
    my $coderef = shift;
    my $all = PadWalker::peek_sub($coderef);
    my $closed = PadWalker::closed_over($coderef);
    for my $k (qw($self $me $class)) {
        return 1 if $all->{$k} && !$closed->{$k};
    }
    return 0;
}

print "test_sub: ", is_method(\&test_sub) ?
    "is a method\n" : "is a sub\n";
print "test_method: ", is_method(\&test_method) ?
    "is a method\n" : "is a sub\n";

Getting the coderefs is left as an exercise for the reader.


An alternative to ikegami's answer is to use the Package::Stash module. Its list_all_symbols method will give you all the sub names in the given package. Here is an example:

perl -MPackage::Stash -E "say for Package::Stash->new('Package::Stash')->list_all_symbols('CODE')"


If you already use Moose, you can use Class::MOP for this. I think Class::MOP is the cleanest way and you can also fetch all Methods/Functions from the inheritance. But like the others said, you cant distinguish between a method and a function.

use Class::MOP;
use Test::More;

my $class = Class::MOP::Class->initialize('Test::More');
my @methods     = $class->get_method_list(); # Only Methods in this Class
my @all_methods = $class->get_all_methods(); # Include all inherited methods

printf "%d functions in Test::More\n", scalar @methods;
printf "%d functions including inheritance\n", scalar @all_methods;

print "methods:     @methods\n\n";
print "all methods: ", join(' ', map({ $_->fully_qualified_name } @all_methods)), "\n";

These prints somethink like this:

39 functions in Test::More
49 functions including inheritance
methods:     subtest _whoa cmp_ok isa_ok use_ok isnt _format_stack like _eq_array plan _eval fail _carp done_testing _type diag _is_module_name import_extra eq_array require_ok BAIL_OUT _dne is ok _eq_hash explain todo todo_skip unlike new_ok eq_set pass can_ok eq_hash is_deeply note _equal_nonrefs _deep_check skip
all methods: Exporter::export_fail Test::More::_whoa Test::More::subtest Exporter::export_tags Test::More::cmp_ok Test::More::use_ok Test::More::isa_ok Test::More::_format_stack Test::More::isnt Test::More::like Test::More::_eq_array Test::More::plan Exporter::export Test::More::_eval Test::More::_carp Test::More::fail Test::More::done_testing Test::More::_type Test::More::diag Test::Builder::Module::_strip_imports Test::More::_is_module_name Test::More::import_extra Exporter::as_heavy Test::More::eq_array Test::More::require_ok Exporter::export_to_level Test::More::BAIL_OUT Test::More::_dne Test::More::is Test::More::ok Exporter::export_ok_tags Test::More::explain Test::More::_eq_hash Test::More::todo_skip Test::More::todo Test::More::new_ok Test::More::unlike Test::More::pass Test::More::eq_set Test::More::can_ok Test::More::eq_hash Test::More::is_deeply Test::More::note Test::Builder::Module::import Test::More::_equal_nonrefs Test::More::skip Test::More::_deep_check Exporter::require_version Test::Builder::Module::builder
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜