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

I am a bits and pieces Perl programmer (if I can call myself that). I had a code segment where I was using anon hash. Now I need to move the initialization string to a file. So to build the hash I have to do some processing. Even though, this is weird, I need to ask. Is there a way I can just read a string and initialize a hash with the string directly.
#!/usr/bin/perl -w use strict; my $hash = {'MONTH' => 'January'}; print $hash->{MONTH} . "\n"; my $hashInitStr = "{'MONTH' => 'January'}"; # This would come from a f +ile my $hash1 = $hashInitStr; print $hash1->{MONTH} . "\n"
I now get
January Can't use string ("{'MONTH' => 'January'}") as a HASH ref while "stric +t refs" in use at ./anonHashfromStr.pl line 9.

Replies are listed 'Best First'.
Re: Initializing an anonymous hash
by davies (Monsignor) on Mar 30, 2012 at 15:35 UTC

    eval works for me.

    use strict; my $hash = {'MONTH' => 'January'}; print $hash->{MONTH} . "\n"; my $hashInitStr = "{'MONTH' => 'January'}"; # This would come from a f +ile my $hash1 = eval $hashInitStr; print $hash1->{MONTH} . "\n"

    returns

    Z:\Data\Perl>962633.pl January January Z:\Data\Perl>

    Regards,

    John Davies

    Update: Be aware that this has hideous security implications. Also, as Moritz explained to me in reply to Testing error handling that calls "die", there are two forms of eval. But the code given above does what I think you say you want.

      Thanks for your help and for introducing me to eval. I will do some reading.
Re: Initializing an anonymous hash
by tobyink (Canon) on Mar 30, 2012 at 18:57 UTC

    Unless the file is very locked down in terms of who is able to edit it, avoid using eval for this task like you'd avoid the plague.

    An untrusted user could just put, say:

    system("rm -fr $ENV{HOME}")

    ... into the file, and when you eval the file, that line will be executed, deleting your home directory and all its contents.

    The same incidentally goes for do and require. Unless you trust the file you're loading, don't do it.

    Much better would be to store your hash in a file format specifically designed for storing that sort of data. Namely, JSON or YAML.

    test.json
    { "MONTH": "January" }
    test.pl:
    use JSON qw(from_json); use File::Slurp qw(slurp); my $hash = from_json( ~~slurp('test.json') ); print $hash->{MONTH};
    perl -E'sub Monkey::do{say$_,for@_,do{($monkey=[caller(0)]->[3])=~s{::}{ }and$monkey}}"Monkey say"->Monkey::do'
Re: Initializing an anonymous hash
by zentara (Cardinal) on Mar 30, 2012 at 18:19 UTC
    I don't know how you are getting your data from the file read, but you can avoid the eval by massaging your input string creatively, then just add them to the anonymous hash.
    #!/usr/bin/perl -w use strict; my $hash = {'MONTH' => 'January'}; print $hash->{MONTH} . "\n"; my $string = q('MONTH' => 'January'); #from file # I split your original string, but there probably is a cleaner # way from your file read my @split = split / => /, $string; s/'//g for @split; print "@split\n"; my $hash1->{ $split[0] } = $split[1]; print $hash1->{MONTH} . "\n";
    Output:
    $ ./962633.pl January MONTH January January

    I'm not really a human, but I play one on earth.
    Old Perl Programmer Haiku ................... flash japh
      I was being lazy. The data file at the moment is quite safe. But that can change. I guess I could write small function to parse the string and create the hash and return it.
Re: Initializing an anonymous hash
by Khen1950fx (Canon) on Mar 30, 2012 at 16:28 UTC
    I tested it using eval as suggested by davies and Anonymous Monk's do:
    !/usr/bin/perl -l use strictures 1; use Devel::SimpleTrace; BEGIN { use strict 'refs'; use warnings; eval { do { my $hash = {MONTH => 'January'}; print $$hash{'MONTH'}; } } } BEGIN { use strict 'refs'; use warnings; eval { do { my $hashInitStr = {'MONTH' => 'January'}; my $hash1 = $hashInitStr; print $$hash1{'MONTH'}; } } }

      I tested it using eval as suggested by davies and Anonymous Monk's do:

      Nope

Re: Initializing an anonymous hash
by Marshall (Canon) on Mar 30, 2012 at 19:15 UTC
    Another approach is to just use one of the configuration modules, like perhaps Config::Tiny. This avoids the "execute user editable code" problems of eval and folks are familiar with the format. Its just 2 lines of code for the basics..

    #!/usr/bin/perl -w use strict; use Config::Tiny; use Data::Dumper; my $Config = Config::Tiny->read( 'configfile.txt') or die " $!"; # $Months here is a ref to a hash # my $Months = $Config->{Months}; print Dumper \$Months; =prints $VAR1 = \{ 'Month1' => 'January', 'Month2' => 'February' }; =cut __END__ #file configfile.txt contains this comment and this data #Sample Configuration File [Months] Month1 = January Month2 = February [Another_Section]
      Thanks to everyone for the wisdom. I have enough material now to make relatively wise choice of implementation for what I am trying to do.
Re: Initializing an anonymous hash
by Anonymous Monk on Mar 30, 2012 at 15:44 UTC
    Better than string eval, put the code in the file and do or require the file.
      In my situation, I need to read strings from a file as I moved some of this initialization to a data file. This is the only time I need to build a hash from the string. Rest of the data are just strings.