NAME
Fugu::Config - the OpenBSD-style configuration grammar
SYNOPSIS
use Fugu::Config;
my $config = Fugu::Config->new(file => '/etc/mydaemon.conf');
$config->load or die $config->error . "\n";
my $port = $config->get('port', 8080);
for my $device ($config->blocks('device')) {
say $device->{settings}{name};
}
my $vm = $config->block('vm', 'default');
DESCRIPTION
Fugu::Config parses the configuration grammar that OpenBSD daemons use. A file holds top-level settings and blocks:
log_level debug
hap_port = 51827
device tasmota thermostat bedroom {
name = "Bedroom Thermostat"
topic = tasmota_AABBCC
}
Both key value and key = value parse. A double-quoted value loses its quotes. A # starts a comment that runs to the end of the line.
A block header is a type, then one or more arguments, then an opening brace. Blocks nest one level; a block inside a block is an error.
The parser keeps the blocks of each type in file order, and also addresses each one by its name, which is the last argument of the header. Thus a caller that wants an ordered list of accessories and a caller that wants the machine called "default" read the same parse.
A malformed line is an error with a file and a line number. The module never skips a line it did not understand. A typo that a parser ignores is a setting that silently does not apply, and the operator finds out from the behavior of the daemon weeks later.
new
new(%args) creates a parser for one file. The method does not read the file. Call load().
This is the argument:
file-
The configuration file. This argument is necessary.
load
load() reads and parses the file. A second call starts over, so a setting that the file no longer holds is gone.
An unreadable file is an error. A caller for whom an absent file is normal tests for the file first. A daemon that silently runs on defaults after a typo in a path is worse than one that refuses to start.
file
file() returns the path that this object parses.
error
error() returns the most recent failure, with its file and line.
get
get($key, $default) returns a top-level setting, or the default.
setting_names
setting_names() returns the names of the top-level settings, sorted.
parse_bool
parse_bool($value, $default) parses a value as a switch. A setting inside a block comes through here.
The accepted spellings are yes, true, on and 1, and their opposites no, false, off and 0. The comparison ignores case.
Any other value returns the default and records an error. Thus a caller that checks gets told, and a caller that does not still gets a defined answer instead of the opposite of what the file said.
blocks
blocks($type) returns every block of the type, in file order.
Each entry is a hash reference with these keys:
type-
The block type.
args-
The header arguments, in order, as an array reference.
name-
The last header argument.
settings-
The settings inside the block, as a hash reference.
order-
The position of the block in the file, counted from zero over every block of every type. A caller that reads two block types and wants them interleaved as the file wrote them sorts on it.
block
block($type, $name) returns the block of the type whose name matches, or undef. When two blocks share a name, the last one in the file wins, as an assignment does.
find_project_root
find_project_root($marker) walks up from the working directory to the first directory that holds $marker. The method returns that directory, or undef when the walk reaches the root without a match.
RETURN VALUES
load() returns the object on success. It returns undef when the file does not open or holds a line that the grammar does not accept, with the reason in error().
get(), file() and error() return a string or undef. parse_bool() returns 1 or 0. blocks() and setting_names() return a list. block() returns a hash reference or undef.
EXAMPLES
This example loads a file that may not exist yet:
my $config = Fugu::Config->new(file => $path);
if (-f $path) {
$config->load or die $config->error . "\n";
}
my $port = $config->get('port', 8080);
ERRORS
new() dies when file is absent or empty, and find_project_root() dies without a marker. Both are programming errors.
No other method dies. load() reports every parse failure through its return value and error().
SEE ALSO
AUTHORS
Dick Olsson <hi@senzilla.io>
CAVEATS
The grammar has no escape for the comment character. A value cannot hold a #, even inside quotes.
Every value is a string. The module does not convert a number, and 0 as a string is true in Perl. Use parse_bool() for a switch.
A key with no value is not a setting, and the parser rejects the line. The grammar has no flag form.