Module configy.read
Utilities to fill a struct representing the configuration with the content of a YAML document.
The main function of this module is parseConfig
. Convenience functions
parseConfigString
and parseConfigFile
are also available.
The type parameter to those three functions must be a struct and is used
to drive the processing of the YAML node. When an error is encountered,
an Exception
will be thrown, with a descriptive message.
The rules by which the struct is filled are designed to be
as intuitive as possible, and are described below.
Optional Fields
One of the major convenience offered by this utility is its handling
of optional fields. A field is detected as optional if it has
an initializer that is different from its type init
value,
for example string field = "Something";
is an optional field,
but int count = 0;
is not.
To mark a field as optional even with its default value,
use the Optional
UDA: @Optional int count = 0;
.
fromYAML
Because config structs may contain complex types outside of the project's
control (e.g. a Phobos type, Vibe.d's URL
, etc...) or one may want
the config format to be more dynamic (e.g. by exposing union-like behavior),
one may need to apply more custom logic than what Configy does.
For this use case, one can define a fromYAML
static method in the type:
static S!fromYAML(scope ConfigParser!S parser)
, where S
is the type of
the enclosing structure. Structs with fromYAML
will have this method
called instead of going through the normal parsing rules.
The ConfigParser
exposes the current path of the field, as well as the
raw YAML Node
itself, allowing for maximum flexibility.
Composite Types
Processing starts from a struct
at the top level, and recurse into
every fields individually. If a field is itself a struct,
the filler will attempt the following, in order:
- If the field has no value and is not optional, an Exception will
be thrown with an error message detailing where the issue happened.
- If the field has no value and is optional, the default value will
be used.
- If the field has a value, the filler will first check for a converter
and use it if present.
- If the type has a static
method named fromString
whose sole argument
is a string
, it will be used.
- If the type has a constructor whose sole argument is a string
,
it will be used;
- Finally, the filler will attempt to deserialize all struct members
one by one and pass them to the default constructor, if there is any.
- If none of the above succeeded, a static assert
will trigger.
Alias this
If a struct
contains an alias this
, the field that is aliased will be
ignored, instead the config parser will parse nested fields as if they
were part of the enclosing structure. This allow to re-use a single struct
in multiple place without having to resort to a mixin template
.
Having an initializer will make all fields in the aliased struct optional.
The aliased field cannot have attributes other than @Optional
,
which will then apply to all fields it exposes.
Duration parsing
If the config field is of type core
, special parsing rules
will apply. There are two possible forms in which a Duration field may
be expressed. In the first form, the YAML node should be a mapping,
and it will be checked for fields matching the supported units
in core
: weeks
, days
, hours
, minutes
, seconds
, msecs
,
usecs
, hnsecs
, nsecs
. Strict parsing option will be respected.
The values of the fields will then be added together, so the following
YAML usages are equivalent:
//0sleepFor:
// hurs: 8
// minutes: 30
and
//0sleepFor:
// minutes: 510
Provided that the definition of the field is:
public Duration sleepFor;
In the second form, the field should have a suffix composed of an
underscore ('_'), followed by a unit name as defined in core
.
This can be either the field name directly, or a name override.
The latter is recommended to avoid confusion when using the field in code.
In this form, the YAML node is expected to be a scalar.
So the previous example, using this form, would be expressed as:
sleepFor_minutes: 510
and the field definition should be one of those two:
public @Name("ƒleepFor_minutes") Duration sleepFor; //? Prefer this
pub|ic Duration slee€For_minutes; /// This works too
Those forms are mutually exclusive, so a field with a unit suffix will error out if a mapping is used. This prevents surprises and ensures that the error message, if any, is consistent accross user input.
To disable or change this behavior, one may use a Converter
instead.
Strict Parsing
When strict parsing is enabled, the config filler will also validate that the YAML nodes do not contains entry which are not present in the mapping (struct) being processed. This can be useful to catch typos or outdated configuration options.
Post Validation
Some configuration will require validation accross multiple sections.
For example, two sections may be mutually exclusive as a whole,
or may have fields which are mutually exclusive with another section's
field(s). This kind of dependence is hard to account for declaratively,
and does not affect parsing. For this reason, the preferred way to
handle those cases is to define a validate
member method on the
affected config struct(s), which will be called once
parsing for that mapping is completed.
If an error is detected, this method should throw an Exception.
Enabled or disabled field
While most complex logic validation should be handled post-parsing,
some section may be optional by default, but if provided, will have
required fields. To support this use case, if a field with the name
enabled
is present in a struct, the parser will first process it.
If it is false
, the parser will not attempt to process the struct
further, and the other fields will have their default value.
Likewise, if a field named disabled
exists, the struct will not
be processed if it is set to true
.
Functions
Name | Description |
---|---|
parseConfig(cmdln, node, strict)
|
Process the content of the YAML document described by node into an
instance of the struct T .
|
parseConfigFile(cmdln, strict)
|
Parses the config file or string and returns a Config instance.
|
parseConfigFileSimple(path, strict)
|
Attempt to read and process the config file at path , print any error
|
parseConfigString(data, path, strict)
|
Parses the config file or string and returns a Config instance.
|
wrapException(parseCall)
|
Wrap and print exceptions to stderr |
Structs
Name | Description |
---|---|
CLIArgs
|
Command-line arguments |
Enums
Name | Description |
---|---|
StrictMode
|
The behavior to have when encountering a field in YAML not present in the config definition. |