Beefy Boxes and Bandwidth Generously Provided by pair Networks
Perl-Sensitive Sunglasses
 
PerlMonks  

Determining the fully qualified name of a global variable.

by clueless newbie (Friar)
on Jan 25, 2013 at 19:31 UTC ( #1015394=perlquestion: print w/ replies, xml ) Need Help??
clueless newbie has asked for the wisdom of the Perl Monks concerning the following question:

Here this clueless newbie asked "Can the fully qualified name of a global variable be determined?". Making use of Anonymous Monk's suggestion, this clueless newbie took a look at Devel::FindRef and jumped perhaps to an erronous conclusion.

Given that Globals.pm, Globals_A.pm, Globals_H.pm and Global_S are

package Globals; use Exporter; our @ISA=qw(Exporter); our @EXPORT=qw($Var $var @var %var); use Globals_S; use Globals_A; use Globals_H; use strict; use warnings; use vars qw($Var); $Var='$Var'; $var='scalar'; @var=qw(array array); %var=(hash=>1); 1;
package Globals_A; use Exporter; our @ISA=qw(Exporter); our @EXPORT=qw(@var); use strict; use warnings; use vars qw(@var); 1 __END__
package Globals_H; use Exporter; our @ISA=qw(Exporter); our @EXPORT=qw(%var); use strict; use warnings; use vars qw(%var); 1 __END__
package Globals_S; use Exporter; our @ISA=qw(Exporter); our @EXPORT=qw($var); use strict; use warnings; use vars qw($var); 1 __END__

This

#!/usr/bin/perl use strict; use warnings; #use Globals_S; use Globals_A; use Globals_H; use Globals; use vars qw($myvar @myvar); use Smart::Comments; use Devel::FindRef; use Xyzzy qw(FullyQualify); print "passing refs:\n"; print "\&FullyQualify is @{[FullyQualify(\&FullyQualify)]}.\n"; print "\$Var is ".join (' ',FullyQualify(\$Var)).".\n"; print "\%var is ".join (' ',FullyQualify(\%var)).".\n"; print "\@var is ".join (' ',FullyQualify(\@var)).".\n"; print "\$var is ".join (' ',FullyQualify(\$var)).".\n"; print "\nThe following is less reliable see the Devel::Symdump documen +ation\n"; print "passing strings:\n"; for (qw(FullyQualify Var var Globals::var)) { print "'$_' is @{[FullyQualify($_)]}\n"; } ; exit;

together with Xyzzy.pm

package Xyzzy; use Exporter; our @ISA=qw(Exporter); our @EXPORT_OK=qw(FullyQualify); use B; use B::Deparse; use Carp; use Devel::FindRef; use Devel::Symdump; use strict; use warnings; #use Smart::Comments; # Given a string or a ref # return its fully qualified name(s) sub FullyQualify { local *coderef=sub { eval { my $obj = B::svref_2object(shift); $obj->GV->STASH->NAME . "::" . $obj->GV->NAME; } || undef; }; #coderef: local *variableref=sub { (my $tmp=(grep {$_->[0] =~ m{^the global}} Devel::Find +Ref::find($_[0]))[0]->[0]) =~ s{^the global }{}; ### $tmp return $tmp; }; # variableref: unless (ref $_[0]) { # scalar my $name=shift(); my $module; if ($name =~ m{^(.+)::}) { # already qualified $module=Devel::Symdump->new($1); } else { # in this caller $module=Devel::Symdump->new(my $caller=(caller)[0]); $name=$caller.'::'.$name; }; my @return; if (grep {m{^$name$}} $module->functions()) { push(@return,coderef(eval '\&'.$name)) }; if (grep {m{^$name$}} $module->hashes()) { push(@return,variableref(eval '\%'.$name)) }; if (grep {m{^$name$}} $module->arrays()) { push(@return,variableref(eval '\@'.$name)) }; if (grep {m{^$name$}} $module->scalars()) { if (@return) { push(@return,variableref(eval '\$'.$name).'?'); } else { push(@return,variableref(eval '\$'.$name)); }; }; return @return; } else { my $ref=shift; if (ref $ref eq 'CODE') { unless (B::Deparse->new->coderef2text($ref) ne ';') { +# $ref is a ref to an autovivified sub Carp::cluck "FullyQualifySubName was passed a code +ref to a sub that has been autovivified!"; return undef; }; return coderef($ref); } elsif ((ref $ref) =~ m{^(?:ARRAY|HASH|SCALAR)$}) { return variableref($ref); } else { return "Your ref is a '@{[ref $ref]} ref'!"; }; }; }; __END__

gives

passing refs: &FullyQualify is Xyzzy::FullyQualify. $Var is $Globals::Var. %var is %Globals_H::var. @var is @Globals_A::var. $var is $Globals_S::var. The following is less reliable see the Devel::Symdump documenation passing strings: 'FullyQualify' is Xyzzy::FullyQualify $main::FullyQualify? 'Var' is $Globals::Var 'var' is %Globals_H::var @Globals_A::var $Globals_S::var? 'Globals::var' is %Globals_H::var @Globals_A::var $Globals_S::var?

This clueless newbie seeks coments on/improvements to Xyzzy.pm.

Comment on Determining the fully qualified name of a global variable.
Select or Download Code
Re: Determining the fully qualified name of a global variable.
by Athanasius (Monsignor) on Jan 27, 2013 at 03:44 UTC
    This clueless newbie seeks com[m]ents on/improvements to Xyzzy.pm.

    Well, OK, since you asked... ;-)

    • End every module with an explicit 1; to return a true value.

    • Closures are great, but why complicate the code when you don’t need to? In this case, named subroutines do the same job.

    • return undef; is redundant. From return:

      If no EXPR is given, returns an empty list in list context, the undefined value in scalar context, and (of course) nothing at all in void context.
    • Likewise in this construct:

      eval { my $obj = B::svref_2object(shift); $obj->GV->STASH->NAME . "::" . $obj->GV->NAME; } || undef;

      The block form of eval is used to trap exceptions, and “the value returned is the value of the last expression evaluated inside the mini-program” but “If there is a syntax error or runtime error, or a die statement is executed, eval returns undef in scalar context or an empty list in list context”. So the || undef is redundant here.

    • unless ... else ... is an unnecessary double negative. Just swap the blocks and the logic becomes clear.

    Here is my version of module Xyzzy.pm:

    Note that I have consolidated the 5 return statements into a single return at the end of sub FullyQualify. Not necessarily an improvement (although I am a big fan of structured programming), but in this case I think it makes the code easier to follow.

    Hope that helps,

    Athanasius <°(((><contra mundum Iustus alius egestas vitae, eros Piratica,

      unless ... else ... is an unnecessary double negative. Just swap the blocks and the logic becomes clear.

      LOL

      > 'return undef;' is redundant. From return:
      If no EXPR is given, returns an empty list in list context, the undefined value in scalar context, and (of course) nothing at all in void context.

      Sorry for nitpicking but it's not equivalent. =)

      In list context  return undef is true, cause a one-element list (undef) will be returned.

      DB<106> sub tst {return undef} DB<107> print "true" if ( @list=tst() ) true

      But empty returns are always false:

      DB<108> sub tst {return} DB<109> print "true" if ( @list=tst() ) DB<110>

      Cheers Rolf

Log In?
Username:
Password:

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

How do I use this? | Other CB clients
Other Users?
Others having an uproarious good time at the Monastery: (5)
As of 2014-07-28 08:39 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    My favorite superfluous repetitious redundant duplicative phrase is:









    Results (193 votes), past polls