diff --git a/Changelog b/Changelog index 0d151c9..f721dd1 100644 --- a/Changelog +++ b/Changelog @@ -1,3 +1,27 @@ + 2.00 - fixed a bug in the ::Extended::keys() method, which + caused a beloved "use of uninitialized ..." message. + Reported by Danial Pearce . + + - Removed all deprecated methods (in fact, they are still + there for shouting out a warn that its deprecated. But + the pod sections are removed. These are NoMultiOptions() + and save(). + + - added two new parameters to new(): -InterPolateVars and + -ExtendedAccess, which allows one to use the functionalites + of the supplied submodules without the need to decide + for one of them. This makes it possible to use variable + interpolation and oop access in the same time. Suggested + by Jared Rhine . + + - added new parameter -BaseHash which makes it possible + to supply your own hash which stores the parsed contents + of the config. This can be a tied hash o the like. + Suggested by Jared Rhine too. + + - switched to release 2.00 because the above is a major + change. + 1.36 - simplified new() parameter parsing, should be now a little bit better to understand. diff --git a/General.pm b/General.pm index 57a7572..190af06 100644 --- a/General.pm +++ b/General.pm @@ -17,7 +17,7 @@ use strict; use Carp; use Exporter; -$Config::General::VERSION = "1.36"; +$Config::General::VERSION = "2.00"; use vars qw(@ISA @EXPORT); @ISA = qw(Exporter); @@ -53,7 +53,15 @@ sub new { DefaultConfig => {}, + BaseHash => {}, + level => 1, + + InterPolateVars => 0, + + ExtendedAccess => 0, + + parsed => 0 }; # create the class instance @@ -93,8 +101,17 @@ sub new { $self->{content} = (); } delete $conf{-DefaultConfig}; + delete $conf{-BaseHash}; # ignore BaseHash if a default one was given } + if (exists $conf{-BaseHash}) { + if ($conf{-BaseHash}) { + # we do not check for ref() output because the hash could + # be something we are not expecting, a tied hash for example + $self->{DefaultConfig} = $conf{-BaseHash}; + } + delete $conf{-BaseHash}; + } # handle options which may either be true or false # allowing "human" logic about what is true and what is not @@ -124,35 +141,63 @@ sub new { else { # this happens if $#param == -1,1 thus no param was given to new! $self->{config} = {}; - return $self; - } - - ### use Data::Dumper; print Dumper($self); exit; - - # process as usual - if (exists $self->{StringContent}) { - # consider the supplied string as config file - $self->_read($self->{StringContent}, "SCALAR"); - $self->{config} = $self->_parse($self->{DefaultConfig}, $self->{content}); - } - elsif (ref($configfile) eq "HASH") { - # initialize with given hash - $self->{config} = $configfile; $self->{parsed} = 1; } - elsif (ref($configfile) eq "GLOB") { - # use the file the glob points to - $self->_read($configfile); - $self->{config} = $self->_parse($self->{DefaultConfig}, $self->{content}); + + + # process as usual + if (!$self->{parsed}) { + if (exists $self->{StringContent}) { + # consider the supplied string as config file + $self->_read($self->{StringContent}, "SCALAR"); + $self->{config} = $self->_parse($self->{DefaultConfig}, $self->{content}); + } + elsif (ref($configfile) eq "HASH") { + # initialize with given hash + $self->{config} = $configfile; + $self->{parsed} = 1; + } + elsif (ref($configfile) eq "GLOB") { + # use the file the glob points to + $self->_read($configfile); + $self->{config} = $self->_parse($self->{DefaultConfig}, $self->{content}); + } + else { + # open the file and read the contents in + $self->{configfile} = $configfile; + # look if is is an absolute path and save the basename if it is absolute + ($self->{configpath}) = $configfile =~ /^(\/.*)\//; + $self->_open($self->{configfile}); + # now, we parse immdediately, getall simply returns the whole hash + $self->{config} = $self->_parse($self->{DefaultConfig}, $self->{content}); + } } - else { - # open the file and read the contents in - $self->{configfile} = $configfile; - # look if is is an absolute path and save the basename if it is absolute - ($self->{configpath}) = $configfile =~ /^(\/.*)\//; - $self->_open($self->{configfile}); - # now, we parse immdediately, getall simply returns the whole hash - $self->{config} = $self->_parse($self->{DefaultConfig}, $self->{content}); + + # + # Submodule handling. Parsing is already done at this point. + # + if ($self->{InterPolateVars}) { + eval { + require Config::General::Interpolated; + }; + if ($@) { + croak $@; + } + $self->{regex} = Config::General::Interpolated::_set_regex(); + $self->{config} = Config::General::Interpolated::_vars($self, $self->{config}, {}); + } + if ($self->{ExtendedAccess}) { + # + # we are blessing here again, to get into the ::Extended namespace + # for inheriting the methods available overthere, which we doesn't have. + # + bless($self, "Config::General::Extended"); + eval { + require Config::General::Extended; + }; + if ($@) { + croak $@; + } } return $self; @@ -354,7 +399,16 @@ sub _parse { delete $config->{$option}; push @{$config->{$option}}, $savevalue; } - push @{$config->{$option}}, $this->_parse_value($option, $value); # it's already an array, just push + eval { + # check if arrays are supported by the underlying hash + my $i = scalar @{$config->{$option}}; + }; + if ($@) { + $config->{$option} = $this->_parse_value($option, $value); + } + else { + push @{$config->{$option}}, $this->_parse_value($option, $value); # it's already an array, just push + } } } } @@ -506,9 +560,7 @@ sub NoMultiOptions { # Since we do parsing from within new(), we must # call it again if one turns NoMultiOptions on! # - my($this) = @_; - $this->{AllowMultiOptions} = 0; - $this->{config} = $this->_parse({}, $this->{content}); + croak "The NoMultiOptions() method is deprecated. Set 'AllowMultiOptions' to 'no' instead!"; } @@ -729,6 +781,8 @@ sub SaveConfigString { } } + + # keep this one 1; @@ -979,15 +1033,32 @@ causes the module to preset the resulting config hash with the given values, which allows you to set default values for particular config options directly. +=item B<-InterPolateVars> + +If set to a true value, variable interpolation will be done on your config +input. See L for more informations. + +=item B<-ExtendedAccess> + +If set to a true value, you can use object oriented (extended) methods to +access the parsed config. See L for more informations. + +=item B<-BaseHash> + +You can supply a reference to a 'hash' which will be used to store the parsed +contents of your config file instead of the default standard perl hash. + +This is a way to affect the way, variable storing will be done. You could, for +example supply a tied hash, say Tie::DxHash, which preserves ordering of the +keys in the config (which a standard perl hash won't do). Or, you could supply +a hash tied to a DBM file to save the parsed variables to disk. + +There are many more things to do in tie-land, see L to get some interesting +ideas. =back -=item NoMultiOptions() -This method only exists for compatibility reasons and is deprecated. -Now you should set the parameter to the B method B<-AllowMultiOptions> to "no". - -see B. =item getall() @@ -995,11 +1066,6 @@ see B. Returns a hash structure which represents the whole config. -=item save() - -B - - =item save_file() Writes the config hash back to the harddisk. This method takes one or two @@ -1514,7 +1580,7 @@ Thomas Linden =head1 VERSION -1.36 +2.00 =cut diff --git a/General/Extended.pm b/General/Extended.pm index 9b5c4c3..d180970 100644 --- a/General/Extended.pm +++ b/General/Extended.pm @@ -14,15 +14,17 @@ use Config::General 1.18; use FileHandle; use Carp; -use vars qw(@ISA); +use Exporter (); +use vars qw(@ISA @EXPORT); # inherit new() and so on from Config::General -@ISA = qw(Config::General); +@ISA = qw(Config::General Exporter); +@EXPORT = qw(obj value hash array is_hash is_array is_scalar exists keys delete configfile); use strict; -$Config::General::Extended::VERSION = "1.5"; +$Config::General::Extended::VERSION = "1.6"; sub obj { @@ -154,12 +156,12 @@ sub keys { # it contains keys (so it must be a hash!) # my($this, $key) = @_; - if (exists $this->{config}->{$key} && ref($this->{config}->{$key}) eq "HASH") { - return map { $_ } keys %{$this->{config}->{$key}}; - } - elsif (!$key) { + if (!$key) { return map { $_ } keys %{$this->{config}}; } + elsif (exists $this->{config}->{$key} && ref($this->{config}->{$key}) eq "HASH") { + return map { $_ } keys %{$this->{config}->{$key}}; + } else { return (); } @@ -181,19 +183,21 @@ sub delete { } -sub save { - # - # save the config back to disk - # - my($this,$file) = @_; - my $fh = new FileHandle; - - if (!$file) { - $file = $this->{configfile}; - } - - $this->save_file($file); -} +# +# removed, use save() of General.pm now +# sub save { +# # +# # save the config back to disk +# # +# my($this,$file) = @_; +# my $fh = new FileHandle; +# +# if (!$file) { +# $file = $this->{configfile}; +# } +# +# $this->save_file($file); +# } sub configfile { @@ -253,63 +257,27 @@ sub DESTROY { Config::General::Extended - Extended access to Config files + =head1 SYNOPSIS - use Config::General::Extended; - $conf = new Config::General::Extended("rcfile"); - # or - $conf = new Config::General::Extended(\%somehash); + use Config::General; + + $conf = new Config::General( + -file => 'configfile', + -ExtendedAccess => 1 + ); =head1 DESCRIPTION -This module is a subclass of B. You can use it if -you want OO access to parts of your config file. The following methods -are directly inherited from Config::General: B. +This is an internal module which makes it possible to use object +oriented methods to access parts of your config file. -Please refer to the L, if you want to learn about the usage -of the two methods mentioned above. The possible format of config files supported -by this module is also well described in L. +Normally you don't call it directly. =head1 METHODS =over -=item new(filename) or new(\%somehash) - -This method returns a B object (a hash blessed into "Config::General::Extended" -namespace. All further methods must be used from that returned object. see below. - -Read a more detailed discussion on how to use the new() method in L. - - -=item NoMultiOptions() - -This method only exists for compatibility reasons. -Now you should set the new() flag B<-AllowMultiOptions> -to "no". - -Refer to L for details about this method. - -=item getall() - -Returns a hash structure which represents the whole config. - -If you use this method, then it would be probably -better to use the simpler module B. It is just mentioned here -for completeness. - - -=item save() - - -Writes the current config hash back to the harddisk. -It takes an optional argument: B. If you omit a filename, save() will -use the filename configured by the method B or B (see below). - -B: the method save() is now superseded by B and B. -Refer to L for details. You can use these new methods to save -a config either to a string or to a file. - =item configfile('filename') Set the filename to be used by B to "filename". It returns the current @@ -522,7 +490,7 @@ Thomas Linden =head1 VERSION -1.5 +1.6 =cut diff --git a/General/Interpolated.pm b/General/Interpolated.pm index 43f9c74..129755c 100644 --- a/General/Interpolated.pm +++ b/General/Interpolated.pm @@ -1,13 +1,16 @@ package Config::General::Interpolated; -$Config::General::Interpolated::VERSION = "1.0"; +$Config::General::Interpolated::VERSION = "1.1"; use strict; use Carp; use Config::General; +use Exporter (); + # Import stuff from Config::General -use vars qw(@ISA); -@ISA = qw(Config::General); +use vars qw(@ISA @EXPORT); +@ISA = qw(Config::General Exporter); +@EXPORT=qw(_set_regex _vars); sub new { # @@ -17,10 +20,24 @@ sub new { my $class = shift; my $self = $class->SUPER::new(@_); + $self->{regex} = $self->_set_regex(); + + $self->{config} = $self->_vars($self->{config}, {}); + + return $self; +} + + + +sub _set_regex { + # + # set the regex for finding vars + # + # the following regex is provided by Autrijus Tang # , and I made some modifications. # thanx, autrijus. :) - $self->{regex} = qr{ + my $regex = qr{ (^|[^\\]) # can be the beginning of the line # but can't begin with a '\' \$ # dollar sign @@ -31,17 +48,12 @@ sub new { \} # ... match closing curly ) }x; - - $self->{config} = $self->vars($self->{config}, {}); - - return $self; + return $regex; } - - -sub vars { +sub _vars { my ($this, $config, $stack) = @_; my %varstack; @@ -90,7 +102,7 @@ sub vars { # traverse the hierarchy part while (my ($key, $value) = each %{$config}) { # this is not a scalar recursive call to myself - $this->vars($value, {%{$stack}, %varstack}) + _vars($value, {%{$stack}, %varstack}) if ref($value) eq 'HASH'; } @@ -109,21 +121,20 @@ Config::General::Interpolated - Parse variables within Config files =head1 SYNOPSIS - use Config::General::Interpolated; - $conf = new Config::General::Interpolated("rcfile"); - # or - $conf = new Config::General::Interpolated(\%somehash); + use Config::General; + $conf = new Config::General( + -file => 'configfile', + -InterPolateVars => 1 + ); =head1 DESCRIPTION -This module is a subclass of B. You can use it if -your config file contains perl-style variables (i.e. C<$variable> -or C<${variable}>). The following methods are directly inherited -from Config::General: B. +This is an internal module which makes it possible to interpolate +perl style variables in your config file (i.e. C<$variable> +or C<${variable}>). +Normally you don't call it directly. -Please refer to the L for the module's usage and the -format of config files. =head1 VARIABLES @@ -193,15 +204,16 @@ L =head1 COPYRIGHT Copyright 2001 by Wei-Hon Chen Eplasmaball@pchome.com.twE. +Copyright 2002 by Thomas Linden . -This program is free software; you can redistribute it and/or +This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. See L =head1 VERSION -This document describes version 1.0 of B. +This document describes version 1.1 of B. =cut