views:

205

answers:

6

I have been thrust into taking over some code but I may be out of my element in figuring this one out. If someone could give me a hint I'd appreciate it. I'm enjoying learning this code but every now and then I need a push.

When looking through this code I came across this line:

 my @files = My::Module::DB::raw_info->search_like(customer_handle => $config->{client}, feed => $config->{site}, arrival =>"$date")

I know that this returns an array from a package called My::Module::DB::raw_info. What I'm not sure of, and I am just learning OOP (thanks to our developer getting fired), is what the "->search_like" refers to.

I didn't see that as a variable or as a subroutine in My::Module::DB::raw_info

Any hints would be appreciated. I'm only beginning to learn this stuff. It's like bathing in fire. (I know I'll be happier later though) Yikes!

+5  A: 

The likely cause of your conundrum is that My::Module::DB extends some other class. Look for a block along the lines of

use parent Some::Module;

or

BEGIN { extends Some::Module }

near the top of My/Module/DB.pm

Edit: As some commenters are helpfully pointing out below, there are a number of ways to subclass a Perl class, but these are probably the most common. (Maybe.)

Williham Totland
also "use base ..."
Arkadiy
"extends" is a Moose thing. =).
Kent Fredric
not use base ;_; , use parent !
Kent Fredric
Well, Moose might be in use, if you pardon the pun. ;) Answer updated to use parent.
Williham Totland
( although base exists, and has been around for a while, so you're likely to see that too, but if you see it, KILL IT, and use parent instead. base is full of cruft )
Kent Fredric
There are other ways to extend a class than use parent or extends. E.g. use base or direct @ISA change.
Alicia
@Alicia, @WWiliham - plus, there's AUTOLOADed methods
DVK
First off: WOW! I can't get over how absolutely helpful everyone has been with this question. Turns out it was that the code was extending something else, specifically (and this is going to be SO obvious when I mention it) Class::DBI. VERY public thanks to everyone but specifically to Williham Totland and DVK. You pushed in a new direction and I have learned something from your posts... JW
Jane Wilkie
+6  A: 

This is probably due to the method being inherited from a base class. However, in the extremely weird situations, it COULD also be injected into the module's namespace dynamically which is much harder to figure out.

You can find your sub either by brute force searching or by figuring out the base class of a module (and possibly higher up the inheritance chain) and searching just the base classes code. I will show how to do both:


Brute force search: This is probably the easiest solution in complicated cases since the sub could have been injected into the module's namespace dynamically by non-ancestor module and finding ancestor modules is not 100% easy due to multiple ways of defining inheritance that could have been used (use base, use parent, Moose stuff, AUTOLOADED stuff)

First, find out which other modules are loaded with My::Module

perl -e 'use My::Module::DB::raw_info; print "$INC{$_}\n" foreach keys %INC'

This will print the location of ALL those modules

Then, search for the sub definition in ALL that code (the following should be all one line, I split it up for readability into 2 lines):

grep search_like 
   `perl -e 'use My::Module::DB::raw_info; print "$INC{$_}\n" foreach keys %INC'`

If this returns too many results, change the grep to

grep "sub search_like"
   `perl -e 'use My::Module::DB::raw_info; print "$INC{$_}\n" foreach keys %INC'`

This will find you the definition in whichever module My::Module::DB::raw_info inherits from without actually analyzing the module code for inheritance.


Inheritance:

Find out the module's parent using ISA as follows:

perl -e 'use My::Module::DB::raw_info; print "@My::Module::DB::raw_info::ISA\n";'

To clarify, this only works for "classically inherited" modules using @ISA, not Moose stuff. It also doesn't work if the routine is called using AutoLoader or is injected into the symbol table dynamically which can happen in any code, not necessarily in the parent one.

DVK
::ISA won't help if A) its bolted on by an exporter B) its bolted on by a Moose role C) anything else that injects subs at any level in the inheritance tree.
Kent Fredric
@Kent - correct. Which is why I explicitly said "it COULD also be injected into the module's namespace dynamically which is much harder to figure out. " and offered - as the first method - the brute force grep of codebase. Why the downvote?
DVK
No downvote from me =). Although, granted, I did not see that =). I recall there being a way to poke into an individual sub to see where it came from, but its a bit rusty.
Kent Fredric
If its any consolation, I should karma myself down somewhat, for not properly RTFA -_-.
Kent Fredric
I'd give this +2 if I could.
Sorpigal
What is this supposed to do: `perl -e 'use My::Module::DB::raw_info::ISA."\n";'` ?
eugene y
@Eugene - Ughm... that DEFINITELY suffered from some copy/paste damage... good catch
DVK
@DVK: thanks so much for this advice... JW
Jane Wilkie
+1  A: 

The method may be defined in the superclasses of My::Module::DB::raw_info. Insert this line before the call to search_like:

print @My::Module::DB::raw_info::ISA;

Now look into these classes.

If this doesn't work, you can use Devel::Peek's Dump() to see where the subroutine came from:

use Devel::Peek;
Dump(\&search_like);

Look for GVGV::GV part in the output.

eugene y
::ISA won't help if A) its bolted on by an exporter B) its bolted on by a Moose role C) anything else that injects subs at any level in the inheritance tree
Kent Fredric
Kent Fredric
+1  A: 

Perhaps it's some inherited method. Read a little about Perl inheritance, search for some assignment to @ISA in your module definition.

leonbloy
::ISA is only helpful if it is inheriance which is causing it to exist. Compile-time sub-injection ( Exporter family, roles, etc ) will not be visible.
Kent Fredric
+1  A: 

In answer to "What I'm not sure of, and I am just learning OOP (thanks to our developer getting fired), is what the "->search_like" refers to.", search_like is a method of the raw_info class that takes name value pairs as its input parameters (Perl Cookbook section 10.7).

FYI, the other book I find very useful is Programming Perl.

David Harris
@David: I just cracked the Perl Cookbook open and I appreciate you offering this up..... JW
Jane Wilkie
+2  A: 

You can use the core Devel::Peek module to look at the internal data held in subroutine references.

To obtain a subroutine reference from an OO method, you use the ->can(...) method of all objects.

my $code_ref = My::Module::DB::raw_info->can('search_like');

and then you can print out the information:

use Devel::Peek 'Dump';

Dump($code_ref);

According to Devel::Peek's docs, you should get something like this:

A reference to a subroutine looks like this:

    SV = RV(0x798ec)
      REFCNT = 1
      FLAGS = (TEMP,ROK)
      RV = 0x1d453c
    SV = PVCV(0x1c768c)
      REFCNT = 2
      FLAGS = ()
      IV = 0
      NV = 0
      COMP_STASH = 0x31068  "main"
      START = 0xb20e0
      ROOT = 0xbece0
      XSUB = 0x0
      XSUBANY = 0
      GVGV::GV = 0x1d44e8   "MY" :: "top_targets"
      FILE = "(eval 5)"
      DEPTH = 0
      PADLIST = 0x1c9338

This shows that

  • the subroutine is not an XSUB (since START and ROOT are non-zero, and XSUB is zero);
  • that it was compiled in the package main;
  • under the name MY::top_targets;
  • inside a 5th eval in the program;
  • it is not currently executed (see DEPTH);
  • it has no prototype (PROTOTYPE field is missing).

So, COMP_STASH shows you where the code was compiled, and GVGV::GV shows you the sub's full name.

Eric Strom