Listing subs in a package
May 25, 2007
How can you list all the subroutines defined in a Perl package, at runtime?
Trying to answer that question, I googled a bit, digged around on cpan, and stumbled upon a few answers. The first one comes from perlmonks and looks like this:
sub get_function_names_from_package {
no strict 'refs';
my $pkg = shift || caller;
my $symtab = *{ $pkg . "::" }{HASH};
grep *$_{CODE},
map $pkg."::$_",
grep !/^_|^[_A-Z]+$/,
keys %$symtab;
}
What this code does is to list all the symbols belonging to a given package, filter away those that start with _ (Perl's standard for private subs) or only uppercase (private globals), then those that does not refer to functions. Very perlish and hard to read ;)
Then I found an other variant in a module called Sub::WrapPackage, that boils down to:
sub get_function_names_from_package {
my $pkg = shift || caller;
my @subs;
no strict;
while(my($name, $v) = each(%{$pkg})) {
push @subs, $pkg."::".$name if(defined(&{$v}));
}
return @subs;
}
Cleaner code. It does not filter out private subs, but that can be easily added.
Then, we have the hardcore way, extracted from the guts of the module Pod::Coverage:
use Devel::Symdump;
use B;
sub get_function_names_from_package {
my $pkg = shift;
my @subs;
eval qq{ require $pkg };
my $syms = Devel::Symdump->new($pkg);
for my $sym ( $syms->functions ) {
# see if said method wasn't just imported from elsewhere
my $owner;
{
no strict 'refs';
# this works only with perl 5.8 and later
$owner = *{ B::svref_2object( \&{ $sym } )->GV->object_2svref };
$owner =~ s/^\*(.*)::.*?$/$1/;
}
next if ($owner ne $pkg);
$sym =~ s/^$pkg\:\://;
next if ($sym =~ /^_/);
push @subs, $sym;
}
return @subs;
}
Make your choice...
Trying to answer that question, I googled a bit, digged around on cpan, and stumbled upon a few answers. The first one comes from perlmonks and looks like this:
sub get_function_names_from_package {
no strict 'refs';
my $pkg = shift || caller;
my $symtab = *{ $pkg . "::" }{HASH};
grep *$_{CODE},
map $pkg."::$_",
grep !/^_|^[_A-Z]+$/,
keys %$symtab;
}
What this code does is to list all the symbols belonging to a given package, filter away those that start with _ (Perl's standard for private subs) or only uppercase (private globals), then those that does not refer to functions. Very perlish and hard to read ;)
Then I found an other variant in a module called Sub::WrapPackage, that boils down to:
sub get_function_names_from_package {
my $pkg = shift || caller;
my @subs;
no strict;
while(my($name, $v) = each(%{$pkg})) {
push @subs, $pkg."::".$name if(defined(&{$v}));
}
return @subs;
}
Cleaner code. It does not filter out private subs, but that can be easily added.
Then, we have the hardcore way, extracted from the guts of the module Pod::Coverage:
use Devel::Symdump;
use B;
sub get_function_names_from_package {
my $pkg = shift;
my @subs;
eval qq{ require $pkg };
my $syms = Devel::Symdump->new($pkg);
for my $sym ( $syms->functions ) {
# see if said method wasn't just imported from elsewhere
my $owner;
{
no strict 'refs';
# this works only with perl 5.8 and later
$owner = *{ B::svref_2object( \&{ $sym } )->GV->object_2svref };
$owner =~ s/^\*(.*)::.*?$/$1/;
}
next if ($owner ne $pkg);
$sym =~ s/^$pkg\:\://;
next if ($sym =~ /^_/);
push @subs, $sym;
}
return @subs;
}
Make your choice...