in reply to Re^6: Config files
in thread Config files

qw(foo bar baz) means the same as ('foo', 'bar', 'baz'). The inner loop loops through the names of the options that you want to split.

The thing is that if you split everything that contains the delimiters you run into problems. You'd have to check all the time whether $config->{sectionName}{valueName} is a scalar or an array ref. That'd be inconvenient. So it's better to split the options that may contain multiple values (even if they don't in some case) and leave the others intact. So that you can be sure $config->{path}{root} is a string and $config->{path}{files} is an array (ref).

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

Replies are listed 'Best First'.
Re^8: Config files
by sparkel (Acolyte) on Dec 11, 2004 at 01:30 UTC
    Hi Jenda,

    Thanks for the response. Does that mean I need to hardcode the names of arrays that will be written in the config file to put them in the "qw()" ?

    So, if my config file contains:

    [one] size = 1,2,3,4 root = C:\test [two] colors = red,blue,green code = %root%\code1

    Then, having:

    use Config::IniHash qw(ReadINI); use Data::Dumper; $config = ReadINI('testiINI.ini', systemvars => 0, forValue => sub { my ($name, $value, $sectionname, $INIhashref) = @_; next if /^(#.*)?$/; $value =~ s{%(?:\[([^\]%]+)\])?([^%]*)%}{ print "for value: $value this is 1: $1 this is 2: $2 \n\n" +; if ($2 eq '') { '%' } elsif ($1 eq '') { $INIhashref->{$sectionname}{$2} } else { $INIhashref->{$1}{$2} } }ge; return $value; } ); foreach my $Section (values %$config) { foreach my $value ( qw( colors size ) ) { $Section->{$value} = [split /\s*,\s*/, $Section->{$value}]; } }

    I am not sure if that is what you meant...but I am not too sure what you said should go into the qw(). How does the code determine what is the scalar variable and what is an array? Thank you.

      You don't have to hardcode the names if you do not want to, but it's IMHO the best solution. There are basicaly three possible solutions.

      1. you can use the code above and specify what options allow multiple values. This way you know for sure that $config->{one}{root} is a string and $config->{one}{size} is an array. Which means you can safely write $path = $config->{one}{root} . "/processing.log"; and foreach my $size (@{$config->{one}{size}}) { ....
      2. You can split the values that contain the delimiters. This would allow the users to specify multiple values for any option in the INI file, the problem is that your script would have to be able to accept that. Otherwise you end up with $path (from the example in the previous solution) containing something like "ARRAY(0x14234234)/processing.log" which doesn't look too usefull to me. The same problem, just in the other direction would be with the "size" option, if the user did not specify several, the $config->{one}{size} would not be an array ref, but a string, so the foreach from the first solution would error out. I think this solution would complicate your script imensely.
      3. The last solution would be to split everything. Which means that $config->{sectionName}{optionName} would always be an array ref. And then if you had a use for just one value of an option you'd use $config->{sectionName}{optionName}[0] and if you wanted to do something with all of them you'd loop over @{$config->{sectionName}{optionName}}. The catch of this solution is that you might need to allow the delimiter in the value of some options. Or you would want to use a different delimiter for some options. Comma is fine if you are writing a list of color names, but is it so great for prices? What if the user enters prices=1,050? Did he/she mean two values, one and fifty or just one value, one thousand fifty?

      You can choose whichever solution you like best, but my choice would be 1) any day.

      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 suggestion. I think other than option 1, as you have suggested, other options would complicate a lot of things...and hence I'll specify the options that allow multiple values.

        If the config file contains:

        [path] root = C:\test code = %root%\code1 [array] files = hello.txt,hi.txt,howdy.txt dirs = %code%, %root%, %code%

        Then, for the "dirs" array, how can I change the following regular expression to find and store all values between %%..since there can be more than one (as seen in the dirs array)...

        $value =~ s{%(?:\[([^\]%]+)\])?([^%]*)%}{ if ($2 eq '') { '%' } elsif ($1 eq '') { $INIhashref->{$sectionname}{$2} } else { $INIhashref->{$1}{$2} } }ge;