views:

629

answers:

5

How do you loop over all the methods of a class in Perl? Are there any good online references to Perl introspection or reflection?

+3  A: 

Depends if you mean, any class, or if you were implementing your own. For the latter, I use Moose, which offers a very clean syntax for these features. From the cookbook:

my %attributes = %{ $self->meta->get_attribute_map };
for my $name ( sort keys %attributes ) {
   my $attribute = $attributes{$name};

   if (   $attribute->does('MyApp::Meta::Attribute::Trait::Labeled')
   # ... keeps on
Todd Gardner
Note that Moose won't find any attributes unless the class you're introspecting was defined using Moose in the first place.However, the method introspection, as well as most other bits, will work just fine.
Dave Rolsky
+4  A: 

In the general case, you'll have to inspect the symbol table (unless you use Moose). For example, to list the methods defined in the IO::File package:

use IO::File;
no strict 'refs';
print join ', ', grep { defined &{"IO::File::$_"} } keys %{IO::File::};

The hash %{IO::File::} is the symbol table of the IO::File package, and the grep filters out non-subroutine entries (e.g. package variables).

To extend this to include inherited methods, you have to recursively search the symbol tables of the parent classes (@IO::File::ISA).

Here is a complete example:

sub list_methods_for_class {
    my $class = shift;
    eval "require $class";
    no strict 'refs';
    my @methods = grep { defined &{$class . "::$_"} } keys %{$class . "::"};
    push @methods, list_methods_for_class($_) foreach @{$class . "::ISA"};
    return @methods;
}

For more info on packages and symbol tables, see the perlmod man page.

trendels
Not every method has to be defined in the symbol table, and you're missing UNIVERSAL.
brian d foy
+9  A: 

The recommendation Todd Gardner gave to use Moose is a good one, but the example code he chose isn't very helpful.

If you're inspecting a non-Moose using class, you'd do something like this:

use Some::Class;
use Class::MOP;

my $meta = Class::MOP::Class->initialize('Some::Class');

for my $meth ( $meta->get_all_methods ) {
    print $meth->fully_qualified_name, "\n":
}

See the Class::MOP::Class docs for more details on how to do introspection.

You'll also note that I used Class::MOP instead of Moose. Class::MOP (MOP = Meta-Object Protocol) is the base on which Moose builds. If you're working with non-Moose classes, using Moose to introspect doesn't gain you anything.

If you wanted, you could use Moose () and Moose::Meta::Class->initialize instead of CMOP.

Dave Rolsky
+1: That's neat, I didn't know you could use Class::MOP like that.
Todd Gardner
I explain the limitations of this in my answer. Even with an empty class it fails to pick up the methods from UNIVERSAL, and can't pick up any from AUTOLOAD.
brian d foy
+2  A: 

You probably want Class::Inspector->methods('Your::Class').

Nuff said.

Adam Kennedy
+5  A: 

You can easily get a list of the defined methods of a class using the answers already provided. However, Perl is a dynamic language, which means more methods may be defined later. There really isn't a way to get a list of all of the methods to which any particular class will handle. For a lot more detail on this sort of stuff, I have a few chapters in Mastering Perl.

People are giving you (and upvoting) answers without telling you about the limitations.

Adam mentions his Class::Inspector, but it doesn't really work because it's trying to do something a dynamic language doesn't do (and that's be static :) For instance, here's a snippet where Class::Inspector returns no methods, but I can still call the VERSION method (as well as isa and can):

    BEGIN {

package Foo;

our $VERSION = '1.23'
}

use Class::Inspector;

my $methods = Class::Inspector->methods( 'Foo' );

print "Methods are [@$methods]\n"; # reports nothing

print Foo->VERSION, "\n";

Here's another case where I can call any method I like, but Class::Inspector only returns AUTOLOAD (and still missing VERSION, isa, and can):

BEGIN {

package Foo;

our $VERSION = '1.23';

my $object = bless {}, __PACKAGE__;

sub AUTOLOAD { $object }

}

use Class::Inspector;

my $methods = Class::Inspector->methods( 'Foo' );

print "Methods are [@$methods]\n"; # reports only "AUTOLOAD"

print Foo->dog->cat->bird, "\n";

Curiously, everyone seems to ignore UNIVERSAL, probably because they don't explicitly handle it since it's only virtually in @ISA. I can add a debug method to every class, and Class::Inspector still misses it even though it's a defined method:

BEGIN {

sub UNIVERSAL::debug { "Hello debugger!\n" }  
package Foo;
}

use Class::Inspector;

my $methods = Class::Inspector->methods( 'Foo' );

print "Methods are [@$methods]\n"; # still reports nothing

print Foo->debug, "\n";

Class::MOP has the same limitations.

Not every module is going to use AUTOLOAD, but it's not an obscure or rare feature either. If you don't mind that you are going to miss some of the methods then Class::Inspector or Class::MOP might be okay. It's just not going to give you a list of every method you can call on a class or an object in every case.

If you have a class or an object and you want to know if you can call a particular method, use can(). Wrap it in an eval block so can can call can() on things that aren't even objects to still get back false, instead of death, in those cases:

if( eval { $object->can( 'method_name' ) } )
    {
    $object->( @args );
    }
brian d foy