Beefy Boxes and Bandwidth Generously Provided by pair Networks
Just another Perl shrine
 
PerlMonks  

how to find the module of a specific function?

by rumpumpel1 (Novice)
on Oct 26, 2017 at 14:10 UTC ( [id://1202071]=perlquestion: print w/replies, xml ) Need Help??

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

let's look at the following code:

use TeamForge6; my $ctf = TeamForge6->new(proxy => 'http://forge.mysite.org',); my $session = $ctf->login($userid, $passwd);

how can I systematically find the module, in which the login function appears?

Replies are listed 'Best First'.
Re: how to find the module of a specific function? symbol table -- oneliner
by Discipulus (Canon) on Oct 26, 2017 at 16:16 UTC
    Hello rumpumpel1,

    you probably mean that TeamForge6 will use many other modules and you want to spot where login sub is located?

    For sure there are safer method, safer in respect to what i propose here, but..

    Symbol table has the information you want. Dealing with that is somehow dangerous but some module, for debugging task, can be helpful.

    For example Devel::Symdump can be used to inspect symbol table. The following oneliner search the whole symbol table, recursively and in any package for a function given in as $ARGV[0]

    perl -MDevel::Symdump -E "package A{sub asub{1}}package B::B{sub bsub{ +1}};; $sym=Devel::Symdump->rnew('main'); for $p($sym->packages){ for ($sym->functions($p)){die qq($_ found in package $p) if $_ +eq $p.'::'.$ARGV[0]} }" bsub B::B::bsub found in package B::B at -e line 1.

    PS sligthly modified the above to show that it recurse package names

    I have many evil links about symbol table at my homenode

    L*

    There are no rules, there are no thumbs..
    Reinvent the wheel, then learn The Wheel; may be one day you reinvent one of THE WHEELS.
Re: how to find the module of a specific *method*?
by LanX (Saint) on Oct 26, 2017 at 14:27 UTC
    > the module, in which the login function appears?

    Don't know what you mean with "appears" ..

    1. If you want to know which modules actually use this method (!) , ...

      ... you could use caller inside the method to report the locations at runtime.

      (not sure if applying B::Xref helps with methods)

    2. If you want to know where the method was defined ...

      ... you can might be able to use ->can to get the function's reference and use introspection with B to find the origin. (untested, will update code)

    Update
    • my $c_ref = $obj->can("method_name") will return the reference of the method
    • my ($file, $line) = get_code_location($c_ref) in Sub::Identify allows you to retrieve the original source location

    the latter can be done without extra module using some half cryptic B code, but I'm reluctant digging it out.

    IIRC an example can be found in the O'Reilly book "Perl Hacks" or google is your friend.

    Cheers Rolf
    (addicted to the Perl Programming Language and ☆☆☆☆ :)
    Je suis Charlie!

Re: how to find the module of a specific function?
by ikegami (Patriarch) on Oct 26, 2017 at 21:09 UTC

    To find the package in which the method was found:

    use mro qw( ); use Scalar::Util qw( blessed ); sub get_package { my ($obj, $method_name) = @_; defined( my $class = blessed($obj) ) or return undef; for my $pkg_name (@{ mro::get_linear_isa($class) }) { my $pkg = do { no strict qw( refs ); *{ $pkg_name.'::'.$method_name } }; return $pkg_name if *{$pkg}{CODE}; } return undef; }

    Note: Doesn't work if the method is autoloaded.


    To find the package in which the method was compiled:

    use B qw( svref_2object ); sub get_package { my ($obj, $method_name) = @_; my $method_ref = $obj->can($method_name) or return undef; return svref_2object($method_ref)->GV->STASH->NAME; }

    Note: Only works for autoloaded methods if can is properly overridden.

    Note: Works for methods implemented in XS.


    To find the file in which the method was compiled:

    use B qw( svref_2object ); sub get_package { my ($obj, $method_name) = @_; my $method_ref = $obj->can($method_name) or return undef; return svref_2object($method_ref)->FILE; }

    Note: Only works for autoloaded methods if can is properly overridden.

    Note: Only works well for Perl methods. For methods implemented in XS, it returns the name of the .c file with no path. For example, returns XS.c for JSON::XS->encode. (This may vary by system, and by XS loader.)

Re: how to find the module of a specific function?
by kcott (Archbishop) on Oct 26, 2017 at 19:55 UTC

    G'day rumpumpel1,

    "how can I systematically find the module, in which the login function appears?"

    In whatever OO hierarchy you have, it's entirely possible that any method could be present in more than one class. I'm going to assume you mean the class where the method is found first according to whatever method resolution order you're using. See "mro - Method Resolution Order" for more about that; and for any questions you might have regarding how I've used that pragma in the following code.

    #!/usr/bin/env perl use 5.010; use strict; use warnings; package A; sub new { bless {} => $_[0] } sub seen_once { 1 } sub seen_twice { 1 } sub seen_thrice { 1 } package A::B; use parent -norequire => 'A'; sub seen_twice { 1 } sub seen_thrice { 1 } package A::B::C; use parent -norequire => 'A::B'; sub seen_thrice { 1 } package main; use mro; my $instantiation_class = 'A::B::C'; my @methods = qw{seen_once seen_twice seen_thrice seen_never}; my $isa = mro::get_linear_isa($instantiation_class); my %found; say "Instantiation class: $instantiation_class"; my $obj = $instantiation_class->new; say 'Objects blessed into class: ', ref $obj; say 'Method Resolution:'; METHOD: for my $method (@methods) { next METHOD if exists $found{$method}; CLASS: for my $class (@$isa) { { no strict 'refs'; next CLASS unless exists ${$class . '::'}{$method}; } ++$found{$method}; say "$method()\tfound first in $class"; last CLASS; } unless (exists $found{$method}) { say "$method()\tNOT found in OO hierarchy!"; } }

    Output:

    Instantiation class: A::B::C Objects blessed into class: A::B::C Method Resolution: seen_once() found first in A seen_twice() found first in A::B seen_thrice() found first in A::B::C seen_never() NOT found in OO hierarchy!

    Update: After posting I thought the "Objects blessed into class: A" looked a bit odd; then realised I'd screwed up the constructor: "sub new { bless {} => __PACKAGE__ }". I've fixed that (now: sub new { bless {} => $_[0] }); after rerunning, the output now has "Objects blessed into class: A::B::C" (which looks somewhat saner). None of the other code or output has changed.

    — Ken

Re: how to find the module of a specific function?
by thanos1983 (Parson) on Oct 26, 2017 at 14:18 UTC

    Hello rumpumpel1,

    What do you mean by "systematically"? You mean to automate the process and reply back to use e.g. login in line 3 is a a method called from module "TeamForge6"?

    Give us a bit of more information it is not clear to "me at least" what you are asking.

    Update: After small research I think I understand what you mean. I think the module Devel::Peek will give you all the information you need. Kind of "similar question" Devel::Peek Dump() not printing out.

    BR / Thanos

    Seeking for Perl wisdom...on the process of learning...not there...yet!
Re: how to find the module of a specific function?
by Anonymous Monk on Oct 26, 2017 at 17:37 UTC
    In your example, login necessarily must be a method of the TeamForge6 object, defined somewhere in it or in its superclass(es), and you should be able to simply go to the appropriate .pm file to find it. If it is at-all difficult to do this reliably, then the design of the application's class structure should be reconsidered.
      In your example, login necessarily must be a method of the TeamForge6 object

      nope, TeamForge6->new can return whatever it wants

        One example of what anonymonk is getting at here (and yes, I've done this for legitimate purposes a few times that I can recall):

        use warnings; use strict; package Fraud; { sub new { return bless {}, shift; } sub login { print "HA-HA, I'm not who you think I am!\n"; } } package Trust; { sub new { return Fraud->new; } sub login { # recently was watching "That 70's Show" print "no login for you, dumbass\n"; } } package main; { my $obj = Trust->new; $obj->login; }

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others making s'mores by the fire in the courtyard of the Monastery: (3)
As of 2024-04-19 20:23 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found