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

Hello Monks,

Do you know how to interpolate a variable that is read from a file? Below is my situation:

1. I have up to a hundred of simple hashes like this:

my %act = ("food" => "eat it", "drink" => "drink it", "Perl" => "play it");
All the hashes have the same keys. To keep the main source file clean, I leave all these hashes in a single file and require it at the head of the main source file.

2. In the main source file, I use all these hashes in this way:

my $item = "Perl"; my $out = "-p $act1{$item} -p $act2{$item} -p ... ";
but, the $out variable is so long that I want to keep it in another file because there are more than hundred of hashes. I do this by producing a one-line file like this:
-p $act1{$item} -p $act2{$item} ...

then I read this line into $out variable in the main source file. I thought Perl can interpolate the variable with their value. But, it turns out that Perl doesn't do this. The variable which contains the contend read from the file just keep all the variable as it is.

Er, I don't know if I explain this problem clear enough. And could someone help me out of this?

Replies are listed 'Best First'.
Re: Interpolation of variables read from a file
by Corion (Patriarch) on Dec 04, 2007 at 07:29 UTC

    Basically, you want a templating system. If you want to keep using the Perl hash syntax, I recommend the following approach:

    • Put all your %act hashes into a larger hash, say, %actions
    • Use a regular expression to interpolate the hash values:
    my %act1 = ( "food" => "eat it", "drink" => "drink it", "Perl" => "play it"); my %act2 = ( "food" => "prepare it", "drink" => "be drunk", "Perl" => "write it"); my %actions = ( act1 => \%act1, act2 => \%act2, ); my %vars = ( item => \$item, ); my $out = '-p $act1{$item} -p $act2{$item} -p ... '; # resp. read that one from a file # The world's simpled templating system: $out =~ s-\$(\w+) # the name of the hash (%act1) \{ # opening brace \$(\w+) # the name of the variable to be used ($item) \} # closing brace - { my $useritem = $vars{ $2 }; $actions{$1}{$useritem} }gxe;

    I haven't tested the code, so likely there are some syntax errors and errors with the specification of the regular expression - I hope that the comments help you enough to fix these.

      I think Corion's method is more suitable for me :-)

      But I find a "bad" way to make it, and I think this way is more efficient in mem and time :-(

      File: main.pl => the main source file
      require "all_hashes.pl"; # read in all the hashes our $item = "Perl"; # this $item must be global :-( require "template.pl"; # perl interpolates all the variable print $out; # $out is defined in template.pl #...
      File: template.pl
      my $out = "-p $act1{$item} -p $act2{$item} ...";
      File: all_hashes.pl => the file contains all the hashes
      my %act1 = ( "food" => "eat it", "drink" => "drink it", "Perl" => "play it"); my %act2 = ( "food" => "prepare it", "drink" => "be drunk", "Perl" => "write it"); #...
      It's bad, hardcoded and has many global variables, however, a simple and fast way :-(
Re: Interpolation of variables read from a file
by ikegami (Patriarch) on Dec 04, 2007 at 07:26 UTC
    What you need is called a templating system. You could roll out your own, use an existing one such as the Template Toolkit.
Re: Interpolation of variables read from a file
by wind (Priest) on Dec 04, 2007 at 07:32 UTC
    You can do it that way, but I suggest that you separate actual variable assignments from your data file, and instead just have a complex data structure.
    # data.pl ( act => { "food" => "eat it", "drink" => "drink it", "Perl" => "play it", }, act1 => { "foo" => "bar", "baz" => "biz", }, );
    Then in your code, you can iterate on keys instead of this hardcoded list.
    my %hash = do 'data.pl'; my $item = "Perl"; my $out = grep {-p $_->{$item}} values %hash ? 1 : 0;
    Or something to that effect.

    - Miller
Re: Interpolation of variables read from a file
by phio (Acolyte) on Dec 04, 2007 at 07:49 UTC
    Thanks all you guys! I love this place :-)