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...

Comments

RSS feed for comments on this post.

The URI to TrackBack this entry is: http://lemonnier.se/erwan/blog/bblog/trackback.php/13/

Leave a Comment

Sorry, Comments have been disabled for this post