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

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

Ok so I'm using Github gists api from here.

I'm trying to get the filename and raw url of each gist, I'm halfway done, but hit an odd roadblock.

So far $gists[0]->{files} gives me the files portion of the gist. See the whole json structure here.

$gists[0]->{files} looks like this with Data::Dumper.:

$VAR1 = { 'main.html' => { 'language' => 'HTML', 'filename' => 'main.html', 'type' => 'text/html', 'size' => 713, 'raw_url' => 'THIS IS WHAT I WANT' } };

I get to the filename with this:

foreach my $g (@gists) { my @files = keys(%{$g->{files}}); my $file = $files[0]; # $file is now main.html print $g->{files}->{$file}->{raw_url}; # ^^ THIS doesn't work!!! }

It gives me this error:

Can't call method HASH(0x7f81c547aea8)'; without a package or object reference

So what am I doing wrong? Is it because there is a dot in the hashname? I've seen examples of strings being used as a hash key

Replies are listed 'Best First'.
Re: can't use certain hashnames when traversing a slightly complex hash
by Athanasius (Archbishop) on Jan 06, 2013 at 11:33 UTC

    Works OK for me:

    #! perl use strict; use warnings; my @gists = ( { files => { 'main.html' => { language => 'HTML', filename => 'main.html', type => 'text/html', size => 713, raw_url => 'THIS IS WHAT I WANT' } } } ); foreach my $g (@gists) { my @files = keys(%{$g->{files}}); my $file = $files[0]; print $g->{files}->{$file}->{raw_url}; }

    Output:

    21:28 >perl 472_SoPW.pl THIS IS WHAT I WANT 21:28 >

    The only difference a dot in the hash key makes is that the key has to be quoted under use strict.

    Can you provide a minimal example that demonstrates the problem you are seeing?

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

      Inside the loop, try this
      foreach my $g (@gists) { for my $filename( keys(%{$g->{files}}) ) { my $fref = $g->{files}{$filename}; # Simplify access to conten +ts ..( -> is optional betweeen "}{" ) print $fref->{raw_url}; last; # If you only want info for ONE file } }

                   "By three methods we may learn wisdom: First, by reflection, which is noblest; Second, by imitation, which is easiest; and third by experience, which is the bitterest."           -Confucius

      Bah! This is so ridiculous, I retyped the code when I was posting the question and ended up typing the code correctly!!

      The code was originally like this:

      print ->$g->{files}->{$file}->{raw_url};

      How do you usually figure the code for a hash traversal? I kept having to restart my webapp, Do you usually use the debugger and inspect the hash? I guess I really have to get used to the command line debugger

      Thanks so much for your replies dear monks! Sorry about the trouble! This is another pretty silly issue.

        How do you usually figure the code for a hash traversal?

        Not sure what you’re asking here, but for the record, the line:

        print $g->{files}->{$file}->{raw_url};

        can be simplified to:

        print $g->{files}{$file}{raw_url};

        because “The arrow is optional between brackets subscripts” (perlref#Using-References, point 3).

        Do you usually use the debugger and inspect the hash?

        No, I’d likely use Data::Dump or Data::Dumper, as in the OP.

        Anyway, glad the problem has been sorted. :-)

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

Re: can't use certain hashnames when traversing a slightly complex hash
by choroba (Cardinal) on Jan 06, 2013 at 12:27 UTC
    Perl is trying to run a method. It means there is
    $g->$key
    somewhere without the curlies around $key. Moreover, the $key does not contain a string, it is a hash reference. Post the real code that causes the error.
    لսႽ† ᥲᥒ⚪⟊Ⴙᘓᖇ Ꮅᘓᖇ⎱ Ⴙᥲ𝇋ƙᘓᖇ
Re: can't use certain hashnames when traversing a slightly complex hash
by sundialsvc4 (Abbot) on Jan 06, 2013 at 14:29 UTC

    Two tips:

    1. Always put hash-keys in literal strings, not barewords.   There’s more than one way to do it,™ so choose one way that works absolutely every time and, every time, do it in just that way.
    2. Always use use strict; use warnings; at the top of every module, and (almost) always, never accept any warnings to exist.

      "Always put hash-keys in literal strings, not barewords."

      BTW: I never did and i do not plan to do so in the future.

      Why should i?

      Update: Oops, sometimes reading helps...sorry!

      Update2: ...it was a mistake, yes. I posted too fast.

      Best regards, Karl

      «The Crux of the Biscuit is the Apostrophe»

Re: can't use certain hashnames when traversing a slightly complex hash
by AnomalousMonk (Archbishop) on Jan 06, 2013 at 15:41 UTC
    I get to the filename with this:

    foreach my $g (@gists) { my @files = keys(%{$g->{files}}); my $file = $files[0]; # $file is now main.html ... }

    One final note. The code quoted from the OP works as commented if and only if there is exactly one key in the  'files' sub-hash (and, of course, the name of the key is 'main.html'). If there are two or more keys, the 'order' of keys in the hash is not guaranteed whatsoever, so  'main.html' might be at index 0, index 1, ...

      Yep, it's all good. I simplified the code and the hash while posting.

      I'm always interested in the first entry of the files sub-hash. (The rest are forks of the original Github gist.)

      Thanks for looking out :)

        I'm always interested in the first entry of the files sub-hash.

        Hmmm...     Again, and just for the record, the  'files' sub-hash (or any hash) can be said to have a 'first' element if and only if it has exactly one element. The only true ordering in a hash (or associative array) is the association between key/value pairs.