http://www.perlmonks.org?node_id=1061399

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

I am trying to add fully declarative mappings between database functions and classes (I am also using Moo for declarative definition of properties). I would like to create a function has_dbmethod() which would have a similar syntax to has(), but would automatically generate wrapper functions for database functions. Now obviously I can't use __PACKAGE__ because I need it to be in the subclass's package, not the parent. So how can I detect the namespace of the subclass, at runtime, which calls this function?
  • Comment on How to programmatically determine package where a sub was called

Replies are listed 'Best First'.
Re: How to programmatically determine package where a sub was called
by kcott (Archbishop) on Nov 06, 2013 at 06:42 UTC

    G'day einhverfr,

    "So how can I detect the namespace of the subclass, at runtime, which calls this function?"

    It sounds like caller will do what you want. There's three ways to use this function, each returns the caller's package name as the first argument:

    $package = caller; ($package, $filename, $line) = caller; ($package, $filename, $line, $subroutine, $hasargs, $wantarray, $evaltext, $is_require, $hints, $bitmask, $hinthash) = caller($i);

    See the doco for full details.

    -- Ken

Re: How to programmatically determine package where a sub was called
by tobyink (Canon) on Nov 06, 2013 at 23:37 UTC

    kcott mentions caller which does indeed do what you want. However, it's worth mentioning that Moo doesn't use that technique.

    Instead, when you import the has keyword into your class, Moo builds a custom has function just for you, which always adds attributes to your class, no matter where it's called from. Demonstration:

    use v5.12; { package Foo; use Moo; { package Goo; # The caller here is "Goo". Foo::has( xxx => (is => 'ro') ); } } # But the attribute was created in "Foo"! say Foo->can('xxx');

    This is not as difficult as it sounds.

    Moose does more or less the same thing. Mouse doesn't; Mouse looks at caller.

    use Moops; class Cow :rw { has name => (default => 'Ermintrude') }; say Cow->new->name