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

I recently came a across a problem with an application that was saving configuration data as a hash in a file and using eval to load the data back. The problem was someone had created new entries by hand and had created duplicate keys. When I was running the code through the debugger, I could see that some keys were not being loaded into the hash, the duplicates were there. But I was missing some others.

I have 2 questions

My question is there some way of catching this error?

Can someone explain what was happening internally, that some hash entries where dropped?

its using Data::Dumper to save the hash and when it restore the data it slurps the file into a string and then executes  %hash = eval $line

Replies are listed 'Best First'.
Re: eval question
by choroba (Cardinal) on Jun 30, 2011 at 21:35 UTC
    The entries were probably not dropped, but overwritten:
    $hash{entry} = "will get lost"; $hash{entry} = "this will replace it"; print $hash{entry};
    In order to catch the error, you need to change the code that loads the values. Instead of $hash{$key} = $value you might use
    die "Error: duplicate value for $key\n" if exists $hash{$key}; $hash{$key} = $value;
    See also perldata, or even perldsc on how to store several values at the same key.
Re: eval question
by muba (Priest) on Jul 01, 2011 at 01:15 UTC

    It's hard to say without an example of what the configuration file looks like, or how you've written the code that loads it. But my best guess is that whoever put in those new entries manually, introduced some syntax errors.

    Assuming that your original configuration file looked something like this:

    { cat => "meow", cow => "moo", dog => "woof" }
    it's not so hard to imagine that commas were forgotten when the new entries where put in:
    { bird => "tweet" # note missing comma cat => "meow", cow => "moo", dog => "woof" # and here again pig => "oink" }

    Depending on how you loaded this hash (and the title of your post suggests that you use eval) then yeah, that could be the problem.

Re: eval question
by GrandFather (Saint) on Jul 02, 2011 at 01:34 UTC

    You may find it helpful to use something like YAML to load and save configuration information. It's not an immediate complete solution to your multiple entry problem, but consider the following:

    use strict; use warnings; use YAML; use Data::Dump; my %configHash = ( cat => 'Fred', dog => 'Joe', ); my $cfgFileContents = YAML::Dump(\%configHash); Data::Dump::dump (\%configHash); print $cfgFileContents; $cfgFileContents .= "cat: Bob\n"; # User added configuration entry my $loaded = YAML::Load($cfgFileContents); Data::Dump::dump ($loaded); $cfgFileContents = <<DATA; --- cat: - Fred - Bob dog: Joe DATA $loaded = YAML::Load($cfgFileContents); Data::Dump::dump ($loaded);

    Prints:

    { cat => "Fred", dog => "Joe" } --- cat: Fred dog: Joe { cat => "Fred", dog => "Joe" } { cat => ["Fred", "Bob"], dog => "Joe" }

    Note that the "User added configuration entry" gets lost (YAML specifies that there must be only one entry for each key in a hash and that additional entries will be ignored). However multiple values can be specified for a hash key if they are entries in a nested list, hence the nested array in the last line.

    True laziness is hard work