Beefy Boxes and Bandwidth Generously Provided by pair Networks
laziness, impatience, and hubris
 
PerlMonks  

Re: accessing stashes

by choroba (Archbishop)
on Mar 01, 2019 at 17:11 UTC ( #1230722=note: print w/replies, xml ) Need Help??


in reply to accessing stashes

You can do that with the symbol table, but using defined and exists is cleaner.
#!/usr/bin/perl use warnings; use strict; use feature qw{ say }; { package My; sub one { print "123"; } sub two; } say ${My::}{one}; # *My::one say ${My::}{two}; # -1 say ${My::}{three}; # say defined *My::one{CODE}; # 1 say defined *My::two{CODE}; # 1 say defined *My::three{CODE}; # say exists &My::one; # 1 say exists &My::two; # 1 say exists &My::three; # say defined &My::one; # 1 say defined &My::two; # say defined &My::three; #

Update: added the first paragraph of says.

Update 2: Interestingly, a forward declared sub with prototypes returns the prototypes with the first syntax:

sub four (&@); # ... say ${My::}{four}; # &@

Update 3: ... unless you add an attribute, too, which makes it output the glob name.

sub five (&@) :method; say ${My::}{five}; # *My::five

Update 4: The -1 is printed only if you remove all other mentions of My::three, otherwise *My::three is printed.

map{substr$_->[0],$_->[1]||0,1}[\*||{},3],[[]],[ref qr-1,-,-1],[{}],[sub{}^*ARGV,3]

Replies are listed 'Best First'.
Re^2: accessing stashes
by ikegami (Pope) on Mar 01, 2019 at 19:12 UTC
Re^2: accessing stashes
by morgon (Priest) on Mar 01, 2019 at 18:45 UTC
    That comes close, but I want something like this (the code below does NOT work):
    use strict; sub hubba { } for my $symbol qw(hubba bubba) { print "$_: "; print defined *My::$symbol{CODE} ? "yep": "nope"; print "\n"; }
    That should print
    hubba: yep bubba: nope
    How can I do that?

      $My::{$symbol} returns a glob.

      *NAME{SLOT} accesses a glob's slot.
      *BLOCK{SLOT} accesses a glob's slot.
      *$NAME{SLOT} accesses a glob's slot.
      EXPR->*{SLOT} accesses a glob's slot.[1]

      So,

      my $glob = $My::{$symbol}; $glob && *{ $glob }{CODE} $glob && *$glob{CODE} $glob && $glob->*{CODE}

      1. Requires Perl 5.24+. Available in Perl 5.20+ by adding both use feature qw( postderef ); and no warnings qw( experimental::postderef );, or by adding use experimental qw( postderef );.

        Something changed in 5.22. $My::{$symbol} can return a code reference or -1 instead of a glob.

        The following is therefore needed:

        sub get_code_ref_by_fqn { # Fully qualified name my ($fqn) = @_; my @pkg_name_parts = split /::/, $fqn; my $symbol = pop(@pkg_name_parts); my $pkg = \%::; for (@pkg_name_parts) { $pkg = $pkg->{$_.'::'} or return undef; } my $glob_or_code = $pkg->{$symbol} or return undef; return $glob_or_code if ref($glob_or_code); return undef if ref(\$glob_or_code) ne 'GLOB'; return *$glob_or_code{CODE}; }

        But you know what, let's just leave those dirty details to Perl.

        sub get_code_ref_by_fqn { # Fully qualified name my ($fqn) = @_; no strict qw( refs ); return undef if !defined(&$fqn); return \&$fqn; }

        Above tested using

        use 5.012; use warnings; sub Foo::Bar::y; sub Foo::Bar::z { } say get_code_ref_by_fqn('Foo::Bar::x') // '[undef]'; say get_code_ref_by_fqn('Foo::Bar::y') // '[undef]'; say get_code_ref_by_fqn('Foo::Bar::z') // '[undef]';
        This is *exactly* what I was looking for - would you be so kind to rewrite my script above with your syntax (am interested in package "main") as I seem to be too drunk to do it myself and my attempts don't compile...

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: note [id://1230722]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others romping around the Monastery: (5)
As of 2021-03-03 22:17 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?
    My favorite kind of desktop background is:











    Results (96 votes). Check out past polls.

    Notices?