I often work on a huge, not-very-well-documented, object-oriented Perl repo at my place of employment. While maintaining the code, I frequently need to trace things that are inherited from other classes so that I can understand what they're doing. For example, I need to figure out what $self->mystery
is and what it's doing:
package Foo::Bar;
use Moose;
use Method::Signatures;
use Foo::Bar::Element;
use Foo::Bar::Function;
use base qw (Baz::Foo::Bar);
method do_stuff ($some_arg) {
# mystery is not defined in Foo::Bar
my $mystery = $self->mystery;
$mystery->another_mystery($some_arg);
}
I usually find myself spending way too much time tracing through parent classes. So my question is, is there an easy way for me to figure out where $self->mystery
comes from? Or in other words, I need to find where mystery is declared.
And by "easy way", I don't mean using ack
or grep
to string search through files. I'm hoping there's some sort of debugging module I can install and use which could help give me some insight.
Thank you.
comes_from
Method!You don’t need to download any special tool or module this, let alone some giant IDE because your undocumented class structure has gotten too complicated for mere humans ever to understand without a hulking IDE.
Why not? Simple: Standard Perl contains everything you need to get the answer you’re looking for. The easy way to find out where something comes from is to use the very useful comes_from
method:
$origin = $self->comes_from("mystery");
$secret_origin = $self->comes_from("another_mystery");
$birthplace = Some::Class->comes_from("method_name");
That will return the original name of the subroutine which that method would resolve to. As you see, comes_from
works as both an object method and a class method, just like can
and isa
.
Note that when I say the name of the subroutine it resolves to, I mean where that subroutine was originally created, back before any importing or inheritance. For example, this code:
use v5.10.1;
use Path::Router;
my($what, $method) = qw(Path::Router dump);
say "$what->$method is really ", $what->comes_from($method);
prints out:
Path::Router->dump is really Moose::Object::dump
Similar calls would also reveal things like:
Net::SMTP->mail is really Net::SMTP::mail
Net::SMTP->status is really Net::Cmd::status
Net::SMTP->error is really IO::Handle::error
It works just fine on plain ole subroutines, too:
SQL::Translator::Parser::Storable->normalize_name
is really SQL::Translator::Utils::normalize_name
The lovely comes_from
method isn’t quite built in though it requires nothing outside of Standard Perl. To make it accessible to you and all your classes and objects and more, just add this bit of code somewhere — anywhere you please really :)
sub UNIVERSAL::comes_from($$) {
require B;
my($invocant, $invoke) = @_;
my $coderef = $invocant->can($invoke) || return;
my $cv = B::svref_2object($coderef);
return unless $cv->isa("B::CV");
my $gv = $cv->GV;
return if $gv->isa("B::SPECIAL");
my $subname = $gv->NAME;
my $packname = $gv->STASH->NAME;
return $packname . "::" . $subname;
}
By declaring that as a UNIVERSAL
sub, now everybody who’s anybody gets to play with it, just like they do with can
and isa
. Enjoy!
Are you sure you don't want an IDE? It seems to be what you are asking about. Padre, Eclipse EPIC, Emacs , and vim and many other editors offer some variation on the features you mention - probably simpler than you seem to want. If you have big project to navigate ctags
can help - it's usually easy to integrate into an editor and you are allowed to hack on your configuration file (with regexes BTW) to get it to recognize bits of a complicated set of source files.
There is a related PERL FAQ entry about IDEs and a SO question: What's a good development environment for Perl?. There are also a host of CPAN modules you will want to use when developing that let you look into your code programmatically:
Devel::Kit
Devel::Peek
SUPER
Devel::Trepan
MooseX::amine
/ mex
You can see an example of a script that looks for methods in classes in the SO node: Get all methods and/or properties in a given Perl class or module.
You might be able to get tools like these to help you hop around in your source in a way you find useful from a shell or from inside the debugger. Trepan has a good short summary of debugging tools as part of its documentation. Generally though you can be very productive combining Data::Dumper
the B::
modules (B::Xref
, B::Deparse
, etc., etc.) with the debugger and ack
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With