# The Configuration Tree


# The Configuration Builder

A configuration program comprises two things: a configuration and 
an action that makes use of that configuration. The action may be a no-op, it may
also be a chain of several atomic steps. It's all the same to us.

To create such a configuration program, we use the ``ConfigurationBuilder``-API.

## Basic Usage

A rather trivial example would look like this:

``` coffee

# instantiate the builder
config = ConfigBuilder()
  # setup the lookup path for config type plugins
  .typePath [process.env.TYPE_PATH]
  # specify a YAML file to load
  .load pathToConfigFile
  # build the configuration program and return the root node
  .build()

```
## Programmatically adding/overriding settings

You can add / override settings by providing a configuration object to
the `.add(object, [filename])`-method:

```coffee

config = ConfigBuilder()
  .add defaults
  .load configFile
  .add 
    foo:
      bar: 42
```

`.add()` will recursively merge the given object into the existing configuration.
Via the optional second argument you can associate a filename with the object.
This filename is used when resolving relative filesystem paths.

Note that while the given `object` itself should be a plain javascript object, it
is totally allowed to *contain* `ConfigNode` instances. 

## Loading YAML-Files

To load configuration from YAML files, use the `.load()` and `.tryLoad()`-methods.
Loading from a file has the same effect as providing the equivalent content to the `.add()`-method.
The `.tryLoad()`-method does the same as `.load()`, but will silently ignore files that do
not exist or cannot be read from. `.load()` on the other hand will throw an exception in 
this case.

## Setting up the Plugin Lookup Path

When writing YAML configuration files, you can annotate nodes with local tags to tell the
config builder to use a particular custom type to represent that node. For example, if
your YAML file contains this:

``` yaml
foo: !my-bar
  oink: 42

```

the config builder will 
## Side Effects (a.k.a. Actions)

The API also allows you to attach side effects to the configuration program. 
As seen in the trivial example above, this is completely optional. 
The original reason for me to add this feature was the IRMa CLI module. On the one
hand, it provides and manipulates the configuration. On the other hand, it also decides
the primary action to execute (display help message, start server, create man page, ...).

``` coffee


config = ConfigBuilder()
  .typePath [process.env.TYPE_PATH]
  .load pathToConfigFile
  .then (env, configRoot, argv)->
    runMyApplication configRoot

# ... later, when everything is setup...

config.run env, argv

```

There are probably a million other ways to do this, I tried a couple and this is simply the
one I liked most. It ties in neatly with the way the ``bind``-operator works (see below).
Another benefit of this approach is that it will generalize nicely should we decide to
introduce asynchronous loading/processing of configuration elements. I am actually thinking
about deprecating the `.build()`-method for this reason and make `.then()` the prefered
way of accessing the configuration.

Note that ``env`` and ``argv`` are just arbitrary values that are passed to your actions.
See the explanation of ``environment`` in the glossary for more details.
The `configRoot` is the root node of the configuration, the same that would be returned by `.build()`.



## The ``bind`` operator

The Configuration Builder mainly defines a monadic combinator ``bind`` that
makes the set of configuration programs a monad.

First, let's assume that any instance of ``ConfigurationBuilder`` has a
current configuration and a current action. It does not modify either of the two.

Now we call ``configBuilder.bind f`` for some Kleisli Arrow ``f``. The
operation will start by creating an intermediate instance ``tmpBuilder`` by
simply applying ``f`` to the current configuration.

It will then create a new action ``combinedAction`` by chaining the current
action of ``configBuilder`` and that of ``tmpBuilder``, taking care of all the
result-passing and promise-related shenanigans.

Finally it will take the current configuration of ``tmpBuilder`` and the
``combinedAction`` it just created, and wrap both up in a new
``ConfigBuilder``. This is the return value.

## Why is the current action not passed to the arrow functions?

The ``bind``-operation only passes the current configuration to the arrows, 
but not the current action. Which is both good and bad. 

It is good, because the chaining of the actions is taken care of by ``bind``.
so the arrows do not have to deal with this.  My observation was that most of
the basic arrow steps *either* modify the configuration *or* the action, but
not both.  If they did modify the action, it would usually be monotonic (i.e.
append a step to a chain of actions). So moving the responsibility to the
arrows would add repetitive clutter with little gain.

It is bad, because it effectively prohibits arrows from altering the action in
non-monotonic ways (e.g. overriding or veto-ing of side effects).  I have yet
to encounter a case where this is a problem, but still -- it seems "incomplete".

I think I will have a second variant of the ``bind``-operation for
that. I could even examine the number of formal parameters of the arrow
function to determine which of the variants to use.

# Glossary


## Configuration

As far as the config builder is concerned, a *configuration* is just a plain
Javascript object.  A builder will carry around some configuration object,
allowing you to incrementally modify or extend it.  When you finally call the
``.build()``-method, it will put the configuration into a new instance of
``RootNode``, which will traverse the configuration and take care of
initializing any nested ``ConfigNode``-instances in the correct order.

## Environment

When executing a configuration program via ``.run()``, the caller passes two
(optional) arguments: The so-called *environment* and an optional
initialization argument for the action.  Both are treated similar in that they
do not end up in the final configuration but instead are passed on to the
action. They do however serve different purposes, which becomes clearer if we
consider programs that contain an action composed of more than one step.  In
this case, each step will be called with the same environment.  In contrast,
the second argument is only passed to the first step. The second step instead
sees the return value of the first step, the third that of the second and so
on.

## Action

Actions provide a way of adding side effects to your configuration program.
An action is a javascript function that takes three arguments:
- the environment, 
- the root node of the final configuration 
- an optional argument.

You may chain any number of actions to the program via the ``.then()`` method.
When you execute the program (via ``.run()``), these actions will be executed 
in the order they were attached. The optional third argument is used to pass
the result of the previous step to the next one. The second argument of the ``.run()``
will be passed to the first action in the chain.

If your action involves asynchronous work, you probably want to have it return a promise 
object.

A rather canonic example for encoding side effects in a configuration program
can be found in IRMa's CLI module. Depending on the options given on the
command line -- it will either start the service, print help or generate a manpage
when the configuration program is executed.

## Configuration Program

A *Configuration Program* is just a pair of a configuration and an action.
Keep in mind that actions are composable, so "one" action may in fact be
composed of several atomic steps.

Config Programs are not directly accessible through the API, instead we use
``ConfigBuilder`` instances to manipulate and optionally/eventually execute
them.

## Configuration Builder

The Configuration Builder is an API that allows you to construct and eventually
execute configuration programs. It does so by using what I like to call
"monadic composition", though the term may not be accurate by mathematical standards.



## Arrows

In the ``ConfigBuilder`` implementation you will find a group of
functions/methods being refered to as *arrows*, hinting to fact that they
either resamble Kleisli Arrows themselfs or are in fact higher-order functions
producing Kleisli Arrows. This is just a fancy term for a very simple thing: A
Kleisli Arrow is a function that takes a "plain" (i.e. non-monadic) value and
produces a monadic value. 

In our case, the "arrows" are functions that take a plain configuration object
and return a new ``ConfigBuilder``. It's the type of function one would pass to
the ``.bind()`` method. The API includes predefined implementations for what we
believe are very useful examples:

  - ``typePath`` for modifying the plugin resolution path

  - ``load`` and ``tryLoad`` for merging configuration files into the
    configuration program

  - ``add`` for programatically appending configuration directives

  - ``then`` for appending side effects

Since you would typically use those in conjunction with the ``.bind()``-method
anyway, the API has shortcut notations for exactly this.  So for example
instead of ``builder.bind(load(someFileName))``, you can equivalently write
``builder.load(someFileName))``.

Of course you can (and very often will) create your own, application-specific
arrows. Think of the predefined ones as building-blocks to support that process.
