Data.Configurator

configurator-0.3.0.0: Configuration management

Copyright | (c) 2011 MailRank Inc.
License | BSD3
Maintainer | Bryan O'Sullivan <bos@serpentine.com>
Stability | experimental
Portability | portable
Safe Haskell | None
Language | Haskell98

Data.Configurator

Contents

- Configuration file format
  - Binding a name to a value
    - Value types
    - String interpolation
  - Grouping directives
  - Importing files
- Types
- Loading configuration data
- Lookup functions
- Notification of configuration changes
- Low-level loading functions
- Helper functions

Description

A simple (yet powerful) library for working with configuration files.

Synopsis

- data Worth a
  - = Required {
    - worth :: a
    }
  - | Optional {
    - worth :: a
    }
- autoReload :: AutoConfig -> [Worth FilePath] -> IO (Config, ThreadId)
- autoReloadGroups :: AutoConfig -> [(Name, Worth FilePath)] -> IO (Config, ThreadId)
- autoConfig :: AutoConfig
- empty :: Config
- lookup :: Configured a => Config -> Name -> IO (Maybe a)
- lookupDefault :: Configured a => a -> Config -> Name -> IO a
- require :: Configured a => Config -> Name -> IO a
- prefix :: Text -> Pattern
- exact :: Text -> Pattern
- subscribe :: Config -> Pattern -> ChangeHandler -> IO ()
- load :: [Worth FilePath] -> IO Config
- loadGroups :: [(Name, Worth FilePath)] -> IO Config
- reload :: Config -> IO ()
- subconfig :: Name -> Config -> Config
- addToConfig :: [Worth FilePath] -> Config -> IO ()
- addGroupsToConfig :: [(Name, Worth FilePath)] -> Config -> IO ()
- display :: Config -> IO ()
- getMap :: Config -> IO (HashMap Name Value)

# Configuration file format

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! \u2603"
    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 of a Unicode alphanumeric code point, hyphen "`-`", or underscore "`_`".

Bindings are created or overwritten in the order in which they are encountered. It is legitimate for a name to be bound multiple times, in which case 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:

- Booleans, represented as `on` or `off`, `true` or `false`. These are case sensitive, so do not try to use `True` instead of `true`!
- Integers, represented in base 10.
- Unicode strings, represented as text (possibly containing escape sequences) surrounded by double quotes.
- Heterogeneous lists of values, represented as an opening square bracket "`[`", followed by a series of comma-separated values, ending with a closing square bracket "`]`".

The following escape sequences are recognised in a text string:

- `\n` - newline
- `\r` - carriage return
- `\t` - horizontal tab
- `\\` - backslash
- `\"` - double quote
- `\u`xxxx - Unicode character from the basic multilingual plane, encoded as four hexadecimal digits
- `\u`xxxx`\u`xxxx - Unicode character from an astral plane, as two hexadecimal-encoded UTF-16 surrogates

### String interpolation

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

If a string value contains the special sequence "`$(foo)`" (for any name `foo`), then the name `foo` will be looked up in the configuration data and its value substituted. If that name cannot be found, it will be looked up in the OS environment.

For security reasons, it is an error for a string interpolation fragment to contain a name that cannot be found in either the current configuration or the environment.

To represent a single literal "`$`" character in a string, double it: "`$$`".

## 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` by supplying the name "`my-group.a`", and "`b`" will be named "`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 does not exist, cannot be read, or contains errors.

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`":

    bar = 1

And another file that imports it into a group:

    hi {
      import "foo.cfg"
    }

This will result in a value named "`hi.bar`".

# Types

data Worth a #

Constructors

Required |
Fields worth :: a
Optional |
Fields worth :: a

Instances

Functor Worth # |
Methods fmap :: (a -> b) -> Worth a -> Worth b # (<$) :: a -> Worth b -> Worth a #
Eq a => Eq (Worth a) # |
Methods (==) :: Worth a -> Worth a -> Bool # (/=) :: Worth a -> Worth a -> Bool #
Show a => Show (Worth a) # |
Methods showsPrec :: Int -> Worth a -> ShowS # show :: Worth a -> String # showList :: [Worth a] -> ShowS #
IsString (Worth FilePath) # |
Methods fromString :: String -> Worth FilePath #
Hashable a => Hashable (Worth a) # |
Methods hashWithSalt :: Int -> Worth a -> Int # hash :: Worth a -> Int #

# Loading configuration data

autoReload #

Arguments

:: AutoConfig | Directions for when to reload and how to handle errors.
-> [Worth FilePath] | Configuration files to load.
-> IO (Config, ThreadId) |

Load a `Config` from the given `FilePath`s, and start a reload thread.

At intervals, a thread checks for modifications to both the original files and any files they refer to in `import` directives, and reloads the `Config` if any files have been modified.

If the initial attempt to load the configuration files fails, an exception is thrown. If the initial load succeeds, but a subsequent attempt fails, the `onError` handler is invoked.

File names have any environment variables expanded prior to the first time they are opened, so you can specify a file name such as `"$(HOME)/myapp.cfg"`.

autoReloadGroups :: AutoConfig -> [(Name, Worth FilePath)] -> IO (Config, ThreadId) #

autoConfig :: AutoConfig #

Defaults for automatic `Config` reloading when using `autoReload`. The `interval` is one second, while the `onError` action ignores its argument and does nothing.

empty :: Config #

A completely empty configuration.

# Lookup functions

lookup :: Configured a => Config -> Name -> IO (Maybe a) #

Look up a name in the given `Config`. If a binding exists, and the value can be `convert`ed to the desired type, return the converted value, otherwise `Nothing`.

lookupDefault #

Arguments

:: Configured a |
=> a | Default value to return if `lookup` or `convert` fails.
-> Config |
-> Name |
-> IO a |

Look up a name in the given `Config`. If a binding exists, and the value can be converted to the desired type, return it, otherwise return the default value.

require :: Configured a => Config -> Name -> IO a #

Look up a name in the given `Config`. If a binding exists, and the value can be `convert`ed to the desired type, return the converted value, otherwise throw a `KeyError`.

# Notification of configuration changes

To more efficiently support an application's need to dynamically reconfigure, a subsystem may ask to be notified when a configuration property is changed as a result of a reload, using the `subscribe` action.

prefix :: Text -> Pattern #

A pattern that matches on a prefix of a property name. Given `"foo"`, this will match `"foo.bar"`, but not `"foo"` or `"foobar"`.

exact :: Text -> Pattern #

A pattern that must match exactly.

subscribe :: Config -> Pattern -> ChangeHandler -> IO () #

Subscribe for notifications. The given action will be invoked when any change occurs to a configuration property matching the supplied pattern.

# Low-level loading functions

load :: [Worth FilePath] -> IO Config #

Create a `Config` from the contents of the named files. Throws an exception on error, such as if files do not exist or contain errors.

File names have any environment variables expanded prior to the first time they are opened, so you can specify a file name such as `"$(HOME)/myapp.cfg"`.

loadGroups :: [(Name, Worth FilePath)] -> IO Config #

Create a `Config` from the contents of the named files, placing them into named prefixes. If a prefix is non-empty, it should end in a dot.

reload :: Config -> IO () #

Forcibly reload a `Config`. Throws an exception on error, such as if files no longer exist or contain errors. If the provided `Config` is a `subconfig`, this will reload the entire top-level configuration, not just the local section.

subconfig :: Name -> Config -> Config #

Gives a `Config` corresponding to just a single group of the original `Config`. The subconfig can be used just like the original `Config`, but see the documentation for `reload`.

addToConfig :: [Worth FilePath] -> Config -> IO () #

Add additional files to a `Config`, causing it to be reloaded to add their contents.

addGroupsToConfig :: [(Name, Worth FilePath)] -> Config -> IO () #

Add additional files to named groups in a `Config`, causing it to be reloaded to add their contents. If the prefixes are non-empty, they should end in dots.

# Helper functions

display :: Config -> IO () #

Perform a simple dump of a `Config` to `stdout`.

getMap :: Config -> IO (HashMap Name Value) #

Fetch the `HashMap` that maps names to values.