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

Hi Jenda

Thank you for the reply. I understood:

@files = split /\s*,\s*/, $config->{path}{files};

If the arrays can occur at any place in the config file along with scalar values, I did not understand how the following code takes care of that

foreach my $Section (values %$config) { # $Section is a hash ref containing the values of the section, not th +e section name! foreach my $value (qw(files colors and other options that should be +arrays)) { $Section->{$value} = [split /\s*,\s*/, $Section->{$value}]; } }

Actually, I did not understand the following line:

foreach my $value (qw(files colors and other options that should be +arrays)) {

Thanks.

Replies are listed 'Best First'.
Re^7: Config files
by Jenda (Abbot) on Dec 11, 2004 at 01:17 UTC

    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

      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