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

I have a hash on 5 programs that gets used in all of them, the hash is the same and every time one element has to be added to the list I have to manually change all 5 programs, what's the best way to make this hash a external or separated file so I can only maintain one file instead of 5? Here is a hash example:
my %hash=( '000001' => 'ITEM _First', '000002' => 'Item B', '000003' => 'House', '000004' => 'Service C', '000005' => 'Service X', '000006' => 'Service Z', '00007b' => 'Adjust Area', '020902' => 'Campus', '0sdc45' => 'Unit C', '000011' => 'Unit B', '0wed45' => 'Lower Level', '0ws456' => 'Cars', '02100m' => 'Numbers' )

It would be nice if I could do this.
Thank you!

Replies are listed 'Best First'.
Re: Hash Question
by Taulmarill (Deacon) on Feb 17, 2004 at 15:17 UTC
    you could write your data to a text file and then read it into the programs.
    my %hash open FILE, "</path/to/your/data/file.csv"; while ( my $line = <FILE> ) { chomp $line; my ( $key, $data ) = split ";", $line; $hash{$key} = $data; }
Re: Hash Question
by blokhead (Monsignor) on Feb 17, 2004 at 16:43 UTC
    You've been shown some pretty high-tech solutions. But I think this would do what you want in a much simpler way:

    In a file named "shared-hash.dat":

    my %hash = ( '000001' => 'ITEM _First', '000002' => 'Item B', '000003' => 'House', '000004' => 'Service C', '000005' => 'Service X', '000006' => 'Service Z', '00007b' => 'Adjust Area', '020902' => 'Campus', '0sdc45' => 'Unit C', '000011' => 'Unit B', '0wed45' => 'Lower Level', '0ws456' => 'Cars', '02100m' => 'Numbers' );
    Now all you need to do in each program to get the data:
    my %hash = do "shared-hash.dat";
    All changes to the structure are made in one place: shared-hash.dat, in plain Perl syntax. For more info, see `perldoc -f do`. Of course, you're executing arbitrary Perl code, so make sure not just anyone can write to that datafile.

    If you need the programs to write back to the hash (and have those changes shared), you will have to do something a little more involved, but it didn't sound like that was the case from your description.

    blokhead

Re: Hash Question
by edan (Curate) on Feb 17, 2004 at 15:24 UTC

    You want to create a module. You'll probably want to read perlmod first. Here's a very basic example to get you started (untested):

    ############################ # filename: MyFirstModule.pm package MyFirstModule; our %common_codes_hash = ( '000001' => 'ITEM _First', '000002' => 'Item B', '000003' => 'House', # ....); 1; __END__ ######################## # filename: myscript1.pl use MyFirstModule; my $whatever = $MyFirstModule::common_codes_hash{$foo}; # .... __END__

    Later, you can get fancy by using Exporter to export your common data structures or functions into the script's namespace, and other things.

    Update: changed the my to our (realized the error at the same time as snowcrash).

    --
    edan (formerly known as 3dan)

      > my %common_codes_hash = (....);
      In the module, the file MyFirstModule.pm, %common_codes_hash should be declared with our instead of my. Otherwise it won't work if you put the module and script in two seperate files.
      itīs a matter of taste, but i whouldnīt store data in modules but in datafiles, textfiles, databases etc.
      modules are for sharing code, not data.
        Except when modules are for sharing data (HTTP::Status, Unicode::CharName , etc)
Re: Hash Question
by William G. Davis (Friar) on Feb 17, 2004 at 15:40 UTC

    Use DB_File or some other DBM module to create a DBM file that stores the hash on disk, then just have each script declare a hash and tie() it to the DBM file. Tying a hash changes its behavior; when you tie a hash to a DBM file, you can make the hash absorb the contents of the hash in the DBM file, make it so any changes to the hash also modify the hash in the DBM file, and other neat stuff depending on the DBM library.

    This code here creates the hash and stores it the hash.dbm DBM file:

    use DB_File; my %hash; tie (%hash, 'DB_File', 'hash.dbm', O_CREAT|O_RDWR) || die $!; %hash=( '000001' => 'ITEM _First', '000002' => 'Item B', '000003' => 'House', '000004' => 'Service C', '000005' => 'Service X', '000006' => 'Service Z', '00007b' => 'Adjust Area', '020902' => 'Campus', '0sdc45' => 'Unit C', '000011' => 'Unit B', '0wed45' => 'Lower Level', '0ws456' => 'Cars', '02100m' => 'Numbers' );

    Afterwards, any script that wants to manipulate the hash in hash.dbm need only just tie() the DBM file for reading and writing, like this:

    use DB_File; my %hash tie (%hash, 'DB_File', 'hash.dbm', O_RDWR) || die $!;

    then modifying %hash will result in modifying the hash stored in hash.dbm.

    If you want a hash in one script to be able to copy the contents of the hash in hash.dbm but not to actually modify it, then tie() the hash for reading only instead of for reading and writing:

    my %hash tie (%hash, 'DB_File', 'hash.dbm', O_RDONLY) || die $!;

    now modifying %hash won't affect the hash stored in hash.dbm.

Re: Hash Question
by flyingmoose (Priest) on Feb 17, 2004 at 19:53 UTC
    A clean way to serialize data to file is to use YAML. YAML is great.

    While less readable, Data::Dumper saves info in a Perl syntax but is part of the standard Perl install.

    I think most end-user-type folks would generally prefer to edit YAML by hand rather than Perl.