http://qs1969.pair.com?node_id=314794

rkg has asked for the wisdom of the Perl Monks concerning the following question:

Hi --

For debugging assistance (eg I am having some trouble with ClassMethod::Maker's "object_list" method; I can't seem to find the promised resulting LOO method):

how can one determine all valid methods for an arbitrary object?

Thanks

rkg

Replies are listed 'Best First'.
Re: OO: All Methods
by Abigail-II (Bishop) on Dec 15, 2003 at 11:35 UTC
    Due to the existance of features like AUTOLOAD, UNIVERSAL, require and eval, you can't.

    But you can get some impression of what's there by inspecting the ISA tree of the class, and walking the stashes of the class and its ISA inheritance tree, and see whether there are any code ref entries in the stashes. However, that doesn't distinguish between class private "normal" subroutines, and subroutines intended to be called as class or object methods.

    Perhaps your best option is to read the documentation of the object.

    Abigail

      Well, the documentation is shockingly deficient; I intend immediately to send a nasty email to the author.
      Errr... that'd be me. <g>

      Seriously, my issue is with C:MM (actually, my subclass of it):
      I think it created a list of Tables, but I can't seem to find them: $x->tables reports 'cannot find method "tables" at...'

      package Foo; use MakeMethods constructor => 'new', required => [qw(name title tables)], object_list => [ 'Table' => 'tables'];
      So thanks for advice.

      Any pointers around the monastery to a code snippet that does the walk you describe?
      Couldn't find any w/ SuperSearch or Google, trying not to reinvent wheels.

      Thanks, Abigail-II --

      rkg

        Here's something I quickly hacked together. It might need some work:
        #!/usr/bin/perl use strict; use warnings; my $class = shift; eval "use $class"; die $@ if $@; # First, find all the classes, and the ones it inherits. my %classes = ($class => 1); my @classes = ($class); while (@classes) { my $class = pop @classes; no strict 'refs'; foreach my $class (@{"$class\::ISA"}) { next if $classes {$class} ++; push @classes => $class; } } # Then find the subs in those classes. while (my $class = each %classes) { no strict 'refs'; print "From class '$class':\n"; while (my $entry = each %{"$class\::"}) { print "\t$entry\n" if defined &{"$class\::$entry"}; } } __END__
        Calling this with IO::File as argument gives:
        From class 'IO::Seekable': sysseek setpos croak confess getpos carp tell seek From class 'IO::File': qualify new confess ungensym open qualify_to_ref gensym croak new_tmpfile carp From class 'IO::Handle': qualify setvbuf format_write fcntl format_lines_per_page print sysread format_top_name input_record_separator SEEK_SET stat confess opened flush eof _open_mode_string syswrite error _IONBF format_formfeed format_page_number sync truncate constant croak SEEK_CUR gets carp fdopen getc untaint read new fileno clearerr write format_line_break_characters blocking format_name ungetc autoflush setbuf ioctl DESTROY ungensym _IOFBF qualify_to_ref _IOLBF output_record_separator gensym close getline output_field_separator printf formline format_lines_left SEEK_END printflush getlines input_line_number new_from_fd From class 'Exporter': export_fail export_tags export_ok_tags export import as_heavy require_version export_to_level
        I'm a long-time C::MM user and contributor, and at first glance, your code looks fine.

        You might want to double-check that the expected methods are being installed as you expect. You could add a logging install_methods in your subclass:

        sub install_methods { my ($class, %methods) = @_; my $target = $class->find_target_class; my $methods = join ', ', keys %methods; warn "Installing $methods in $target\n"; $class->SUPER::install_methods( %methods ); }
Re: OO: All Methods
by zentara (Archbishop) on Dec 15, 2003 at 16:59 UTC
    Hi, I'm no expert on OO, but I'm a good code librarian. Does this snippet help?
    #!/usr/bin/perl #given an arbitrary object, get a dump of all #the functions connected to the object. use CGI; my $obj = CGI->new(); print &dump_functions( $obj ); sub dump_functions { use Data::Dumper; use Class::Inspector; my ( $obj ) = @_; my ( $ref, $methods); $ref = ref $obj; $methods = Class::Inspector->methods( $ref, 'full', 'public' ); @{ $methods } = grep /$ref/, @{ $methods }; return Dumper( $methods ); } __END__

    OUTPUT:

    $VAR1 = [ 'CGI::AUTOLOAD', 'CGI::DESTROY', 'CGI::XHTML_DTD', 'CGI::add_parameter', 'CGI::all_parameters', 'CGI::binmode', 'CGI::cgi_error', 'CGI::charset', 'CGI::compile', 'CGI::croak', 'CGI::delete', 'CGI::escape', 'CGI::expand_tags', 'CGI::expires', 'CGI::import', 'CGI::init', 'CGI::initialize_globals', 'CGI::make_attributes', 'CGI::new', 'CGI::param', 'CGI::parse_params', 'CGI::print', 'CGI::put', 'CGI::read_from_cmdline', 'CGI::rearrange', 'CGI::save_request', 'CGI::self_or_CGI', 'CGI::self_or_default', 'CGI::to_filehandle', 'CGI::unescape' ];
Re: OO: All Methods
by Anonymous Monk on Dec 16, 2003 at 06:31 UTC
    Or you could just use Class::Inspector->methods

    OK, so that doesn't solve the AUTOLOAD situation, but it does deal with some of the weirder bits, like ignoring anonymous and overload stuff correctly.