Skip Menu |

This queue is for tickets about the Config-General CPAN distribution.

Report information
The Basics
Id: 53759
Status: resolved
Priority: 0/
Queue: Config-General

People
Owner: tlinden [...] cpan.org
Requestors: STOCKS [...] cpan.org
Cc:
AdminCc:

Bug Information
Severity: Normal
Broken in: 2.44
Fixed in: (no value)



Subject: Single-value arrays not properly converted from data structure to config syntax to data structure
If we start out with some data structure that contains a single-value array: { something => [ 'singlearrayvalue' ] } Then convert this to a Config::General string using save_string() something singlearrayvalue And then convert back to data structure using -String we will get: { something => 'singlearrayvalue' } The single array value is converted to a Scalar. The key issue here appears to be that there is no way to specify a single value array in the Config::General syntax, or if there is, it is not documented and does not convert back properly using save_string(). I have attached a test file to exemplify the issue. I am using Config::General syntax to store configuration for some modules. Some of these modules require options to be passed in as an arrayref, even if there is only one configuration option. For example: Cache::Memcached::Fast->new({ servers => [ '127.0.0.1:11211' ] }). It appears the -DefaultConfig option can be used to work around this issue but it seems like somewhat of a hack which _could_ cause issues in the future. I'm not sure the best way to solve this problem, but it appears something like the following would work: <block> hashkey [ 'singlevaluearray' ] </block>
Subject: single_value_array.t
#!/usr/bin/perl use strict; use warnings; use Config::General; use Data::Dumper; use Test::More tests => 1; use Test::Deep; my $conf = Config::General->new; my $orig_data_struct = { block => { hashkey => [ 'singlearrayvalue' ], }, }; # Convert data structure to config syntax string my $config_string = $conf->save_string($orig_data_struct); # Convert config syntax string back to data structure my $new_data_struct = { Config::General->new( -String => $config_string )->getall }; is_deeply( $orig_data_struct, $new_data_struct, 'Convert single array value from data struct to config and back works' );
I don't think this is a good idea. If I need such a feature (which is often the case), I do it this way: hosts = alba, codey, spock, lucile and use split() in my code to get an array from this. Also this looks more like a list to the user who may edit the config file.
Case closed. Btw this could even break existing code if implemented this way, e.g. someone using [] in their config would get an array instead of the expected scalar. Nope.
Subject: Re: [rt.cpan.org #53759] Single-value arrays not properly converted from data structure to config syntax to data structure
Date: Wed, 7 Apr 2010 17:52:19 -0400
To: bug-Config-General [...] rt.cpan.org
From: Robert Stockdale <robert.stockdale [...] gmail.com>
Right, so as I mentioned in my original post this probably wasn't the best solution, but I was just trying to get some discussion started... It seems kind of broken that the conversion methods produce different output than the source if you convert back. A POD update to note this caveat would be nice at the very least. Lastly, your workaround sounds OK, but I'm not a huge fan of copying and pasting code every time I need to do this. I was hoping there might be some elegant solution here... On Tue, Apr 6, 2010 at 4:08 AM, T. Linden via RT < bug-Config-General@rt.cpan.org> wrote: Show quoted text
> <URL: https://rt.cpan.org/Ticket/Display.html?id=53759 > > > Case closed. Btw this could even break existing code if implemented this > way, e.g. someone using [] in their config would get an array instead of > the expected scalar. Nope. >
-- Bob Stockdale robert.stockdale@gmail.com
Well, I see your point. What if we add a parameter which controls such a feature? I added such an option (using the [] scheme). Check out the attached patch (to 2.46).
Subject: force-array-2.46.patch
diff -rc Config-General-2.46/Changelog Config-General-2.47/Changelog *** Config-General-2.46/Changelog Thu Apr 8 11:24:22 2010 --- Config-General-2.47/Changelog Thu Apr 8 12:28:34 2010 *************** *** 1,3 **** --- 1,8 ---- + 2.47 + - fixed rt.cpan.org#53759 by adding new option -ForceArray. + when enabled a single config value enclosed in [] will become + an array forcefully. + 2.46 - fixed rt.cpan.org#56370: there was a sort() call in _store() left, which lead to sorted arrays even if -SaveSorted were diff -rc Config-General-2.46/General.pm Config-General-2.47/General.pm *** Config-General-2.46/General.pm Thu Apr 8 11:20:51 2010 --- Config-General-2.47/General.pm Thu Apr 8 12:23:52 2010 *************** *** 32,38 **** use Carp; use Exporter; ! $Config::General::VERSION = 2.46; use vars qw(@ISA @EXPORT_OK); use base qw(Exporter); --- 32,38 ---- use Carp; use Exporter; ! $Config::General::VERSION = 2.47; use vars qw(@ISA @EXPORT_OK); use base qw(Exporter); *************** *** 86,92 **** parsed => 0, # internal state stuff for variable interpolation files => {}, # which files we have read, if any UTF8 => 0, ! SaveSorted => 0 }; # create the class instance --- 86,93 ---- parsed => 0, # internal state stuff for variable interpolation files => {}, # which files we have read, if any UTF8 => 0, ! SaveSorted => 0, ! ForceArray => 0 # force single value array if value enclosed in [] }; # create the class instance *************** *** 864,876 **** } } else { ! # standard config option, insert key/value pair into node ! $config->{$option} = $this->_parse_value($config, $option, $value); ! if ($this->{InterPolateVars}) { ! # save pair on local stack ! $config->{__stack}->{$option} = $config->{$option}; ! } } } } --- 865,883 ---- } } else { ! if($this->{ForceArray} && $value =~ /^\[\s*(.+?)\s*\]$/) { ! # force single value array entry ! push @{$config->{$option}}, $this->_parse_value($config, $option, $1); ! } ! else { ! # standard config option, insert key/value pair into node ! $config->{$option} = $this->_parse_value($config, $option, $value); ! if ($this->{InterPolateVars}) { ! # save pair on local stack ! $config->{__stack}->{$option} = $config->{$option}; ! } ! } } } } *************** *** 1201,1212 **** foreach my $entry ( $this->{SaveSorted} ? sort keys %$config : keys %$config ) { if (ref($config->{$entry}) eq 'ARRAY') { ! foreach my $line ( $this->{SaveSorted} ? sort @{$config->{$entry}} : @{$config->{$entry}} ) { ! if (ref($line) eq 'HASH') { ! $config_string .= $this->_write_hash($level, $entry, $line); ! } ! else { ! $config_string .= $this->_write_scalar($level, $entry, $line); } } } --- 1208,1225 ---- foreach my $entry ( $this->{SaveSorted} ? sort keys %$config : keys %$config ) { if (ref($config->{$entry}) eq 'ARRAY') { ! if( $this->{ForceArray} && scalar @{$config->{$entry}} == 1 && ! ref($config->{$entry}->[0]) ) { ! # a single value array forced to stay as array ! $config_string .= $this->_write_scalar($level, $entry, '[' . $config->{$entry}->[0] . ']'); ! } ! else { ! foreach my $line ( $this->{SaveSorted} ? sort @{$config->{$entry}} : @{$config->{$entry}} ) { ! if (ref($line) eq 'HASH') { ! $config_string .= $this->_write_hash($level, $entry, $line); ! } ! else { ! $config_string .= $this->_write_scalar($level, $entry, $line); ! } } } } *************** *** 2154,2160 **** ! =head1 IDENTICAL OPTIONS You may have more than one line of the same option with different values. --- 2167,2173 ---- ! =head1 IDENTICAL OPTIONS (ARRAYS) You may have more than one line of the same option with different values. *************** *** 2229,2235 **** --- 2242,2257 ---- If turned off, Config::General will complain about multiple occurring options with identical names! + =head2 FORCE SINGLE VALUE ARRAYS + + You may also force a single config line to get parsed into an array by + turning on the option B<-ForceArray> on and by surrounding the value of the + config entry by []. Example: + + hostlist = [ foo.bar ] + Will be a singlevalue array entry if the option is turned on. If you want + it to remain to be an array you have to turn on B<-ForceArray> suring save too. =head1 LONG LINES *************** *** 2510,2516 **** =head1 VERSION ! 2.46 =cut --- 2532,2538 ---- =head1 VERSION ! 2.47 =cut diff -rc Config-General-2.46/t/run.t Config-General-2.47/t/run.t *** Config-General-2.46/t/run.t Thu Apr 8 11:23:14 2010 --- Config-General-2.47/t/run.t Thu Apr 8 12:27:19 2010 *************** *** 8,14 **** use Data::Dumper; ! use Test::More tests => 61; #use Test::More qw(no_plan); # ahem, we deliver the test code with a local copy of --- 8,14 ---- use Data::Dumper; ! use Test::More tests => 63; #use Test::More qw(no_plan); # ahem, we deliver the test code with a local copy of *************** *** 702,704 **** --- 702,715 ---- $cfg51 = new Config::General( -ConfigFile => "t/cfg.51.out", -InterPolateVars => 1 ); my %hash51new = $cfg51->getall(); is_deeply(\%hash51, \%hash51new, "compare saved config containing escaped chars"); + + + # check if forced single value arrays remain + my $cfg52 = new Config::General( -String => "habeas = [ corpus ]", -ForceArray => 1); + my %hash52 = $cfg52->getall(); + my @array52 = qw(corpus); + is_deeply($hash52{habeas}, \@array52, "check -ForceArray single value arrays"); + $cfg52->save_file("t/cfg.52.out"); + $cfg52 = new Config::General( -ConfigFile => "t/cfg.52.out", -ForceArray => 1); + my %hash52new = $cfg52->getall(); + is_deeply(\%hash52new, \%hash52, "check -ForceArray single value arrays during save()");
Subject: Re: [rt.cpan.org #53759] Single-value arrays not properly converted from data structure to config syntax to data structure
Date: Thu, 8 Apr 2010 20:21:50 -0400
To: bug-Config-General [...] rt.cpan.org
From: Robert Stockdale <robert.stockdale [...] gmail.com>
This looks great! It will definitely solve my issue and it will also not break any existing code so it looks like a win all around. I did notice a few small typos in the pod: "...into an array by turning on the option B<-ForceArray> on..." - too many 'on's "...remain to be an array you have to turn on B<-ForceArray> suring save too." - suring -> during Other than that it looks great! Thanks so much! Any idea when I can expect a release? Thanks again, -Bob On Thu, Apr 8, 2010 at 6:32 AM, T. Linden via RT < bug-Config-General@rt.cpan.org> wrote: Show quoted text
> <URL: https://rt.cpan.org/Ticket/Display.html?id=53759 > > > Well, I see your point. What if we add a parameter which controls such a > feature? I added such an option (using the [] scheme). Check out the > attached patch (to 2.46). >
-- Bob Stockdale robert.stockdale@gmail.com
Ok, added it to version 2.48.