NAME
Config::General::Hierarchical - Hierarchical Generic Config Module
SYNOPSIS
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 {
...
}
DESCRIPTION
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.
HOW CONFIGURATION DATA ARE ORGANIZED
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',
};
HOW CONFIGURATION FILES ARE READ
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.
This is how Config::General::Hierarchical
inizializes the Config::General
object.
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.
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
-
not used yet: TODO
-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
SUBROUTINES/METHODS
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.
new()
- synopsis
-
$cfg = Config::General::Hierarchical->new( %options );
- return value
-
Returns a new constructed
Config::General::Hierarchical
object. - description
-
Some
%options
can be specified by and hash.-AutoLaunder
-CComments
-LowerCaseNames
-SplitDelimiter
-SplitPolicy
-
Proxied to
Config::General
. check
1-
This make the
new()
method to implicitally call thecheck()
method as well. file
<string>-
This make the
new()
method to implicitally call theread()
method as well. inherits
<string>-
Redefines the default
inherits
syntax of the same directive. undefined
<string>-
Redefines the default
undefined
syntax of the same directive. wild
<string>-
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.
check()
- synopsis
-
$cfg->check;
- return value
-
If it does not die, returns the node itself.
- description
-
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.
import()
- synopsis
-
use Config::General::Hierarchical;
- description
-
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.
get()
- synopsis
-
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( ... );
- return value
-
Returns the value of the configuration variable
VariableName
. - description
-
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 aConfig::General::Hierarchical
object, when it is defined as an array you will obtain a reference to anARRAY
(even if empty), otherwise you will get a scalar.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.
getk()
- synopsis
-
my @keys = $cfg->getk;
- description
-
This mothod returns the array with all the keys configured in the configuration files for the node.
read()
- synopsis
-
$cfg->read( $filename );
- return value
-
Returns the
Config::General::Hierarchical
object itself. - description
-
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 theConfig::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.
syntax()
- synopsis
-
package MyConfig; # use base 'Config::General::Hierarchical'; # sub syntax { my ( $self ) = @_; my %constraint = ( ... ); return $self->merge_values( \%constraint, $self->SUPER::syntax ); }
- return value
-
It must return the reference to the hash describing the syntax constraint.
- description
-
This method is called by
get()
,import()
andread()
methods in order to check the struscture syntax of the red configuration.
DIRECTIVES
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.
inherits
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...
undefined
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.
# configuration
<node>
key 1
undefined key
</node>
# code
$cfg->_node->_key;
wild
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.
# 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 );
}
SYNTAX CONSTRAINT
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.
TYPES
The type is specified by an uppercase letter, if not specified the default is string.
- datetime
-
A - a date and time value: 'YYYY-mm-dd HH:MM:SS'
- boolean
-
B - a boolean value
- date
-
D - a date: 'YYYY-mm-dd'
-
E - an e-mail address
- integer
-
I - an integer number
- number
-
N - a floating point numer
- string
-
S - a string even if empty
- time
-
T - a time: 'HH:MM:SS'
FLAGS
The flags are specified by a lowercase letter.
- array
-
a - the variable is an array: when the value is getted a reference to an ARRAY is returned
- merge
-
m - the hinerited value is merged instead of overwritten; it can be used only for strings and arrays
- undefined
-
u - the value can be undefined
MULTIPLE FLAGS
There are a few of thing to pay attention when many flags are specified.
- am
-
This is the tipical m use.
- au
-
A reference to an ARRAY is returned, empty if the value is undefined.
BACKSLASH ESCAPEING
The get method before performing the syntax constraint check parses the value in order to escape the backslashes. The following backslasch sequences are recognised.
- \\ backslash
- \$ dollar
- \a beel
- \b backspace
- \f form feed
- \n new line
- \r carriage return
- \t horizontal tabulator
- \v vertical tabulator
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;
INLINE VARIABLE SUBSTITUTION
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.
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'
.
# configuration
<node>
key b
<node>
var a${node->key}c
DUMPING CONFIGURATION
The module Config::General::Hierachical::Dump offers a simple and usefull way to dump configurration files.
EXAMPLE
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';
BUGS AND INCOMPATIBILITIES
Please report.
SEE ALSO
I strongly recommend you to read the following documentations:
Config::General The way this module reads configuration files
LICENSE AND COPYRIGHT
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.
AUTHOR
Daniele Ricci <icc |AT| cpan.org>
CREDITS
A special thanks to Dada S.p.A. (Italy) for giving authorization to publish this module.
VERSION
0.05