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

Hello fellow monks,

update: I want to create a config file that people who don't know perl can update or change variables....hence I want to stay away from '$' or '.'

Is there a way I can substitute variables in a config file?

so since I will be using the root variable in a lot of places in the config file, instead of repeating 'C:\test', is there an easier way to substitute that in pathnames that contain that everywhere? In this way if I change the value of root at one place....I won't need to change it everywhere it appears

In a config file if I have the following:

[path] root = C:\test code = C:\test\code1

Is there a way I can substitute variables and hence don't need to repeat them everywhere like:

[path] root = C:\test code = $root . "\code1"

Thank you.

Replies are listed 'Best First'.
Re: Config files
by Jenda (Abbot) on Dec 07, 2004 at 01:43 UTC

    This is Perl, you can do anything. So desing whatever syntax will be most comfortable to your users. I usualy use %variablename% in config files and templates and so far it worked fine with my users. (As you can guess by now they are all Windows users.)

    If you happen to use Config::IniHash you can specify a function to be called for each option read and perform whatever transformations you like. Eg. if you wanted the users to use %foo% if they want to include the "foo" option in the current section and %[sec]foo% to include the "foo" option in the "sec" section. you could do it like this:

    use Config::IniHash qw(ReadINI); $config = ReadINI('c:\temp\zkINI.ini', systemvars => 0, forValue => sub { my ($name, $value, $sectionname, $INIhashref) = @_; $value =~ s{%(?:\[([^\]%]+)\])?([^%]*)%}{ if ($2 eq '') { '%' } elsif ($1 eq '') { $INIhashref->{$sectionname}{$2} } else { $INIhashref->{$1}{$2} } }ge; return $value; } ); use Data::Dumper; print Dumper($config);
    This of course assumes that you do not try to reference an option that was not yet specified :-)

    Jenda
    We'd like to help you learn to help yourself
    Look around you, all you see are sympathetic eyes
    Stroll around the grounds until you feel at home
       -- P. Simon in Mrs. Robinson

      Hi Jenda,

      Thanks for the response. That is exactly what I was looking for.

      I have been trying to go over your code (excellent code by the way) and the hash part is hard for me to understand.

      Could you please explain me how I can obtain the different values from the hash?

      Thanks.

        The thing returned by ReadINI() is a reference to a hash of hashes. This means that:

        • to access a specific value in a specific section: $config->{sectionName}{valueName}
        • to list the sections: foreach my $sectionName (keys %$config) {...
        • to list the values in a section:
          foreach my $name (%{$config->{sectionName}}) { print "$name = $config->{sectionName}{$name}\n"; }
          or
          for my $Section ($config->{sectionName) { foreach my $name (%$Section) { print "$name = $Section->{$name}\n"; }} or ...
        I think you should read the perlreftut and perldsc manpages.

        Jenda
        We'd like to help you learn to help yourself
        Look around you, all you see are sympathetic eyes
        Stroll around the grounds until you feel at home
           -- P. Simon in Mrs. Robinson

Re: Config files
by Old_Gray_Bear (Bishop) on Dec 07, 2004 at 01:00 UTC
    Take a look at Config::Simple and Config::Tiny.

    Config::Tiny in particular looks like a Windows .ini file --

    [section-name] var1=value1 var2=value2 [another section] var3=value3
    That should be relatively easy for 'non-Perl' users sensibilities.

    ----
    I Go Back to Sleep, Now.

    OGB

      yeah I am using this config style:

      But if I have :

      [section] var1=value1 var2=value1/value2 [another section] var3=value1/value3

      Since value1 is repeated so many times, how would you suggest I write the config file?

      So since:
      var1 = value1 and
      var2 = value1/value2

      Should I make
      var2 = var1 . '/value2' or
      var2 = var1 + /value2

      Hope I was clear...please let me know if you didn't understand.

      Thanks.

Re: Config files
by ikegami (Patriarch) on Dec 07, 2004 at 00:04 UTC
    Your question is impossible to answer without knowing what you use to read in your config file. However, I suspect the module you use is "dumb" and won't do what you want it to do. It's up to the program to do it.
    # Use the appropriate syntax for your module: my $root = ... my $code = ... my $include = ... my $lib = ... foreach ($code, $include, $lib) { s/%ROOT%/$root/gi; # -or- # # $code =~ s/%([A-Z][A-Z_]*)%/ # if ($1 eq 'ROOT') { # $root # } elsif (exists($ENV{$1})) { # $ENV{$1} # } else { # $1 # } # /eg }
      Basically I want to create a config file where the variables can be changed by people who don't know perl.

      So I was wondering...what is the best way to create the config file in terms of substituting variables that will be used over and over again in the config file.

      I just gave the example of the $root . '\code' , but is there a better way to subsititute the root variable in the config file?

      Thanks.

        If you're so concerned about the complexity the config file, why don't you write an interactive configuration utility?

        Back to the matter immedately at hand...

        You keep talking about the config file, while you should be talking about the module that reads the config file and the program that uses the module. If you used the code I posted earlier in this thread, you could write your config file as:

        [path] root = C:\test code = %root%\code1 include = %root%\include lib = %root%\lib

        instead of

        [path] root = C:\test code = C:\test\code1 include = C:\test\include lib = C:\test\lib

        It doesn't get any simpler (from the config file's perspective). What else do you want?

Re: Config files
by dragonchild (Archbishop) on Dec 07, 2004 at 00:41 UTC
    Use one of the bazillion config modules on CPAN. My favorite is Config::ApacheFormat, though that is by no means the best one for "dumb" people.

    Being right, does not endow the right to be rude; politeness costs nothing.
    Being unknowing, is not the same as being stupid.
    Expressing a contrary opinion, whether to the individual or the group, is more often a sign of deeper thought than of cantankerous belligerence.
    Do not mistake your goals as the only goals; your opinion as the only opinion; your confidence as correctness. Saying you know better is not the same as explaining you know better.

Re: Config files
by mifflin (Curate) on Dec 06, 2004 at 23:14 UTC
    maybe with eval
    # cat test.ini [path] root = C:\test code = $root . '\code1' # cat test.pl use Config::IniFiles; $ini = Config::IniFiles->new(-file => 'test.ini'); $root = $ini->val('path', 'root'); print "root = $root\n"; $code = $ini->val('path', 'code'); print "code = $code\n"; $code = eval $code; print "code = $code\n"; # perl test.pl root = C:\test code = $root . '\code1' code = C:\test\code1
    note that I had to change your double quotes to single quotes in the code ini file entry.

      I don't think it's wise to give the users so much power. Not only would eval"" let them run whatever code they want inside the application (which may or may not matter much) but it can also easily break the app in ways that will not be aparent to the user.

      Besides you will want them to be able to reuse whatever option they like, not just the "root". So they would either have to use

      [path] root = C:\test code = $ini->val('path', 'root') . '\code1'
      or something similar or you'd have to copy all the values into whatever package the eval""ed code runs in. Which is again not something you want to do.

      It's (IMnsHO) better to invent a special, more restricted syntax and parse it instead of eval""ing.

      Jenda
      We'd like to help you learn to help yourself
      Look around you, all you see are sympathetic eyes
      Stroll around the grounds until you feel at home
         -- P. Simon in Mrs. Robinson

      Hi,

      Thanks for the reply. Is there an easier way to use substitutions like I have used above. Something easy that people who don't know perl ( that is don't know what '$' or '.' is, can update, append or change the config file)

      Since I am repeating a lot of path names, I wanted to substitute those variables throughout the config file, so inorder to change all of them, only one change would be required.

      Thank you.