6

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?

Axeman
  • 29,660
  • 2
  • 47
  • 102
Pistos
  • 23,070
  • 14
  • 64
  • 77
  • I already have my Perl class set up (with bless, etc.), so I don't need to be shown how to do that. – Pistos Jul 31 '09 at 19:55

4 Answers4

11

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
  • 53,118
  • 13
  • 86
  • 159
  • 1
    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 Aug 04 '09 at 13:21
  • Hash::Util::lock_hash_recurse is a fine solution, but I like the built in solution. – Dave Horner May 16 '17 at 04:36
8

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
  • 30,628
  • 10
  • 74
  • 122
  • 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 Jul 31 '09 at 20:37
  • 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 Jul 31 '09 at 20:39
  • 2
    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 Jul 31 '09 at 21:10
  • No, it's a package variable. Perl does not have "class variables". – jrockway Aug 02 '09 at 08:07
4

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
  • 116,958
  • 15
  • 196
  • 339
  • 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 Jul 31 '09 at 20:35
  • 4
    @Pistos http://perldoc.perl.org/perlfaq8.html#How-do-I-keep-my-own-module/library-directory%3F – Sinan Ünür Jul 31 '09 at 20:44
  • 1
    @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 Nov 04 '09 at 14:18
  • @Pistos: They do trust you with your script, right? You do not need to muck with the system `perl`. – Sinan Ünür Nov 04 '09 at 14:56
1

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

Cadoo
  • 807
  • 5
  • 13
  • 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 Jul 31 '09 at 20:10