tags:

views:

307

answers:

3

I know I can list all of the package and lexcial variables in a given scope using Padwalker's peek_our and peek_my, but how can I get the names and values of all of the global variables like $" and $/?

#!/usr/bin/perl

use strict;
use warnings;

use PadWalker qw/peek_our peek_my/;
use Data::Dumper;

our $foo = 1;
our $bar = 2;

{
    my $foo = 3;
    print Dumper in_scope_variables();
}

print Dumper in_scope_variables();

sub in_scope_variables {
    my %in_scope = %{peek_our(1)};
    my $lexical  = peek_my(1);
    #lexicals hide package variables
    while (my ($var, $ref) = each %$lexical) {
     $in_scope{$var} = $ref;
    }
    ##############################################
    #FIXME: need to add globals to %in_scope here#
    ##############################################
    return \%in_scope;
}
+4  A: 

You can access the symbol table, check out p. 293 of "Programming Perl" Also look at "Mastering Perl: http://www252.pair.com/comdog/mastering_perl/ Specifically: http://www252.pair.com/comdog/mastering_perl/Chapters/08.symbol_tables.html

Those variables you are looking for will be under the main namespace

A quick Google search gave me:

{
    no strict 'refs';

    foreach my $entry ( keys %main:: )
    {
        print "$entry\n";
    }
}

You can also do

*sym = $main::{"/"}

and likewise for other values

If you want to find the type of the symbol you can do (from mastering perl):

foreach my $entry ( keys %main:: )
{
    print "-" x 30, "Name: $entry\n";

    print "\tscalar is defined\n" if defined ${$entry};
    print "\tarray  is defined\n" if defined @{$entry};
    print "\thash   is defined\n" if defined %{$entry};
    print "\tsub    is defined\n" if defined &{$entry};
}
MGoDave
%main:: holds package variables like "our $foo", not global variables like $/.
Chas. Owens
I take it back, I just didn't recognize them because the are missing their sigils. Hmm, how to figure out if they are arrays, hashes, or scalars.
Chas. Owens
you can use the built-in 'ref' function to get the type of the symbol.
MGoDave
you don't need no strict 'refs'; if you say %main::, you only need it if you say %{'main::'}.
Chas. Owens
I'll edit the answer to address your concerns including typing
MGoDave
perl -le 'our $foo = 5; our @foo = qw/a b/; print ref $main::{foo}'
Chas. Owens
prints nothing, there is one entry for foo, which is a typeglob that will resolve to scalar or array depending on context. Hmm, I guess I should go look at how PadWalker is figuring that out.
Chas. Owens
look at my link, under the section "The symbol table", there is s simple test there
MGoDave
That appears to be copyrighted material, if it isn't posted there with brian d foy's permission please remove the link.
Chas. Owens
It is the author's site http://www252.pair.com/comdog/mastering_perl/
MGoDave
linked from the author's original site... I am re-adding the link
MGoDave
Then I certain hope it has his permission to be there (grin).
Chas. Owens
But seriously, read that chapter, I believe it will help at least give a foundation to what you are trying to do.
MGoDave
+2  A: 

You can do something like the following to check the symbol table of the main package:

{
    no scrict 'refs';

    for my $var (keys %{'main::'}) {
        print "$var\n";
    }
}
kbosak
oops, took too long to post and MGoDave got in before me with the answer. But be sure to include no scrict 'refs' if you're using strict or you'll get an error.
kbosak
Actually, turns out it was just the way I coded mine.. you can do it with strict the way your code is (ie. keys %main:: without quotes)
kbosak
Did you actually try that? %main:: does not contain global variables, only package variables declared in the main package. I am looking for the global variables like $/.
Chas. Owens
I did try and it does in fact contain global variables
MGoDave
I take it back, I just didn't recognize them because the are missing their sigils. Hmm, how to figure out if they are arrays, hashes, or scalars.
Chas. Owens
look at my answer, in the comments :)
MGoDave
A: 

And that does it. Thanks to MGoDave and kbosak for providing the answer in front of my face that I was too stupid to see (I looked in %main:: to start with, but missed that they didn't have their sigils). Here is the complete code:

#!/usr/bin/perl

use strict;
use warnings;

use PadWalker qw/peek_our peek_my/;
use Data::Dumper;

our $foo = 1;
our $bar = 2;

{
    my $foo = 3;
    print Dumper in_scope_variables();
}

print Dumper in_scope_variables();

sub in_scope_variables {
    my %in_scope = %{peek_our(1)};
    my $lexical  = peek_my(1);
    for my $name (keys %main::) {
        my $glob = $main::{$name};
        if (defined ${$glob}) {
         $in_scope{'$' . $name} = ${$glob};
        }

        if (defined @{$glob}) {
         $in_scope{'@' . $name} = [@{$glob}];
        }

        if (defined %{$glob}) {
         $in_scope{'%' . $name} = {%{$glob}};
        }
    }

    #lexicals hide package variables
    while (my ($var, $ref) = each %$lexical) {
        $in_scope{$var} = $ref;
    }
    return \%in_scope;
}
Chas. Owens
np, sometimes a push in the right direction is all that is needed.
MGoDave