The config-schema package

This is a package candidate release! Here you can preview how this package release will appear once published to the main package index (which can be accomplished via the 'maintain' link below). Please note that once a package has been published to the main package index it cannot be undone! Please consult the package uploading documentation for more information.



This package makes it possible to defined schemas for use when loading configuration files using the config-value format. These schemas can be used to be process a configuration file into a Haskell value, or to automatically generate documentation for the file format.

[Skip to ReadMe]


Dependenciesbase (>=4.9 && <4.11), config-value (==0.5.*), containers (==0.5.*), free (==4.12.*), kan-extensions (==5.0.*), semigroupoids (==5.2.*), text (==1.2.*), transformers (==0.5.*) [details]
CopyrightEric Mertens 2017
AuthorEric Mertens
Home page
Bug tracker
Source repositoryhead: git clone
UploadedSun May 7 04:00:12 UTC 2017 by EricMertens




Maintainers' corner

For package maintainers and hackage trustees

Readme for config-schema-


Hackage Build Status

This package allows the user to define configuration schemas suitable for matching against configuration files written in the config-value format. These schemas allow the user to extract an arbitrary Haskell value from an interpretation of a configuration file. It also allows the user to programatically generate documentation for the configuration files accepted by the loader.

{-# Language OverloadedStrings, ApplicativeDo #-}

module Example where

import qualified Data.Text as Text
import qualified Data.Text.IO as Text
import           Data.Text (Text)
import           Data.Monoid ((<>))
import           Data.Functor.Alt ((<!>))

import           Config
import           Config.Schema

exampleFile :: Text
exampleFile =
  " name: \"Johny Appleseed\" \n\
  \ age : 99                  \n\
  \ happy: yes                \n\
  \ kids:                     \n\
  \   * name: \"Bob\"         \n\
  \   * name: \"Tom\"         \n"

exampleValue :: Value
Right exampleValue = parse exampleFile

exampleSpec :: ValueSpecs Text
exampleSpec = sectionsSpec "" $
  do name  <- reqSection  "name" "Full name"
     age   <- reqSection  "age"  "Age of user"
     happy <- optSection' "happy" "Current happiness status" yesOrNo
     kids  <- reqSection' "kids"  "All children" (oneOrList kidSpec)

     return $
       let happyText = case happy of Just True  -> " and is happy"
                                     Just False -> " and is not happy"
                                     Nothing    -> " and is private"

       in name <> " is " <> Text.pack (show (age::Integer)) <>
             " years old and has kids " <>
             Text.intercalate ", " kids <>

kidSpec :: ValueSpecs Text
kidSpec = sectionsSpec "kid" (reqSection "name" "Kid's name")

-- | Matches the 'yes' and 'no' atoms
yesOrNo :: ValueSpecs Bool
yesOrNo = True  <$ atomSpec "yes" <!>
          False <$ atomSpec "no"

printDoc :: IO ()
printDoc = Text.putStr (generateDocs exampleSpec)
-- *Example> printDoc
-- Configuration file fields:
--     name: REQUIRED text
--        Full name
--     age: REQUIRED integer
--        Age of user
--     happy: `yes` or `no`
--        Current happiness status
--     kids: REQUIRED kid or list of kid
--        All children
-- kid
--     name: REQUIRED text
--        Kid's name

example :: Either [LoadError] Text
example = loadValue exampleSpec exampleValue
-- *Example> exampleVal
-- Right "Johny Appleseed is 99 years old and has kids Bob, Tom and is happy"