Config::Natural - Module that can read easy-to-use configuration files
Lets say you have a file mail.conf
name = John Doe email = jdoe@somewhere.net server = mail.somewhere.net signature = - John Doe -- Visit my homepage at http://www.somewhere.net/~jdoe/ .
You can read it using the following program:
use Config::Natural; my $mailconf = new Config::Natural 'mail.conf';
and you can for example print the signature:
print $mailconf->param('signature');
This module has been written in order to provide an easy way to read simple configuration files. The syntax of these configuration files is what seemed to me the most natural way to write these files, hence the name of this module.
One of the reason I wrote this module is that I wanted a very easy way to feed data to HTML::Template based scripts. Therefore the API of Config::Natural is compatible with HTML::Template, and you can write programs as simple as:
use strict; use Config::Natural; use HTML::Template; my $source = new Config::Natural 'file.src'; my $tmpl = new HTML::Template type => 'filename', source => 'file.tmpl', associate => $source; print $tmpl->output;
And this is not just another trivial example: I use scripts nearly as simple as this one to create most of my pages.
To affect a value to a parameter, simply write:
greetings = hello world
The parameter greetings
will have the value "hello world"
.
You can also give multi-lines values this way:
text = - Perl is a language optimized for scanning arbitrary text files, extracting information from those text files, and printing reports based on that information. It's also a good language for many system management tasks. The language is intended to be practical (easy to use, efficient, complete) rather than beautiful (tiny, elegant, minimal). [from perl(1)] .
Think of this as a ``Unix inspired'' syntax. Instead of giving the value,
you write "-"
to mean ``the value will follow'' (in Unix, this means the
data will come from standard input). To end the multi-lines value, you
simply put a single dot "."
on a line (as in Unix mail, but it needn't
be on the first column).
If you need to write several identical records, you can use lists. The syntax is:
list_name { parameter = value text = - This text may be as long as you wish. . }
Example: a version history
## that's the version history of Config::Natural :) history { date = 2000.10.10 version = 0.7.0 comment = First fully functional release as an independent module. } history { date = 2000.11.04 version = 0.7.1 comment = Minor change in the internal structure: options are now grouped. } history { date = 2000.11.05 version = 0.8.0 comment = Code cleanup (mainly auto-generation of the options accessors). comment = Added list support. }
Lists can be nested. Example:
machine { name = neutron sys = linux service { type = firewall importance = critical } } machine { name = proton sys = linux service { type = proxy importance = low } service { type = router importance = medium } }
As a shorthand, you can write something like
flavour = lemon flavour = strawberry flavour = vanilla
instead of
flavours { flavour = lemon } flavours { flavour = strawberry } flavours { flavour = vanilla }
As you see, Config::Natural automatically creates a surrounding list
around the parameter "flavour"
, and names this list using the plural
of the list name, i.e. "flavours"
(ok, I'm only appending a ``s'' for
now ;)
Such a construct can be also be nested.
Note: There must be only one item on each line. This means you can't write:
line { param = value }
but instead
line { param = value }
I don't think it's a big deal, because the aim of Config::Natural is to be fast and to read files with a clear and simple syntax.
You can include a file using the "include"
keyword. For example:
# including some other file include generic.conf # now do specific stuff debug = 0 fast = 1
If the argument is the name of a directory, all the files inside that
directory are included. Check read_source()
for more information.
You can use comments in your file. If a line begins with a
sharp sign "#"
, it will be ignored. The sharp sign needs not
being in the first column though.
Config::Natural offer three filter mechanisms so that you can modify the data on-the-fly at two differents moments of the parsing.
file.txt read_source() ___________ _________________ | ... | =====> | reading file | | foo=hello | | > for each line | _____________ | ... | | X <======|==> | prefilter | |___________| | v | |_____________| | parsing line -|--, |_________________| | | param() <----------' _________________ _____________ | X <=====|==> | data filter | | v | |_____________| | X <=====|==> | handler | | v | |_____________| | storing value | |_________________|
Prefilter occurs before Config::Natural parsing, therefore a prefilter receives the current line as it was read from the file. This can be used in order to correct some names which otherwise couldn't be parsed by Config::Natural, for example names with spaces. Check in the examples/ directory for sample programs that implements such functions.
You can set up a prefilter using the ->prefilter()
method, or at
creation time with the prefilter
option.
Data filter only occurs when affecting values to their parameters. This can be used to implement additional features, like a syntax for interpolating values. Check in the examples/ directory for sample programs that implements such functions.
You can set up a data filter using the ->filter()
method, or at
creation time with the filter
option.
Handlers only occurs when affecting values to their parameters, but instead of being object methods, handlers can be seen as ``parameters'' methods, in that they are bound to a name, and are only called when a parameter with that name is affected.
Handlers are defined with the ->handler()
method.
This is a new functionality, introduced in version 0.99.
A parameter path is a way of referring any parameter, even if it's deeply buried inside several layers of nested lists.
It is used by the method ->value_of()
to provide a much
easier way to read data hidden in nested lists.
The parameter path syntax is loosely inspired by XPath:
path = /level0[index0]/level1[index1]/.../param
Indexes start at zero, like in Perl (and unlike XPath).
When an index is omitted, [0]
is assumed.
If you want to get back a whole list, instead of a single value,
use [*]
, which will return the reference to that list.
If the default symbols used in the configuration file syntax doesn't fit your needs, you can change them using the following methods. Of course you must call these before reading the data file(s).
"="
.
"-"
.
"."
.
"#"
.
"{"
.
"}"
.
"include"
.
You can give an optional hashref in order to change settings of the object at creation time. Any valid object option can be used here.
my $config = new Config::Natural { read_hidden_files => 1 };
You can also give a file name or a file handle, which will call
read_source()
with that argument.
# calling with a file name my $config = new Config::Natural 'myconfig.conf'; # calling with a file handle my $config = new Config::Natural \*DATA;
use Config::Natural; my $conf = new Config::Natural \*DATA; $conf->param(-debug => 1); ## set debug on if($conf->param('debug')) { print "current options:\n"; print $conf->dump_param(-prefix => ' '); } # ... __END__ ## default values verbose = 1 debug = 0 die_on_errors = 0
If the argument is a directory name, read_source()
then recursively reads
all the files present in that directory. Invisible files (dot-files) are
read only when the option read_hidden_files
is enabled.
You can call the read_source()
method several times if you want
to merge the settings from different configuration files.
1) Return the list of the parameters:
@params = $conf->param;
2) Return the value of a parameter:
print $conf->param('debug');
3) Return the values of a number of parameters:
@dbg = $conf->param(qw(debug verbose));
4) Set the value of a parameter:
## using CGI.pm-like syntax $conf->param(-debug => 0); ## using a hashref $conf->param({ debug => 0 });
5) Set the values of a number of parameters ## using Perl/Tk-like syntax $conf->param( -warn_non_existant => 1, -mangle => 0 ); ## using a hashref $conf->param( { warn_non_existant => 1, mangle => 0 } );
Options
nospace
- If you set this option to true, no space will be printed
around the affectation symbol.
prefix
- If you set this option to a string, it will be printed
before printing each parameter.
suffix
- If you set this option to a string, it will be printed
after printing each parameter.
read_source()
will be used.
sub myfilter { my $self = shift; # important! remember it's a method my $data = shift; $data =~ s/\s*#.*$//go; # remove comments appearing on return $data # an affectation line } my $conf = new Config::Natural { filter => \&myfilter };
sub crypt_handler { my $param = shift; my $value = shift; return crypt($value, $param); } $conf->set_handler('passwd', \&crypt_handler);
Sébastien Aperghis-Tramoni <sebastien@aperghis.net>
Config::Natural is Copyright (C)2000-2004 Sébastien Aperghis-Tramoni.
This program is free software. You can redistribute it and/or modify it under the same terms as Perl itself.