Config::General::Hierarchical - Hierarchical Generic Config Module
Simple use
use Config::General::Hierarchical; # my $cfg = Config::General::Hierarchical->new( file => $filename ); my $value = $cfg->_ConfigurationVariableName;
Full use
package MyConfig; # use base 'Config::General::Hierarchical'; # sub syntax { ... }
This module provides easy ways to achieve three goals: to read configuration values that are organized in complex structures and stored in a hierarchical structure of files, to access them, and to define syntax and structure constraints.
To make the structure constraints easy to be managed, a good way is to force the configuration structure to a tree of named nodes; each one can be either a parent node or a value node, if a value can be a string or an array of strings then this structure can be aesily stored in an perl hash where for each key can be stored a reference to another hash, a reference to an array of scalars or a scalar.
This configuration example
<db> <*> tout 300 </*> <customers> host customersdb.${DBServersDomain} name customersdb user customerslogin pass customerspwd </customers> <products> host productsdb.${DBServersDomain} name productsdb user productslogin pass productspwd tout 600 </products> <users> host usersdb.${DBServersDomain} name usersdb user userslogin pass userspwd </users> </db> DBServersDomain my.domain
is equivalent to this code
my $cfg = { db => { customers => { host => 'customersdb.my.domain', name => 'customersdb', user => 'customerslogin', pass => 'customerspwd', tout => 300, }, products => { host => 'productsdb.my.domain', name => 'productsdb', user => 'productslogin', pass => 'productspwd', tout => 600, }, users => { host => 'usersdb.my.domain', name => 'usersdb', user => 'userslogin', pass => 'userspwd', tout => 300, }, }, DBServersDomain => 'my.domain', };
For the purpose to read and to parse configuration files Config::General is used, so it is better if you introduce yourself to that module before going on reading this chapter: it is written assuming that the reader knows how Config::General reads and parses files.
Config::General
This is how Config::General::Hierarchical inizializes the Config::General object.
Config::General::Hierarchical
Config::General->new( '-AllowMultiOptions' => 1, '-AutoTrue' => 0, '-BackslashEscape' => 0, '-CComments' => 0, '-ConfigFile' => $filename, '-ExtendedAccess' => 0, '-InterPolateEnv' => 0, '-InterPolateVars' => 0, '-MergeDuplicateBlocks' => 1, '-MergeDuplicateOptions' => 0, '-SlashIsDirectory' => 0, '-UseApacheInclude' => 0, );
Inizializing the Config::General module with both the parameters -MergeDuplicateBlocks and -AllowMultiOptions to true and -MergeDuplicateOptions to false, it reads and parses the file in a structure respecting the structure constraint. Beeing this module written for configuration file, neithr -ConfigHash nor -String are used, but -ConfigFile is used for each file to read. The parameters -AutoLaunder, -CComments, -LowerCaseNames, -SplitDelimiter and -SplitPolicy are presetted or unsetted, but left at your control: new() methot proxies theese parameters.
-MergeDuplicateBlocks
-AllowMultiOptions
-MergeDuplicateOptions
-ConfigHash
-String
-ConfigFile
-AutoLaunder
-CComments
-LowerCaseNames
-SplitDelimiter
-SplitPolicy
new()
An overview on other Config::General parameters:
-AutoTrue
0: this module provides its own way to normalize and check theese values
-BackslashEscape
0: this module provides its own way to interpolate backslashes
-DefaultConfig
not used: I think this is not a usefull option for the purpose to read more than one file
-ExtendedAccess
0: this module provides its own easy way to access data
-FlagBits
not used yet: TODO
-InterPolateEnv
-InterPolateVars
0: this module provides its own way to interpolate values
-SlashIsDirectory
0: we don't need to be compliant with apache
-Tie
-UseApacheInclude
0: this module provides its own way to include other files: the inherits directive; other parameters changing the include beheavure of Config::General are simply not used and not mentioned as well
All theese methods (execpt for the new() one) are for internal use, but having you probably to write a class that hinerits this one, it can be a good thing if you know how the module works.
$cfg = Config::General::Hierarchical->new( %options );
Returns a new constructed Config::General::Hierarchical object.
Some %options can be specified by and hash.
%options
Proxied to Config::General.
check
This make the new() method to implicitally call the check() method as well.
check()
file
This make the new() method to implicitally call the read() method as well.
read()
inherits
Redefines the default inherits syntax of the same directive.
undefined
Redefines the default undefined syntax of the same directive.
wild
It defines the wild string. By default it values '*'. If used as key of any node (etiher in configuration or in the syntax constraint), the relative value is used as default value (or syntax) for every key requested for that node.
'*'
$cfg->check;
If it does not die, returns the node itself.
This mothod calls the get() method for each key of the node with two effects: if the method returns, all the variables for that node respect the syntax constraint, all the values are now cached.
get()
import()
use Config::General::Hierarchical;
This mothod performs the checks on the correct usage of the syntax method. This means that if there is an error in the syntax constraint it is notifeied to the developer at compile time.
my $value = $cfg->get( 'VariableName' ); # alias my $value = $cfg->_VariableName; my $value = $cfg->get( 'VariableName', 'SubNode' ); # alias my $value = $cfg->_VariableName->get( 'SubNode' ); # alias my $value = $cfg->_VariableName->_SubNode; my $value = $cfg->get( 'VariableName', ... ); # alias my $value = $cfg->_VariableName( ... );
Returns the value of the configuration variable VariableName.
VariableName
Accessing configuration data by this method you can be sure that the returned value respects the syntax constraint, if this is not the case, a die() is called and any value is returned. You can be sure as well that the returned value has the appropriate type defined by the syntax constraint, this means that when a configuration variable is defined as a node getting its value you will obtain a reference to a Config::General::Hierarchical object, when it is defined as an array you will obtain a reference to an ARRAY (even if empty), otherwise you will get a scalar.
die()
ARRAY
A quicker to write way to access data is provided with AUTOLOAD mothod: you can get the value of a variable by calling that method called as the name of the variable prependend by an underscore.
AUTOLOAD
getk()
my @keys = $cfg->getk;
This mothod returns the array with all the keys configured in the configuration files for the node.
$cfg->read( $filename );
Returns the Config::General::Hierarchical object itself.
Reads and parses all the file structure, beginning from $filename and following its hierarchical structure. It dies on error or if called twice. By this method the Config::General::Hierarchical object becames a node: the configuration root node, which is the only one without a name: you can reference it by the object.
$filename
syntax()
package MyConfig; # use base 'Config::General::Hierarchical'; # sub syntax { my ( $self ) = @_; my %constraint = ( ... ); return $self->merge_values( \%constraint, $self->SUPER::syntax ); }
It must return the reference to the hash describing the syntax constraint.
This method is called by get(), import() and read() methods in order to check the struscture syntax of the red configuration.
There are some configuration variable which Config::General::Hierarchical handles as directives. This means that will there be some keywords that will can not be used neither as configuration variable name nor as node name. Anyway, if you strongly need to use a configuration variable name which is a directive name, you can redefine the keyword for each directive by this way:
# This make the include keyword now be handled as the inherits directive my $cfg = Config::General::Hierarchical->new( inherits => 'include' );
The same directive can be used more than once in the same configuration file.
It specifies a file to inherit. It take one argument: the name of the file to inherit. If used twice (or more) undefined configuration variables are inherited from the last file in order to create a temporary configuration tree which inherits the file specified by previous inherits directive, an so on...
It forces a variable to have an undefined value even if it have some value defined in the inherited structure. It can be specified more than once and it can be used as key of a node with the same purpose.
The undefined directive takes precedence on the value. In the following exaple undef is returned.
undef
# configuration <node> key 1 undefined key </node> # code $cfg->_node->_key;
It's default value is '*'. It can be used to specify default value or syntax constraint for all the other key not specified and requested for the same node where a wild key is defined. For example it can be used to specify that every database timeout must be and integer and that its default value is 300: in the following example both $cfg->_db->_customers->_tout and $cfg->_db->_users->_tout will return 300 while $cfg->_db->_products->_tout will returns 600 and $cfg->_db->_example->_tout will die.
$cfg->_db->_customers->_tout
$cfg->_db->_users->_tout
300
$cfg->_db->_products->_tout
600
$cfg->_db->_example->_tout
# configuration <db> <*> tout 300 </*> <customers> host customersdb.${DBServersDomain} name customersdb user customerslogin pass customerspwd </customers> <example> tout alphanumeric </example> <products> host productsdb.${DBServersDomain} name productsdb user productslogin pass productspwd tout 600 </products> <users> host usersdb.${DBServersDomain} name usersdb user userslogin pass userspwd </users> </db> DBServersDomain my.domain # code package MyConfig; # use base 'Config::General::Hierarchical'; # sub syntax { my ( $self ) = @_; my %constraint = ( db => { '*' => { tout => 'I' } } ); return $self->merge_values( \%constraint, $self->SUPER::syntax ); }
The syntax constraint specifies the option variable tree and the syntax that variables must respect. To specify the structure and the syntax this module uses an hash for each node where each key is the name of a configuration variable and values can be either a string defining the variable syntax or a reference to an other hash if the configuration variable is a node. A variable syntax can contains an uppercase letter to specify the type of the configuration variable and/or some lowercase letter to specify some flags. It is not mandatory to specify every key! When there is any specification for a configuration variable requested by get any check is performed if it is a node otherwise the value must be simply defined. The syntax constraint is checked when the get method is called: if the configuration variable doesn't respect the syntax a die is called.
The type is specified by an uppercase letter, if not specified the default is string.
A - a date and time value: 'YYYY-mm-dd HH:MM:SS'
B - a boolean value
D - a date: 'YYYY-mm-dd'
E - an e-mail address
I - an integer number
N - a floating point numer
S - a string even if empty
T - a time: 'HH:MM:SS'
The flags are specified by a lowercase letter.
a - the variable is an array: when the value is getted a reference to an ARRAY is returned
m - the hinerited value is merged instead of overwritten; it can be used only for strings and arrays
u - the value can be undefined
There are a few of thing to pay attention when many flags are specified.
This is the tipical m use.
A reference to an ARRAY is returned, empty if the value is undefined.
The get method before performing the syntax constraint check parses the value in order to escape the backslashes. The following backslasch sequences are recognised.
A backslash at the end of the line makes the following line to be concatenated with the current one, this is a Config::General feature. In the following example $value contains the value 'valuecontinued'.
# config file variable value\ continued #code my $value = $cfg->variable;
If a value contains the following syntax
${variable_name}
this token is substituted with the value of variable_name. The inline variable substitution is made at get time, so the value substituted is the final one of the variable. The value of variable_name is obtained by a get() call, so the syntax constraiant check is performed on it before the substitution.
variable_name
To do the inline variable substituition is necessary that a reference to the root node is still alive, otherwise a die() is called. Anyway, it is possible to call the check() method on the node before loosing the root node reference in order to cache all the values. It can be called explicitally on a node of implicitally by the new() methed using the check parameter with a true value.
# config.conf file <node> key ${var} </node> var value
In the following exaple a die() is called
my $node = get_node; $node->_key; # this generates a die call # sub get_node { my $cfg = Config::General::Hierarchical->new( file => 'config.conf' ); return $cfg->_node; }
This can be prevented by this way
my $node = get_node; $node->_key; # sub get_node { my $cfg = Config::General::Hierarchical->new( file => 'config.conf', check => 1 ); return $cfg->_node; }
or by this way (more efficient than previous).
my $node = get_node; $node->_key; # sub get_node { my $cfg = Config::General::Hierarchical->new( file => 'config.conf' ); return $cfg->_node->check; }
When an undef variable is requested during inline variable substitution, its value is substituted with an empty string.
The syntax to access the value of a subkey while in inline variable substitution is -> ; in the following example $cfg->_var will return 'abc' .
->
$cfg->_var
'abc'
# configuration <node> key b <node> var a${node->key}c
The module Config::General::Hierachical::Dump offers a simple and usefull way to dump configurration files.
Using many of the features of Config::General::Hierarchical it is possible to do so.
$ cat MyConfig.pm package MyConfig; use base 'Config::General::Hierarchical'; sub syntax { my ( $self ) = @_; my %constraint = ( GMTOffsett => 'I', IdString => 'm', ); return $self->merge_values( \%constraint, $self->SUPER::syntax ); } 1; $ cat MyConfigDump.pm package MyConfigDump; use base 'Config::General::Hierarchical::Dump'; use MyConfig; sub parser { return 'MyConfig' }; 1; $ cat base.conf #!/usr/bin/perl -MMyConfigDump GMTOffsett N/A IdString MyApp LogString MyFacility-${IdString} $ cat eu.conf #!/usr/bin/perl -MMyConfigDump inherits base.conf GMTOffsett -1 IdString Eu Rate UER $ cat fr.conf #!/usr/bin/perl -MMyConfigDump inherits eu.conf IdString Fr $ cat gb.conf #!/usr/bin/perl -MMyConfigDump inherits eu.conf GMTOffsett 0 IdString GB Rate GBP $ cat it.conf #!/usr/bin/perl -MMyConfigDump inherits eu.conf IdString It $ cat pt.conf #!/usr/bin/perl -MMyConfigDump inherits eu.conf GMTOffsett 0 IdString Pt $ cat us.conf #!/usr/bin/perl -MMyConfigDump inherits base.conf IdString US Rate USD $ ./base.conf GMTOffsett = error; IdString = 'MyApp'; LogString = 'MyFacility-MyApp'; $ ./eu.conf GMTOffsett = '-1'; IdString = 'MyAppEu'; LogString = 'MyFacility-MyAppEu'; Rate = 'UER'; $ ./fr.conf GMTOffsett = '-1'; IdString = 'MyAppEuFr'; LogString = 'MyFacility-MyAppEuFr'; Rate = 'UER'; $ ./gb.conf GMTOffsett = '0'; IdString = 'MyAppEuGB'; LogString = 'MyFacility-MyAppEuGB'; Rate = 'GBP'; $ ./it.conf GMTOffsett = '-1'; IdString = 'MyAppEuIt'; LogString = 'MyFacility-MyAppEuIt'; Rate = 'UER'; $ ./pt.conf GMTOffsett = '0'; IdString = 'MyAppEuPt'; LogString = 'MyFacility-MyAppEuPt'; Rate = 'UER'; $ ./us.conf GMTOffsett = error; IdString = 'MyAppUS'; LogString = 'MyFacility-MyAppUS'; Rate = 'USD';
Some perl versions has a bug which give a message like following one:
Attempt to free unreferenced scalar: SV 0xe7411a0, Perl interpreter: 0xe160010 at t/99_dump.t line 2 during global destruction.
If it is possible to upgrade perl version, this is the best solution, otherwise an installation workaround can be used:
export EXCLUDE_WEAKEN=1 cpan Config::General::Hierarchical
Please report here https://rt.cpan.org/Dist/Display.html?Name=Config-General-Hierarchical any other one.
I strongly recommend you to read the following documentations:
Config::General The way this module reads configuration files
Copyright (c) 2007-2009 Daniele Ricci
This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself.
Daniele Ricci <icc |AT| cpan.org>
A special thanks to Dada S.p.A. (Italy) for giving authorization to publish this module.
0.07
To install Config::General::Hierarchical, copy and paste the appropriate command in to your terminal.
cpanm
cpanm Config::General::Hierarchical
CPAN shell
perl -MCPAN -e shell install Config::General::Hierarchical
For more information on module installation, please visit the detailed CPAN module installation guide.