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.time.Duration, 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.time: 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.time. 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

NameDescription
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

NameDescription
CLIArgs Command-line arguments

Enums

NameDescription
StrictMode The behavior to have when encountering a field in YAML not present in the config definition.