Beefy Boxes and Bandwidth Generously Provided by pair Networks
laziness, impatience, and hubris
 
PerlMonks  

How to find all the available functions in a file or methods in a module?

by szabgab (Priest)
on Nov 11, 2008 at 07:20 UTC ( [id://722795]=perlquestion: print w/replies, xml ) Need Help??

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

While we are still not exactly there with Padre but I would like to get your opinion on the issue.

Given a Perl script or a module or a class, how can one find the list of all the functions? Given an object - assuming I know which class it belongs to - how can one find out which methods are available to it?

I know the simple case is finding all the sub blabla {} entries and the general case cannot be solved and that I should use PPI for this anyway.

Can we define rules that assuming them we can find all the functions? Can we find better proximations?

For example:

  • If I have string eval in my code I know there can be anything injected.
  • If I use Class::Accessor then I can look for mk_accessors that will reveal the extra methods I have.
So what else should I check?

I know even if we collect all the method generator modules that are currently available on CPAN and support it, someone will upload a new one. But then we can just add support for that too.

So what virtual function generators are there?

What other kind of code (besides string eval) can generate methods on the fly? Can we recognize them in a reasonable way?

Update

After seeing the response of ikegami I see I have to make it clear I meant that I'd like to do it without running the code although, it might also be a good strategy to try to run code and get the information that way. The only problem can be with the source code of a missile launcher that might start the count-down in a BEGIN block.
  • Comment on How to find all the available functions in a file or methods in a module?

Replies are listed 'Best First'.
Re: How to find all the available functions in a file or methods in a module?
by ikegami (Patriarch) on Nov 11, 2008 at 07:57 UTC
    Have you searched CPAN for modules that walk the symbol table? The following will find all subs currently existing in a package. It can be expanded to walk the entire symbol table. It can be expanded to look at @ISA. There's no way to know whether the subs it finds are methods or not.
    use strict; use warnings; use Scalar::Util qw( reftype ); sub is_glob { for (@_ ? $_[0] : $_) { return reftype(\$_) eq 'GLOB'; } } sub get_subs { my ($pkg) = @_; my $symtab = \%::; for (split /::/, $pkg) { $symtab = $symtab->{"${_}::"} or return; } return grep is_glob($symtab->{$_}) && *{$symtab->{$_}}{CODE}, keys %$symtab; } print "$_\n" for sort +get_subs('Foo::Bar');

    Interesting tidbit: 'Foo::Bar' can be written as Foo::Bar::.

    What other kind of code (besides string eval) can generate methods on the fly? Can we recognize them in a reasonable way?

    Assignment of a sub ref to a glob.

Re: How to find all the available functions in a file or methods in a module?
by JavaFan (Canon) on Nov 11, 2008 at 08:30 UTC
    What other kind of code (besides string eval) can generate methods on the fly?
    AUTOLOAD is both a well known generator of methods/functions as a simulator. You might not find a Foo->bar() method while searching the stash, but that doesn't mean you can't call 'bar' on Foo. AUTOLOAD may handle that; sometimes by installing a Foo::bar and then calling it or by just taking care of itself.

    As for other ways beside string eval to generate methods, there's the assignment to the typeglob:

    *{"Foo::bar"} = sub {print "Hello, world"};
    or
    *{"Foo::bar"} = \&{"Baz::quux"};
    The latter is what typically happens at import time.
Re: How to find all the available functions in a file or methods in a module?
by jplindstrom (Monsignor) on Nov 11, 2008 at 13:44 UTC

    Obviously there isn't ever gonna be a 100% solution for a language as dynamic as Perl. Even if you had some kind of internal reflection capability at runtime, you can't account for an AUTOLOAD that hasn't been run yet. And for textual parsing you can't find dynamically created methods and attributes.

    In PerlySense I take a heuristic approach to identifying methods.(And I don't distinguish between methods and attributes.)

    Basically, Perl code has a lot of conventions and idioms. If it looks like Perl, let's assume it is Perl. So if you look at Perl code and see this, what would you say it looks like?

    $self->send_email();
    It looks like a method on the class for the current package. So let's assume that's what it is. In the same vein I take the shortcut of considering this a method/accessor:
    $self->{email} = $recipient_email;

    If PerlySense can't find an explicit declaration for a sub or attribute (mostly attributes), it will look for matching POD to display or navigate to.

    How you interpret things kinda depends on whether you consider false positives or false negatives worse. Maybe some positives are worse in some situations and negatives worse in others (possibly completions vs refactorings). Just looking at methods invoked on $self is not gonna find all of them, but static parsing of "sub" + $self->method and $self->{attribute} turns out to be pretty complete.

    When it comes to static parsing of syntax, I guess we'll need to write plugins to accompany module-introduced syntax for Moose, Class::Accessor, Class::MethodMaker, etc.

    I haven't done anything like that yet, but there's enough Moose classes in the code base at work that I'm really starting to miss a working "Go to Base Class" for the Moose stuff.

    /J

      Obviously there isn't ever gonna be a 100% solution for a language as dynamic as Perl...

      ...I guess we'll need to write plugins to accompany module-introduced syntax for Moose, Class::Accessor, Class::MethodMaker, etc.

      Hei J!

      I just had a similiar idea to switch the responsibility from the IDE to the modules author, so I paste my thoughts in reply to yours. 8 )

      From a bigger perspective ... IMHO the conceptionally best approach for IDEs would be to define an interface for authors to communicate which methods and subs their modules generate. So authors have the responsibility to export their tags.

      For instance an additional module for Class::Accessor, let's call it Class::Accessor::Tags may have the necessary parsing logic for the to-be-tagged module.

      Or maybe for more dynamic generations "::Tags" may just override subs like mk_accessors() in a way that executing the code doesn't really run but just produce the tag-infos.

      Saying this it's unlikely that module-authors will do this extra work just to support Padre and the OP would maybe not want to support all open IDE's like Emacs and Vi.

      So a general IDE-independent standard would be needed!

      UPDATES:

      Talking about "tags" it may seem that I'm favourizing the format of ctags or etags as appropriate interface (just look at the manpage *), but I'm not sure... not knowing a better alternative doesn't mean that there is no better choice. Anyway IMHO most IDEs support tag-files, making them to a de facto standard.

      * some links: http://en.wikipedia.org/wiki/Ctags http://ctags.sourceforge.net/

        Yes, an IDE neutral "standard" would be wonderful. Given the momentum of Padre at the moment, hope the lower layers of it will be fully reusable across other editors.

        Regarding exporting, I think that just declaring method names would be too limited for some uses.

        For instance, for refactorings (let's say "Rename Attribute"), the refactoring code needs to know not just the name, but which part of the source tree specifies the name.

        /J

Re: How to find all the available functions in a file or methods in a module?
by TGI (Parson) on Nov 11, 2008 at 19:13 UTC

    If you can come up with a 90% solution that covers traditional methods, Moose, Class::Accessor, and Class::Struct, I think you'll be in good shape.

    For the rest, provide an easy way for me to specify the methods and other information manually. Either in my code or in another file. For modules I get from CPAN or elsewhere, it would need to be in a separate file that I could reuse between projects (and hopefully share with others). For my own modules, I'd prefer to have a way to embed the infomation in my code, but a separate file would be OK, too.

    If you make it easy for me to build a plugin to provide automatic support for my personal method-maker du jour, so much the better.

    By the way, thanks for all the effort you are putting into this project.


    TGI says moo

Re: How to find all the available functions in a file or methods in a module?
by LanX (Saint) on Nov 11, 2008 at 14:11 UTC

    In many code-generating modules you don't need "running the code" completely but just compiling the code and then looking in the symboltable.

    Since this is not safe and code can be run doing this e.g. in begin-blocks you should give the user the responsibility to allow this kind of parsing.

    Once compiled you can use B::Deparse to inspect the code, occurences of $self are a good indicator for methods.

    But in terms of static parsing it will be very hard to improve the results of PPI or perltidy or general tools like etags.

(DUP) Re: How to find all the available functions in a file or methods in a module?
by ikegami (Patriarch) on Nov 11, 2008 at 07:58 UTC

    This node is duplicate. Please ignore.


    Have you searched CPAN for modules that walk the symbol table? The following will find all subs currently existing in a package. It can be expanded to walk the entire symbol table. It can be expanded to look at @ISA. There's no way to know whether the subs it finds are methods or not.

    use strict; use warnings; use Scalar::Util qw( reftype ); sub is_glob { for (@_ ? $_[0] : $_) { return reftype(\$_) eq 'GLOB'; } } sub get_subs { my ($pkg) = @_; my $symtab = \%::; for (split /::/, $pkg) { $symtab = $symtab->{"${_}::"} or return; } return grep is_glob($symtab->{$_}) && *{$symtab->{$_}}{CODE}, keys %$symtab; } print "$_\n" for sort +get_subs('Foo::Bar');

    Interesting tidbit: 'Foo::Bar' can be written as Foo::Bar::.

    What other kind of code (besides string eval) can generate methods on the fly? Can we recognize them in a reasonable way?

    Assignment of a sub ref to a glob.

      There's no way to know whether the subs it finds are methods or not.

      well, you can use B::Deparse on the subref and then regex for $self

      UPDATE: or something like $self and shift or @_ in the same line...

      OK "self" is only a convention but also human intelligence is relying on spotting $self or alike to recognise a method.

Re: How to find all the available functions in a file or methods in a module?
by ivanwillsau (Novice) on Nov 11, 2008 at 20:34 UTC
    There is another consideration for methods that are created via AUTOLOAD.

    I saw an article somewhere about (possibly user.perl.org or slashdot.org or an article some where on the O'Reilly sites) where someone was suggesting using tests as a way for determining what methods exist in dynamic language code, it wasn't Perl specific. When I read the article someone had responded that they had created a demo of the method using vim which may be of some help.

    Ivan

Re: How to find all the available functions in a file or methods in a module?
by Anonymous Monk on Nov 11, 2008 at 20:50 UTC
    You might find this link useful.. Help.pm

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://722795]
Approved by moritz
Front-paged by almut
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others imbibing at the Monastery: (4)
As of 2024-12-02 15:56 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found