views:

701

answers:

4

I want to do, in Perl, the equivalent of the following Ruby code:

class Foo
  MY_CONST = {
    'foo' => 'bar',
    'baz' => {
      'innerbar' => 'bleh'
    },
  }

  def some_method
    a = MY_CONST[ 'foo' ]
  end

end

# In some other file which uses Foo...

b = Foo::MY_CONST[ 'baz' ][ 'innerbar' ]

That is, I just want to declare a constant, nested hash structure for use both in the class and outside. How to?

+6  A: 

You can use the Hash::Util module to lock and unlock a hash (keys, values, or both).

package Foo;
use Hash::Util;

our %MY_CONST = (
    foo => 'bar',
    baz => {
        innerbar => 'bleh',
    }
);

Hash::Util::lock_hash_recurse(%MY_CONST);

Then in some other file:

use Foo;
my $b = $Foo::MY_CONST{baz}{innerbar};
Michael Carman
Thanks, Michael, this is exactly what I need. I tried to use lock_hashref, but it doesn't seem to be defined for me, but that's okay, I can make do with lock_hash.
Pistos
I notice I can accomplish what I need simply with "our", I don't need Hash::Util. I'm not concerned with other people messing with the hash after the fact, I simply needed to know how to define an accessible constant in Perl. Your example code showed me.
Pistos
So you don't really need a constant? The Hash::Util stuff is the magic that keeps people from changing the hash.
brian d foy
No, it's a package variable. Perl does not have "class variables".
jrockway
+1  A: 

Here is a guide to hashes in perl. Hash of Hashes

Cadoo
Thanks, thoughI've built nested hashes in general in Perl. My specific need has to do with using it both within and outside a package/class.
Pistos
+4  A: 

See Readonly:

#!/usr/bin/perl

package Foo;

use strict;
use warnings;

use Readonly;

Readonly::Hash our %h => (
    a => { b => 1 }
);

package main;

use strict;
use warnings;

print $Foo::h{a}->{b}, "\n";

$h{a}->{b} = 2;

Output:

C:\Temp> t
1
Modification of a read-only value attempted at C:\Temp\t.pl line 21
Sinan Ünür
Readonly is not installed on the system I'm using, and I'm not at liberty to freely install new modules. But thanks for your suggestion. I did come across that when googling.
Pistos
@Pistos http://perldoc.perl.org/perlfaq8.html#How-do-I-keep-my-own-module/library-directory%3F
Sinan Ünür
@Sinan: Thanks, but that doesn't help in my case. You might be mistaking my circumstances for those of a user on shared hosting or something. The barriers are not technical, they are social/political/managerial. :)
Pistos
@Pistos: They do trust you with your script, right? You do not need to muck with the system `perl`.
Sinan Ünür
+6  A: 

You can also do this entirely with builtins:

package Foo;
use constant MY_CONST =>
{
    'foo' => 'bar',
    'baz' => {
        'innerbar' => 'bleh',
    },
};

sub some_method
{
    # presumably $a is defined somewhere else...
    # or perhaps you mean to dereference a parameter passed in?
    # in that case, use ${$_[0]} = MY_CONST->{foo} and call some_method(\$var);
    $a = MY_CONST->{foo};
}

package Main;  # or any other namespace that isn't Foo...
# ...
my $b = Foo->MY_CONST->{baz}{innerbar};
Ether
Thanks, Ether. I am going to go with this syntax, since it lets me consistently use references everywhere. I would mark yours as the accepted answer, but it came a bit too late. :)
Pistos