BINDish

NAME

Config::BINDish - parse BIND9/named kind of config files

SYNOPSIS

my $cfg = Config::BINDish.new;
$cfg.read: string => q:to/CFG/;
server "s1" {
    name "my.server";
    paths {
        base "/opt/myapp";
        pool "files" static {
            "pub/img";
            "static/img";
            "docs";
        };
        pool "files" dynamic {
            "users/reports";
            "system/reports"
        }
    }
}
CFG
say $cfg.top.get( :server("s1") => :paths => :pool("images") => 'root' ); # ./pub/img

$cfg.read: file => $my-config-filename;

DISCLAIMER

This module is very much experimental in the sense of the API methods it provides. The grammar is expected to be more stable, yet no warranties can be given at the moment.

DESCRIPTION

In this documentation I'll be referring to the configuration format implemented by the module as BINDish config or simply BINDish.

EXTENSIONS

BINDish configuration parser can be augmented with 3rd-party extensions. Every extension is implemented as a role which will be used to build the final grammar or actions classes (see Grammar). The classes are based upon Config::BINDish::Grammar and Config::BINDish::Actions respectively. Here is the steps Config::BINDish does to build them:

  • An empty class is created which will serve as the final version

  • Extension roles are punned and added as parents to the class

  • Then the base class is added as the last parent

The order in which the extensions are added is defined by the order and the way they're registered. The later added ones serve as the earlier parents meaning that Raku's method call dispatching will have their methods invoked first.

There are two and a half ways to extend the parser. First is to use is BINDish-grammar or is BINDish-actions trait:

unit module Config::BINDish::Ext1;
role Grammar is BINDish-grammar {
    token value:sym<mine> {
        ...
    }
}
role Actions is BINDish-actions {
    method value:sym<mine>($/) {
        ...
    }
}

In this case the role they're applied to will be auto-registered with Config::BINDish. When such extension is contained by a module then it would be added when the module is used:

use Config::BINDish::Ext1;
use Config::BINDish::Ext2;

Note that considering the order of use statements, Ext2 will be able to override methods of Ext1.

The specific of using the traits is that extensions declared this way will become application-wide available. So, even if the extension module is used by a module used by the main code, the extension will be available to any instance of Config::BINDish.

Note: We say that extensions registered with the traits are registered statically.

The other 1.5 ways of adding the extensions are to use extend-grammar and extend-actions constructor arguments or method with the same names:

my $cfg = Config::BINDish.new: :extend-grammar(ExtG1, ExtG2), :extend-actions(ExtA1, ExtA2);
$cfg.extend-grammar(ExtG3)
    .extend-actions(ExtA3);

In this case extension roles don't need the traits applied. This way we call dynamic registration.

The other specific of dynamic extensions is that they will go after the static ones. I.e. in the above examples ExtG* and ExtA* will be positioned before Ext1 and Ext2 in the MRO order, prioritizing the former over the latter ones.

Why is the above called 1.5 ways? Because the constructor eventually uses the extend-* methods.

See also Config::BINDish::Grammar and Config::BINDish::Actions to get more information about writing extensions.

ATTRIBUTES

Config::BINDish::Grammar::Strictness $.strict

The default grammar strictness mode. See Config::BINDish::Grammar::Strictness documentation for details.

%.blocks, %.options

These two attributes contain user-defined structure of the config file. More information about them can be found in Config::BINDish::Grammar documentation, methods declare-blocks and declare-options.

$.grammar, $.actions

The final grammar and actions class versions with all registered extensions applied. Both attributes are lazy and clearable in terms of AttrX::Mooish. It means that the following is possible:

say $cfg.grammar.^name; # Config::BINDish::Grammar...
$cfg.extend-grammar(MyApp::GrammarMod);
$cfg.clear-grammar;     # Actually, extend-grammar already does this. This line is here to demo the concept only.
say $cfg.grammar.^name; # Config::BINDish::Grammar+{MyApp::GrammarMod}...

IO::Path $.file

If read method was called with :file<...> argument then this attribute will hold corresponding IO::Path object for the file name.

Bool $.flat = False

If set to True then Config::BINDish::Actions will act in flattening mode.

$.top

The top node produced by the grammar actions. I.e. it is the result of $<TOP>.ast of the Match object produced by grammar's parse method. For Config::BINDish::Actions it would be an instance of Config::BINDish::AST. But an extension can produce something to its taste which wouldn't be an AST whatsoever. The only requirement imposed on the object stored by the attribute is to provide get method.

$.match

This attribute stores the Match object produced by grammar's parse method.

METHODS

extend-grammar( +@ext ), extend-actions( +@ext )

Interface to dynamically register extensions. Take a list of roles and records them as extensions. Then it clears $.grammar or $.actions attributes, respectively. Both return self to allow method call chaining.

build-grammar(), build-actions()

Methods used by AttrX::Mooish to lazily initialize $.grammar and $.actions attributes respectively.

multi method read(Config::BINDish:U: |args)

Instantiates Config::BINDish class and re-invokes read method on the instance with args capture.

multi method read(IO:D(Str:D) :$file, |args), multi method read(Str:D :$string, |args)

Parses a configuration stored either in a $string or in a $file and returns the resulting Match object. The capture args is passed over to the parse method of $.grammar alongside with $.actions, $.strict, $.flat, %.blocks, and %.options attributes.

The method returns what is returned by grammar's parse method. The same value is then stored in $.match attribute.

SEE ALSO

README.md

AUTHOR

Vadim Belman [email protected]

The Camelia image is copyright 2009 by Larry Wall. "Raku" is trademark of the Yet Another Society. All rights reserved.