Knobs

Last updated on September 04, 2017


  1. Home
    1. Overview
    2. Configuration Syntax
  2. Usage

Overview

Knobs is a configuration library for Scala. It is based on the Data.Configurator library for Haskell, but is extended in a number of ways to make it more useful.

Features include:

Syntax

A configuration file consists of a series of directives and comments, encoded in UTF-8. A comment begins with a # character, and continues to the end of a line.

Files and directives are processed from first to last, top to bottom.

Binding a name to a value

A binding associates a name with a value.

my_string = "hi mom!"
your-int-33 = 33
his_bool = on
HerList = [1, "foo", off]

A name must begin with a Unicode letter, which is followed by zero or more Unicode alphanumeric characters, hyphens -, or underscores _.

Bindings are created or overwritten in the order which they are encountered. It is legitimate to bind a name multiple times, in which the last value wins.

a = 1
a = true
# value of a is now true, not 1

Value types

The configuration file format supports the following data types:

The following escape sequences are recognized in a text string:

A time unit specification for a Duration can be any of the following:

String interpolation

Strings support interpolation, so that you can dynamically construct a string based on data in your configuration, the OS environment, or system properties.

If a string value contains the special sequence $(foo) (for any name foo), then Knobs will look up the name foo in the configuration data and substitute its value. If it can’t find that name, it will look in the Java system properties. Failing that, Knobs will look in the OS environment for a matching environment variable.

It is an error for a string interpolation fragment to contain a name that cannot be found either in the current configuration or the system environment.

To represent a single literal $ character in a string, use a double $$.

Grouping directives

It is possible to group a number of directives together under a single prefix:

my-group
{
  a = 1

  # groups support nesting
  nested {
    b = "yay!"
  }
}

The name of a group is used as a prefix for the items in the group. For instance, the value of a above can be retrieved using lookup("my-group.a"), and b with lookup("my-group.nested.b").

Importing files

To import the contents of another configuration file, use the import directive.

import "$(HOME)/etc/myapp.cfg"

Absolute paths are imported as is. Relative paths are resolved with respect to the file they are imported from. It is an error for an import directive to name a file that doesn’t exist, cannot be read, or contains errors. Only environment variables, not system properties or other bindings, are interpolated into import directives.

File lookup semantics

The meaning of the import directive depends on the Resource type the configuration is being loaded from. In general, paths are resolved relative to the current file. Knobs only supports importing files of the same resource type as the current file. For example a classpath resource can only import other files from the classpath, and an on-disk file resource can only import other files from disk.

Importing into groups

If an import appears inside a group, the group’s naming prefix will be applied to all of the names imported from the given configuration file.

Supposing we have a file named “foo.cfg” that looks like this:

bar = 1

And another file that imports into a group:

hi {
  import "foo.cfg"
}

This will result in a value named hi.bar.