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

I have been trying to get at some info in a symbol table without much luck, because the name of one of the packages is dynamic. This works fine:
print Dumper(\%main::some_package::);
But, if i dont know the name of some_package explicitly, its in a variable, how do i do this? i've tried many dereferences, like:
my $package_name = 'some_package'; print Dumper(\%main::{$package_name}::);
and various other variants with no luck. There has to be a way to do this, i've been trying for quite a while.

Thanks

Replies are listed 'Best First'.
Re: Symbol table dereference
by ysth (Canon) on Jul 28, 2004 at 23:10 UTC
    If $package_name is just a top level package, this is easy:

    First of all, the main symbol table %:: (aka %main::) is a hash; you want to look up the key named $package_name."::" (assuming $package_name doesn't already have the all-important trailing ::). This is just $::{$package_name."::"}.

    Now, the values in a symbol table are globs (with the exception of declared-but-not-defined subs, which are scalars giving prototype information); you want to get the hash reference out of the glob. This is done with the *FOO{THING} syntax (enclosing our FOO in {} since its an expression that evaluates to a glob, not a simple glob name): *{$::{$package_name."::"}}{HASH}.

    Voila:

    use strict; use Data::Dumper; my $package_name = "Data"; print Dumper *{$::{$package_name."::"}}{HASH};
    gives:
    $VAR1 = { 'Dumper::' => *{'Data::Dumper::'} };
    You can then go ahead and use that hash ref to get a nested package, look up a glob in it, and extract a hash reference from it:
    use strict; use Data::Dumper; my $top_level = "Data"; my $second_level = "Dumper"; print Dumper *{${*{$::{$top_level."::"}}{HASH}}{$second_level."::"}}{H +ASH}
    gives:
    $VAR1 = { 'Seen' => *Data::Dumper::Seen, 'post' => *Data::Dumper::post, 'Toaster' => *Data::Dumper::Toaster, 'Varname' => *Data::Dumper::Varname, 'pad' => *Data::Dumper::pad, 'Values' => *Data::Dumper::Values, 'Dumpf' => *Data::Dumper::Dumpf, 'new' => *Data::Dumper::new, '_sortkeys' => *Data::Dumper::_sortkeys, 'Pair' => *Data::Dumper::Pair, 'DESTROY' => *Data::Dumper::DESTROY, 'EXPORT_OK' => *Data::Dumper::EXPORT_OK, 'Pad' => *Data::Dumper::Pad, 'confess' => *Data::Dumper::confess, 'Deepcopy' => *Data::Dumper::Deepcopy, 'EXPORT_FAIL' => *Data::Dumper::EXPORT_FAIL, 'Sortkeys' => *Data::Dumper::Sortkeys, 'Freezer' => *Data::Dumper::Freezer, 'ISA' => *Data::Dumper::ISA, 'Terse' => *Data::Dumper::Terse, 'Maxdepth' => *Data::Dumper::Maxdepth, 'Dumpp' => *Data::Dumper::Dumpp, 'Useperl' => *Data::Dumper::Useperl, 'Dumpxs' => *Data::Dumper::Dumpxs, 'bootstrap' => *Data::Dumper::bootstrap, '_dump' => *Data::Dumper::_dump, 'qquote' => *Data::Dumper::qquote, 'Useqq' => *Data::Dumper::Useqq, 'BEGIN' => *Data::Dumper::BEGIN, 'Purity' => *Data::Dumper::Purity, 'Names' => *Data::Dumper::Names, 'Deparse' => *Data::Dumper::Deparse, 'EXPORT' => *Data::Dumper::EXPORT, 'DumperX' => *Data::Dumper::DumperX, 'croak' => *Data::Dumper::croak, 'Dump' => *Data::Dumper::Dump, 'import' => *Data::Dumper::import, 'Indent' => *Data::Dumper::Indent, 'Dumper' => *Data::Dumper::Dumper, 'Quotekeys' => *Data::Dumper::Quotekeys, 'Bless' => *Data::Dumper::Bless, 'carp' => *Data::Dumper::carp, 'VERSION' => *Data::Dumper::VERSION, 'Reset' => *Data::Dumper::Reset, 'Dumpperl' => *Data::Dumper::Dumpperl };
    and you can look up a particular symbol in that and use it. To call Data::Dumper::Dumper, for instance, you can say:
    use Data::Dumper; my $top_level = "Data"; my $second_level = "Dumper"; my $subname = "Dumper"; print &{*{${*{${*{$::{$top_level."::"}}{HASH}}{$second_level."::"}}{HA +SH}}{$subname}}{CODE}}(\%Data::);
    calls Data::Dumper::Dumper via the symbol table and prints:
    $VAR1 = { 'Dumper::' => *{'Data::Dumper::'} };
    Actually, a lot of the above can be much simplified, because of an odd rule that says you can put a glob where a reference of a particular type is wanted, and it automatically produces the reference to that part of the glob:
    use strict; use Data::Dumper; my $package_name = "Data"; print Dumper \%{$::{$package_name."::"}}; use strict; use Data::Dumper; my $top_level = "Data"; my $second_level = "Dumper"; print Dumper \%{${$::{$top_level."::"}}{$second_level."::"}}; use Data::Dumper; my $top_level = "Data"; my $second_level = "Dumper"; my $subname = "Dumper"; print &{${${$::{$top_level."::"}}{$second_level."::"}}{$subname}}(\%Da +ta::);
Re: Symbol table dereference
by Joost (Canon) on Jul 28, 2004 at 19:20 UTC
      Yep. Thanks much, i've been going nuts for hours!
Re: Symbol table dereference
by broquaint (Abbot) on Jul 29, 2004 at 03:06 UTC
    I'd recommend looking into qualify_to_ref from Symbol e.g
    use strict; use Symbol 'qualify_to_ref'; use Data::Dumper; my $tbl = qualify_to_ref('Data::Dumper::'); print Dumper *$tbl{HASH}; __output__ $VAR1 = { 'ISA' => *Data::Dumper::ISA, 'Useperl' => *Data::Dumper::Useperl, 'Sortkeys' => *Data::Dumper::Sortkeys, 'EXPORT_FAIL' => *Data::Dumper::EXPORT_FAIL, 'new' => *Data::Dumper::new, ...
    This neatly side steps the necessity of turning off strict 'refs' and jumping through various hoops to deal with nested package names.
    HTH

    _________
    broquaint

Re: Symbol table dereference
by stvn (Monsignor) on Jul 28, 2004 at 19:25 UTC

    You have to do it under no strict 'refs', and you make it basically a soft reference (variable resolved from a string). Also you need to watch how $package is in the string. This should work for you.

    my $package_name = 'some_package'; { no strict 'refs'; print Dumper(\%{"main::${package_name}::"}); }

    -stvn
Re: Symbol table dereference
by gaal (Parson) on Jul 28, 2004 at 19:18 UTC
    print +Dumper(\%{ $package_name . "::"});