config-schema-1.2.2.0: Schema definitions for the config-value package
Copyright(c) Eric Mertens 2017
LicenseISC
Maintaineremertens@gmail.com
Safe HaskellNone
LanguageHaskell2010

Config.Schema.Spec

Description

This module provides a set of types and operations for defining configuration file schemas.

These specifications are can be consumed by Config.Schema.Load and Config.Schema.Docs.

This is the schema system used by the glirc IRC client https://hackage.haskell.org/package/glirc. For a significant example, visit the Client.Configuration and Client.Configuration.Colors modules.

Synopsis

Specifying values

ValueSpec allows you to define specifications that will match parsed config-value configuration files. ValueSpec allows us to define the shape of configuration values that will match the specification as well as a way to process those matches.

Below we have an example configuration record that can be matched from a configuration file.

More documentation for defining key-value pairs is available below.

This configuration file expects either a given username or allows the user to ask for a random username. The (<!>) operator allows us to combine two alternatives as seen below. The config-value language distinguishes between atoms like random and strings like "random" allowing unambiguous special cases to be added in addition to free-form text.

{-# Language RecordWildCards, OverloadedStrings, ApplicativeDo #-}
module Example where

import Config.Schema
import Data.Functor.Alt ((<!>))
import Data.Maybe       (fromMaybe)
import Data.Text        (Text)

data Config = Config
  { userName :: UserName
  , retries  :: Int
  }

data UserName = Random | Given Text

userNameSpec :: ValueSpec UserName
userNameSpec = Random <$  atomSpec "random"
           <!> Given  <$> anySpec -- matches string literals

nameExample :: ValueSpec Config
nameExample = sectionsSpec "config" $

  do userName <- reqSection' "username" userNameSpec "Configured user name"

     retries  <- fromMaybe 3
             <$> optSection "retries" "Number of attempts (default: 3)"

     pure Config{..}

Examples:

username: random
retries: 5
-- Generates: Config { userName = Random, retries = 5 }

We can omit the retries:

username: random
-- Generates: Config { userName = Random, retries = 3 }

We can specify a specific username as a string literal instead of using the atom random:

username: "me"
-- Generates: Config { userName = Given "me", retries = 3 }

Sections can be reordered:

retries: 5
username: random
-- Generates: Config { userName = Random, retries = 5 }

data ValueSpec a Source #

Non-empty disjunction of value specifications. This type is the primary way to specify expected values.

Multiple specifications can be combined using this type's Alt instance.

To create ValueSpec values see Config.Schema.Spec

Instances

Instances details
Functor ValueSpec Source # 
Instance details

Defined in Config.Schema.Types

Methods

fmap :: (a -> b) -> ValueSpec a -> ValueSpec b #

(<$) :: a -> ValueSpec b -> ValueSpec a #

Alt ValueSpec Source #

Left-biased choice between two specifications

Instance details

Defined in Config.Schema.Types

customSpec :: Text -> ValueSpec a -> (a -> Either Text b) -> ValueSpec b Source #

The custom specification allows an arbitrary function to be used to validate the value extracted by a specification. If Nothing is returned the value is considered to have failed validation.

namedSpec Source #

Arguments

:: Text

name

-> ValueSpec a

underlying specification

-> ValueSpec a 

Named value specification. This is useful for factoring complicated value specifications out in the documentation to avoid repetition of complex specifications.

class HasSpec a where Source #

Class of value specifications without parameters.

Instances

Instances details
HasSpec Double Source #

Since: 1.2.0.0

Instance details

Defined in Config.Schema.Spec

HasSpec Float Source #

Since: 1.2.0.0

Instance details

Defined in Config.Schema.Spec

HasSpec Int Source # 
Instance details

Defined in Config.Schema.Spec

HasSpec Int8 Source # 
Instance details

Defined in Config.Schema.Spec

HasSpec Int16 Source # 
Instance details

Defined in Config.Schema.Spec

HasSpec Int32 Source # 
Instance details

Defined in Config.Schema.Spec

HasSpec Int64 Source # 
Instance details

Defined in Config.Schema.Spec

HasSpec Integer Source # 
Instance details

Defined in Config.Schema.Spec

HasSpec Natural Source #

Since: 1.2.0.0

Instance details

Defined in Config.Schema.Spec

HasSpec Word Source # 
Instance details

Defined in Config.Schema.Spec

HasSpec Word8 Source # 
Instance details

Defined in Config.Schema.Spec

HasSpec Word16 Source # 
Instance details

Defined in Config.Schema.Spec

HasSpec Word32 Source # 
Instance details

Defined in Config.Schema.Spec

HasSpec Word64 Source # 
Instance details

Defined in Config.Schema.Spec

HasSpec Text Source # 
Instance details

Defined in Config.Schema.Spec

HasSpec a => HasSpec [a] Source #

Zero or more elements in a list

Instance details

Defined in Config.Schema.Spec

Methods

anySpec :: ValueSpec [a] Source #

Integral a => HasSpec (Ratio a) Source #

For Ratio and Rational

Since: 1.2.0.0

Instance details

Defined in Config.Schema.Spec

HasSpec a => HasSpec (NonEmpty a) Source #

One or more elements in a list

Since: 1.2.0.0

Instance details

Defined in Config.Schema.Spec

(HasSpec a, HasSpec b) => HasSpec (Either a b) Source #

Left-biased, untagged union of specs

Instance details

Defined in Config.Schema.Spec

Methods

anySpec :: ValueSpec (Either a b) Source #

Key-value mapping specifications

Specifications that match key-value map literals.

sectionsSpec Source #

Arguments

:: Text

unique documentation identifier

-> SectionsSpec a

underlying specification

-> ValueSpec a 

Named subsection value specification. The unique identifier will be used for generating a documentation section for this specification and should be unique within the scope of the specification being built.

assocSpec Source #

Arguments

:: ValueSpec a

underlying specification

-> ValueSpec [(Text, a)] 

Specification for a section list where the keys are user-defined. Values are matched against the underlying specification and returned as a list of section-name/value pairs.

Since: 0.3.0.0

Number specifications

Specifications built from numberSpec matching number literals.

numberSpec :: ValueSpec Number Source #

Primitive specification for matching any number.

Since: 1.2.0.0

integerSpec :: ValueSpec Integer Source #

Specification for matching any integral number.

Since: 1.2.0.0

rationalSpec :: ValueSpec Rational Source #

Specification for matching any number as a Rational.

Since: 1.2.0.0

naturalSpec :: ValueSpec Natural Source #

Specification for matching any non-negative, integral number

Since: 1.2.0.0

fractionalSpec :: Fractional a => ValueSpec a Source #

Specification for matching any fractional number.

Since: 0.2.0.0

numSpec :: Num a => ValueSpec a Source #

Specification for matching any integral number.

Text specifications

Specifications built from textSpec for matching string literals.

textSpec :: ValueSpec Text Source #

Specification for matching any text literal

Since: 1.2.0.0

stringSpec :: ValueSpec String Source #

Specification for matching any text as a String

Atom specifications

Specifications built to match atoms.

atomSpec Source #

Arguments

:: Text

atom

-> ValueSpec () 

Primitive specification for matching a particular atom.

anyAtomSpec :: ValueSpec Text Source #

Primitive specification for matching any atom. Matched atom is returned.

yesOrNoSpec :: ValueSpec Bool Source #

Specification for using atoms yes and no to represent booleans True and False respectively

trueOrFalseSpec :: ValueSpec Bool Source #

Specification for using atoms true and false to represent booleans True and False respectively.

Since: 1.2.0.0

List specifications

Specifications for matching list literals built with 'listSpec.

listSpec Source #

Arguments

:: ValueSpec a

element specification

-> ValueSpec [a] 

Primitive specification for matching a list of values each satisfying a given element specification.

oneOrList Source #

Arguments

:: ValueSpec a

element specification

-> ValueSpec [a] 

Specification that matches either a single element or multiple elements in a list. This can be convenient for allowing the user to avoid having to specify singleton lists in the configuration file.

nonemptySpec Source #

Arguments

:: ValueSpec a

element specification

-> ValueSpec (NonEmpty a) 

Matches a non-empty list.

Since: 0.2.0.0

oneOrNonemptySpec Source #

Arguments

:: ValueSpec a

element specification

-> ValueSpec (NonEmpty a) 

Matches a single element or a non-empty list.

Since: 0.2.0.0

Specifying sections

Sections specifications allow you to define an unordered collection of required and optional sections using a convenient Applicative do-notation syntax.

Let's consider an example of a way to specify a name given a base and optional suffix.

{-# Language OverloadedStrings, ApplicativeDo #-}
module Example where

import Config.Schema
import Data.Text (Text)

nameExample :: ValueSpec Text
nameExample =
  sectionsSpec "name" $
  do x <- reqSection "base" "Base name"
     y <- optSection "suffix" "Optional name suffix"
     pure (maybe x (x <>) y)

Example configuration components and their extracted values.

base:     "VAR"
optional: "1"
-- Generates: VAR1

Order doesn't matter

optional: "1"
base:     "VAR"
-- Generates: VAR1

Optional fields can be omitted

base:     "VAR"
-- Generates: VAR

Unexpected sections will generate errors to help detect typos

base:     "VAR"
extra:    0
-- Failure due to unexpected extra section

All required sections must appear for successful match

optional: "1"
-- Failure due to missing required section

data SectionsSpec a Source #

A list of section specifications used to process a whole group of key-value pairs. Multiple section specifications can be combined using this type's Applicative instance.

To create SectionsSpec values see Config.Schema.Spec

Instances

Instances details
Functor SectionsSpec Source # 
Instance details

Defined in Config.Schema.Types

Methods

fmap :: (a -> b) -> SectionsSpec a -> SectionsSpec b #

(<$) :: a -> SectionsSpec b -> SectionsSpec a #

Applicative SectionsSpec Source # 
Instance details

Defined in Config.Schema.Types

reqSection Source #

Arguments

:: HasSpec a 
=> Text

section name

-> Text

description

-> SectionsSpec a 

Specification for a required section with an implicit value specification.

optSection Source #

Arguments

:: HasSpec a 
=> Text

section name

-> Text

description

-> SectionsSpec (Maybe a) 

Specification for an optional section with an implicit value specification.

reqSection' Source #

Arguments

:: Text

section name

-> ValueSpec a

value specification

-> Text

description

-> SectionsSpec a 

Specification for a required section with an explicit value specification.

optSection' Source #

Arguments

:: Text

section name

-> ValueSpec a

value specification

-> Text

description

-> SectionsSpec (Maybe a) 

Specification for an optional section with an explicit value specification.

Re-exports

class Functor f => Alt (f :: Type -> Type) where #

Laws:

<!> is associative:             (a <!> b) <!> c = a <!> (b <!> c)
<$> left-distributes over <!>:  f <$> (a <!> b) = (f <$> a) <!> (f <$> b)

If extended to an Alternative then <!> should equal <|>.

Ideally, an instance of Alt also satisfies the "left distributon" law of MonadPlus with respect to <.>:

<.> right-distributes over <!>: (a <!> b) <.> c = (a <.> c) <!> (b <.> c)

But Maybe, IO, Either a, ErrorT e m, and STM satisfy the alternative "left catch" law instead:

pure a <!> b = pure a

However, this variation cannot be stated purely in terms of the dependencies of Alt.

When and if MonadPlus is successfully refactored, this class should also be refactored to remove these instances.

The right distributive law should extend in the cases where the a Bind or Monad is provided to yield variations of the right distributive law:

(m <!> n) >>- f = (m >>- f) <!> (m >>- f)
(m <!> n) >>= f = (m >>= f) <!> (m >>= f)

Minimal complete definition

(<!>)

Methods

(<!>) :: f a -> f a -> f a infixl 3 #

<|> without a required empty

some :: Applicative f => f a -> f [a] #

many :: Applicative f => f a -> f [a] #

Instances

Instances details
Alt [] 
Instance details

Defined in Data.Functor.Alt

Methods

(<!>) :: [a] -> [a] -> [a] #

some :: Applicative [] => [a] -> [[a]] #

many :: Applicative [] => [a] -> [[a]] #

Alt Maybe 
Instance details

Defined in Data.Functor.Alt

Methods

(<!>) :: Maybe a -> Maybe a -> Maybe a #

some :: Applicative Maybe => Maybe a -> Maybe [a] #

many :: Applicative Maybe => Maybe a -> Maybe [a] #

Alt IO

This instance does not actually satisfy the (<.>) right distributive law It instead satisfies the "Left-Catch" law

Instance details

Defined in Data.Functor.Alt

Methods

(<!>) :: IO a -> IO a -> IO a #

some :: Applicative IO => IO a -> IO [a] #

many :: Applicative IO => IO a -> IO [a] #

Alt First 
Instance details

Defined in Data.Functor.Alt

Methods

(<!>) :: First a -> First a -> First a #

some :: Applicative First => First a -> First [a] #

many :: Applicative First => First a -> First [a] #

Alt Last 
Instance details

Defined in Data.Functor.Alt

Methods

(<!>) :: Last a -> Last a -> Last a #

some :: Applicative Last => Last a -> Last [a] #

many :: Applicative Last => Last a -> Last [a] #

Alt Option 
Instance details

Defined in Data.Functor.Alt

Methods

(<!>) :: Option a -> Option a -> Option a #

some :: Applicative Option => Option a -> Option [a] #

many :: Applicative Option => Option a -> Option [a] #

Alt First 
Instance details

Defined in Data.Functor.Alt

Methods

(<!>) :: First a -> First a -> First a #

some :: Applicative First => First a -> First [a] #

many :: Applicative First => First a -> First [a] #

Alt Last 
Instance details

Defined in Data.Functor.Alt

Methods

(<!>) :: Last a -> Last a -> Last a #

some :: Applicative Last => Last a -> Last [a] #

many :: Applicative Last => Last a -> Last [a] #

Alt NonEmpty 
Instance details

Defined in Data.Functor.Alt

Alt IntMap 
Instance details

Defined in Data.Functor.Alt

Methods

(<!>) :: IntMap a -> IntMap a -> IntMap a #

some :: Applicative IntMap => IntMap a -> IntMap [a] #

many :: Applicative IntMap => IntMap a -> IntMap [a] #

Alt Seq 
Instance details

Defined in Data.Functor.Alt

Methods

(<!>) :: Seq a -> Seq a -> Seq a #

some :: Applicative Seq => Seq a -> Seq [a] #

many :: Applicative Seq => Seq a -> Seq [a] #

Alt ValueSpec Source #

Left-biased choice between two specifications

Instance details

Defined in Config.Schema.Types

Alt (Either a) 
Instance details

Defined in Data.Functor.Alt

Methods

(<!>) :: Either a a0 -> Either a a0 -> Either a a0 #

some :: Applicative (Either a) => Either a a0 -> Either a [a0] #

many :: Applicative (Either a) => Either a a0 -> Either a [a0] #

Alt (V1 :: Type -> Type) 
Instance details

Defined in Data.Functor.Alt

Methods

(<!>) :: V1 a -> V1 a -> V1 a #

some :: Applicative V1 => V1 a -> V1 [a] #

many :: Applicative V1 => V1 a -> V1 [a] #

Alt (U1 :: Type -> Type) 
Instance details

Defined in Data.Functor.Alt

Methods

(<!>) :: U1 a -> U1 a -> U1 a #

some :: Applicative U1 => U1 a -> U1 [a] #

many :: Applicative U1 => U1 a -> U1 [a] #

MonadPlus m => Alt (WrappedMonad m) 
Instance details

Defined in Data.Functor.Alt

Alt (Proxy :: Type -> Type) 
Instance details

Defined in Data.Functor.Alt

Methods

(<!>) :: Proxy a -> Proxy a -> Proxy a #

some :: Applicative Proxy => Proxy a -> Proxy [a] #

many :: Applicative Proxy => Proxy a -> Proxy [a] #

Ord k => Alt (Map k) 
Instance details

Defined in Data.Functor.Alt

Methods

(<!>) :: Map k a -> Map k a -> Map k a #

some :: Applicative (Map k) => Map k a -> Map k [a] #

many :: Applicative (Map k) => Map k a -> Map k [a] #

(Bind f, Monad f) => Alt (MaybeT f) 
Instance details

Defined in Data.Functor.Alt

Methods

(<!>) :: MaybeT f a -> MaybeT f a -> MaybeT f a #

some :: Applicative (MaybeT f) => MaybeT f a -> MaybeT f [a] #

many :: Applicative (MaybeT f) => MaybeT f a -> MaybeT f [a] #

Alt f => Alt (Coyoneda f) 
Instance details

Defined in Data.Functor.Coyoneda

Methods

(<!>) :: Coyoneda f a -> Coyoneda f a -> Coyoneda f a #

some :: Applicative (Coyoneda f) => Coyoneda f a -> Coyoneda f [a] #

many :: Applicative (Coyoneda f) => Coyoneda f a -> Coyoneda f [a] #

Apply f => Alt (ListT f) 
Instance details

Defined in Data.Functor.Alt

Methods

(<!>) :: ListT f a -> ListT f a -> ListT f a #

some :: Applicative (ListT f) => ListT f a -> ListT f [a] #

many :: Applicative (ListT f) => ListT f a -> ListT f [a] #

Alternative f => Alt (WrappedApplicative f) 
Instance details

Defined in Data.Functor.Alt

Alt f => Alt (Lift f) 
Instance details

Defined in Data.Functor.Alt

Methods

(<!>) :: Lift f a -> Lift f a -> Lift f a #

some :: Applicative (Lift f) => Lift f a -> Lift f [a] #

many :: Applicative (Lift f) => Lift f a -> Lift f [a] #

(Hashable k, Eq k) => Alt (HashMap k) 
Instance details

Defined in Data.Functor.Alt

Methods

(<!>) :: HashMap k a -> HashMap k a -> HashMap k a #

some :: Applicative (HashMap k) => HashMap k a -> HashMap k [a] #

many :: Applicative (HashMap k) => HashMap k a -> HashMap k [a] #

Alt f => Alt (Rec1 f) 
Instance details

Defined in Data.Functor.Alt

Methods

(<!>) :: Rec1 f a -> Rec1 f a -> Rec1 f a #

some :: Applicative (Rec1 f) => Rec1 f a -> Rec1 f [a] #

many :: Applicative (Rec1 f) => Rec1 f a -> Rec1 f [a] #

ArrowPlus a => Alt (WrappedArrow a b) 
Instance details

Defined in Data.Functor.Alt

Methods

(<!>) :: WrappedArrow a b a0 -> WrappedArrow a b a0 -> WrappedArrow a b a0 #

some :: Applicative (WrappedArrow a b) => WrappedArrow a b a0 -> WrappedArrow a b [a0] #

many :: Applicative (WrappedArrow a b) => WrappedArrow a b a0 -> WrappedArrow a b [a0] #

Alt f => Alt (IdentityT f) 
Instance details

Defined in Data.Functor.Alt

Methods

(<!>) :: IdentityT f a -> IdentityT f a -> IdentityT f a #

some :: Applicative (IdentityT f) => IdentityT f a -> IdentityT f [a] #

many :: Applicative (IdentityT f) => IdentityT f a -> IdentityT f [a] #

(Bind f, Monad f, Semigroup e) => Alt (ExceptT e f) 
Instance details

Defined in Data.Functor.Alt

Methods

(<!>) :: ExceptT e f a -> ExceptT e f a -> ExceptT e f a #

some :: Applicative (ExceptT e f) => ExceptT e f a -> ExceptT e f [a] #

many :: Applicative (ExceptT e f) => ExceptT e f a -> ExceptT e f [a] #

(Bind f, Monad f) => Alt (ErrorT e f) 
Instance details

Defined in Data.Functor.Alt

Methods

(<!>) :: ErrorT e f a -> ErrorT e f a -> ErrorT e f a #

some :: Applicative (ErrorT e f) => ErrorT e f a -> ErrorT e f [a] #

many :: Applicative (ErrorT e f) => ErrorT e f a -> ErrorT e f [a] #

Alt f => Alt (ReaderT e f) 
Instance details

Defined in Data.Functor.Alt

Methods

(<!>) :: ReaderT e f a -> ReaderT e f a -> ReaderT e f a #

some :: Applicative (ReaderT e f) => ReaderT e f a -> ReaderT e f [a] #

many :: Applicative (ReaderT e f) => ReaderT e f a -> ReaderT e f [a] #

Alt f => Alt (StateT e f) 
Instance details

Defined in Data.Functor.Alt

Methods

(<!>) :: StateT e f a -> StateT e f a -> StateT e f a #

some :: Applicative (StateT e f) => StateT e f a -> StateT e f [a] #

many :: Applicative (StateT e f) => StateT e f a -> StateT e f [a] #

Alt f => Alt (StateT e f) 
Instance details

Defined in Data.Functor.Alt

Methods

(<!>) :: StateT e f a -> StateT e f a -> StateT e f a #

some :: Applicative (StateT e f) => StateT e f a -> StateT e f [a] #

many :: Applicative (StateT e f) => StateT e f a -> StateT e f [a] #

Alt f => Alt (WriterT w f) 
Instance details

Defined in Data.Functor.Alt

Methods

(<!>) :: WriterT w f a -> WriterT w f a -> WriterT w f a #

some :: Applicative (WriterT w f) => WriterT w f a -> WriterT w f [a] #

many :: Applicative (WriterT w f) => WriterT w f a -> WriterT w f [a] #

Alt f => Alt (WriterT w f) 
Instance details

Defined in Data.Functor.Alt

Methods

(<!>) :: WriterT w f a -> WriterT w f a -> WriterT w f a #

some :: Applicative (WriterT w f) => WriterT w f a -> WriterT w f [a] #

many :: Applicative (WriterT w f) => WriterT w f a -> WriterT w f [a] #

Alt f => Alt (Reverse f) 
Instance details

Defined in Data.Functor.Alt

Methods

(<!>) :: Reverse f a -> Reverse f a -> Reverse f a #

some :: Applicative (Reverse f) => Reverse f a -> Reverse f [a] #

many :: Applicative (Reverse f) => Reverse f a -> Reverse f [a] #

Alt f => Alt (Backwards f) 
Instance details

Defined in Data.Functor.Alt

Methods

(<!>) :: Backwards f a -> Backwards f a -> Backwards f a #

some :: Applicative (Backwards f) => Backwards f a -> Backwards f [a] #

many :: Applicative (Backwards f) => Backwards f a -> Backwards f [a] #

(Alt f, Alt g) => Alt (f :*: g) 
Instance details

Defined in Data.Functor.Alt

Methods

(<!>) :: (f :*: g) a -> (f :*: g) a -> (f :*: g) a #

some :: Applicative (f :*: g) => (f :*: g) a -> (f :*: g) [a] #

many :: Applicative (f :*: g) => (f :*: g) a -> (f :*: g) [a] #

(Alt f, Alt g) => Alt (Product f g) 
Instance details

Defined in Data.Functor.Alt

Methods

(<!>) :: Product f g a -> Product f g a -> Product f g a #

some :: Applicative (Product f g) => Product f g a -> Product f g [a] #

many :: Applicative (Product f g) => Product f g a -> Product f g [a] #

Alt f => Alt (M1 i c f) 
Instance details

Defined in Data.Functor.Alt

Methods

(<!>) :: M1 i c f a -> M1 i c f a -> M1 i c f a #

some :: Applicative (M1 i c f) => M1 i c f a -> M1 i c f [a] #

many :: Applicative (M1 i c f) => M1 i c f a -> M1 i c f [a] #

(Alt f, Functor g) => Alt (Compose f g) 
Instance details

Defined in Data.Functor.Alt

Methods

(<!>) :: Compose f g a -> Compose f g a -> Compose f g a #

some :: Applicative (Compose f g) => Compose f g a -> Compose f g [a] #

many :: Applicative (Compose f g) => Compose f g a -> Compose f g [a] #

Alt f => Alt (RWST r w s f) 
Instance details

Defined in Data.Functor.Alt

Methods

(<!>) :: RWST r w s f a -> RWST r w s f a -> RWST r w s f a #

some :: Applicative (RWST r w s f) => RWST r w s f a -> RWST r w s f [a] #

many :: Applicative (RWST r w s f) => RWST r w s f a -> RWST r w s f [a] #

Alt f => Alt (RWST r w s f) 
Instance details

Defined in Data.Functor.Alt

Methods

(<!>) :: RWST r w s f a -> RWST r w s f a -> RWST r w s f a #

some :: Applicative (RWST r w s f) => RWST r w s f a -> RWST r w s f [a] #

many :: Applicative (RWST r w s f) => RWST r w s f a -> RWST r w s f [a] #