Beefy Boxes and Bandwidth Generously Provided by pair Networks
more useful options
 
PerlMonks  

How to get function's name inside of CODE attribute

by menth0l (Monk)
on Oct 05, 2011 at 11:56 UTC ( #929767=perlquestion: print w/ replies, xml ) Need Help??
menth0l has asked for the wisdom of the Perl Monks concerning the following question:

Hi,

How can i get function name and/or it's path inside :CODE attribute's body? In Perl 5.12 im using approach like in the example below. My problem is that when ported to Perl 5.10 i get wrong function name.
package MyAttributes; use Attribute::Handlers; sub UNIVERSAL::FOO : ATTR(CODE) { my ($package, $symbol, $referent, $attr, $data) = @_; # in 5.12 i get "*Baz::bar" # in 5.10 i get "*MyAttributes::ANON" my $f = *$symbol; $f =~ tr/*//d; print "Function $f is has FOO attribute"; } package Baz; sub bar :FOO { ... } 1;
What's the proper way to do it (i'd like it to be portable between 5.10 and 5.12)?

Comment on How to get function's name inside of CODE attribute
Download Code
Re: How to get function's name inside of CODE attribute
by Anonymous Monk on Oct 05, 2011 at 12:10 UTC

    What's the proper way to do it

    Stay out of UNIVERSAL!

      Why? I need my attributes to be universal since i'm using it in different class/module trees across whole app.
Reaped: Re: How to get function's name inside of CODE attribute
by NodeReaper (Curate) on Oct 05, 2011 at 13:00 UTC
Re: How to get function's name inside of CODE attribute
by jandrew (Hermit) on Oct 05, 2011 at 15:14 UTC
    Maybe you would find Moose an interesting alternative to get the result you want (portable between 5.10 and 5.12). Check out Moose::Manual::MOP specifically and for a broader introduction Moose::Manual.
      Moose indeed is interesting but since I've already chosen Object::InsideOut as base for my app i don't want to mix those two.
Re: How to get function's name inside of CODE attribute
by chromatic (Archbishop) on Oct 05, 2011 at 16:49 UTC

    You can't always get a name (as attributes can apply to anonymous functions), but Sub::Information can help:

    use 5.014; use Sub::Information; use Attribute::Lexical 'CODE:FOO' => \&handle_foo_attr; sub handle_foo_attr { my ($func, $identifier, $attrs, $caller) = @_; my $info = Sub::Information->new( $func ); my $name = $info->name; say "Function '$name' has FOO attribute"; }

    I added in Attribute::Lexical to avoid the need to monkeypatch UNIVERSAL.


    Improve your skills with Modern Perl: the free book.

      I added in Attribute::Lexical to avoid the need to monkeypatch UNIVERSAL.

      You don't have to read much of the code before you get to:

      unshift @UNIVERSAL::ISA, "Attribute::Lexical::UNIVERSAL";

      So, this module avoids adding methods to UNIVERSAL (I assume), but adding a super class after the fact is certainly also monkey patching.

      (Yes, I actually implement attributes without monkey patching UNIVERSAL at all and much more simply and, IMHO, sanely and buttoning that up for CPAN is on my to-do list.)

      - tye        

        Yes, I actually implement attributes without monkey patching UNIVERSAL at all and much more simply and, IMHO, sanely and buttoning that up for CPAN is on my to-do list.

        Is the code sane enough for github? or some other public code hosting site? I would like to see this.

        -stvn

        I'm no fan of that myself, but it's less troublesome than putting all handlers in UNIVERSAL. I'll happily switch to a better solution that avoids modifying global behavior altogether.


        Improve your skills with Modern Perl: the free book.

      Using Sub::Information didn't help me. It works fine under 5.12 but has the same effect on 5.10 as in my previous example, i.e. $info->name returns empty string.
Re: How to get function's name inside of CODE attribute
by juster (Friar) on Oct 06, 2011 at 14:59 UTC

    I ran into this before (in perl 5.10) when messing around with attributes. The cause of your problems is that perl attributes are evaluated at compile time, before the subs are evaluated.

    Let me back up a bit. Attribute::Handlers is a wrapper around the simpler attribute handling logic in perl. This simpler attribute handling is described in the attributes module. When an attribute is used, perl calls the MODIFY_type_ATTRIBUTE method on the package who owns the sub or variable. In your case type is "CODE". The arguments passed to this method are the package name, coderef, and the attribute text (without the colon). The coderef is a placeholder that is later filled in after perl finishes compiling the sub. Until then, it is empty... ish.

    The only way I could think to do get the names would be to save the coderefs for examining later, when all the information is available. Then you can dissect them to get the information you want.

    use warnings; use strict; package FooAttr; use Devel::Peek qw(Dump); use B qw(); our @Subs; sub MODIFY_CODE_ATTRIBUTES { my ($pkg, $cref, @attrs) = @_; # Sucks in perl 5.10. Dump($cref); my @bad; for my $attr (@attrs){ if ($attr eq 'FOO') { push @Subs, $cref; } else { push @bad, $attr; } } return @bad; } # Add "FooAttr" to @UNIVERSAL::ISA at *compile-time*. # Otherwise Bar won't find MODIFY_CODE_ATTRIBUTES. BEGIN { push @UNIVERSAL::ISA, __PACKAGE__; } package Bar; use Devel::Peek qw(Dump); # This calls FooAttr::MODIFY_CODE_ATTRIBUTES at *compile-time*. sub baz :FOO {} # Keep in mind this is at runtime. Let's examine the same coderefs! for my $cr (@FooAttr::Subs) { Dump($cr); # This is what Sub::Identify[/Information] does but it # can also use C code to avoid the B module. my $gv = B::svref_2object($cr)->GV; printf "%s::%s\n", $gv->STASH->NAME, $gv->NAME; }

    There are zeroes at the top of the output where Devel::Peek's Dump is called by MODIFY_CODE_ATTRIBUTE and the filled in values at the bottom of the output are printed by the runtime code at the end of the Bar module. Keep in mind these are for the same code reference.

    Attribute::Handlers (which also adds to @UNIVERSAL::ISA) tries to convert the provided coderef to a symbol by examining all the symbols in the $pkg that is passed to MODIFY_CODE_ATTRIBUTES to see if they equal the coderef. This fails because the symbols are not yet populated in the package's symbol table. Again, this is because weird things are going on at compile-time, that I don't fully understand.

      This is very interesting but it seems it's an overkill for what i need.
      I think i'll just cut corners and add a new parameter to attribute with function name/path, i.e.:
      package FOO; sub foo :BAR (func => 'FOO::foo') { ... }

Reaped: Re: How to get function's name inside of CODE attribute
by NodeReaper (Curate) on Oct 09, 2011 at 12:35 UTC
Reaped: Re: How to get function's name inside of CODE attribute
by NodeReaper (Curate) on Oct 10, 2011 at 12:46 UTC

Log In?
Username:
Password:

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

How do I use this? | Other CB clients
Other Users?
Others drinking their drinks and smoking their pipes about the Monastery: (7)
As of 2014-07-23 05:07 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    My favorite superfluous repetitious redundant duplicative phrase is:









    Results (133 votes), past polls