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.
| [reply] [Watch: Dir/Any] [d/l] [select] |
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. | [reply] [Watch: Dir/Any] [d/l] [select] |
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
| [reply] [Watch: Dir/Any] [d/l] [select] |
|
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/
| [reply] [Watch: Dir/Any] |
|
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
| [reply] [Watch: Dir/Any] |
|
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.
| [reply] [Watch: Dir/Any] |
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.
| [reply] [Watch: Dir/Any] |
(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.
| [reply] [Watch: Dir/Any] [d/l] [select] |
|
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.
| [reply] [Watch: Dir/Any] |
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 | [reply] [Watch: Dir/Any] |
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 | [reply] [Watch: Dir/Any] |