Safe Haskell | Safe-Inferred |
---|---|
Language | Haskell2010 |
Parse the shell environment for configuration
A minor extension of envparse.
Usage:
import Freckle.App.Env data Config = Config -- Example { cBatchSize :: Natural , cDryRun :: Bool , cLogLevel :: LogLevel } loadConfig :: IO Config loadConfig = parse $ Config <$> var auto "BATCH_SIZE" (def 1) <*> switch "DRY_RUN" mempty <*> flag (Off LevelInfo) (On LevelDebug) "DEBUG" mempty
Synopsis
- data Info e
- data Error
- type Reader e a = String -> Either e a
- data Parser e a
- data Mod (t :: Type -> Type) a
- class AsUnread e where
- class AsEmpty e where
- class AsUnset e where
- class HasHelp (t :: Type -> Type)
- data Flag a
- data Var a
- type ErrorHandler e = String -> e -> Maybe String
- parse :: AsUnset e => (Info Error -> Info e) -> Parser e a -> IO a
- (<>) :: Semigroup a => a -> a -> a
- (>=>) :: Monad m => (a -> m b) -> (b -> m c) -> a -> m c
- (<=<) :: Monad m => (b -> m c) -> (a -> m b) -> a -> m c
- char :: AsUnread e => Reader e Char
- optional :: Alternative f => f a -> f (Maybe a)
- asum :: (Foldable t, Alternative f) => t (f a) -> f a
- splitOn :: Char -> Reader e [String]
- var :: AsUnset e => Reader e a -> String -> Mod Var a -> Parser e a
- footer :: String -> Info e -> Info e
- header :: String -> Info e -> Info e
- def :: a -> Mod Var a
- parsePure :: AsUnset e => Parser e a -> [(String, String)] -> Either [(String, e)] a
- prefixed :: String -> Parser e a -> Parser e a
- sensitive :: Parser e a -> Parser e a
- switch :: String -> Mod Flag Bool -> Parser e Bool
- str :: IsString s => Reader e s
- nonempty :: (AsEmpty e, IsString s) => Reader e s
- auto :: (AsUnread e, Read a) => Reader e a
- helpDef :: (a -> String) -> Mod Var a
- help :: forall (t :: Type -> Type) a. HasHelp t => String -> Mod t a
- helpDoc :: Parser e a -> String
- desc :: String -> Info e -> Info e
- handleError :: ErrorHandler e -> Info x -> Info e
- defaultErrorHandler :: (AsUnset e, AsEmpty e, AsUnread e) => ErrorHandler e
- parseOr :: AsUnset e => (String -> IO a) -> (Info Error -> Info e) -> Parser e b -> IO (Either a b)
- newtype Off a = Off a
- newtype On a = On a
- flag :: Off a -> On a -> String -> Mod Flag a -> Parser Error a
- data Timeout
- eitherReader :: (String -> Either String a) -> Reader Error a
- time :: String -> Reader Error UTCTime
- keyValues :: Reader Error [(Text, Text)]
- keyValue :: Char -> Reader Error (Text, Text)
- splitOnParse :: Char -> Reader e a -> Reader e [a]
- timeout :: Reader Error Timeout
Documentation
The type of errors returned by envparse
's Reader
s. These fall into 3
categories:
- Variables that are unset in the environment.
- Variables whose value is empty.
- Variables whose value cannot be parsed.
type Reader e a = String -> Either e a #
An environment variable's value parser. Use (<=<)
and (>=>)
to combine these
An environment parser
Instances
Alternative (Parser e) | |
Applicative (Parser e) | |
Functor (Parser e) | |
data Mod (t :: Type -> Type) a #
This represents a modification of the properties of a particular Parser
.
Combine them using the Monoid
instance.
The class of types that contain and can be constructed from the error returned from parsing variable whose value cannot be parsed.
The class of types that contain and can be constructed from the error returned from parsing variables whose value is empty.
The class of types that contain and can be constructed from the error returned from parsing unset variables.
class HasHelp (t :: Type -> Type) #
A class of things that can have a help message attached to them
setHelp
Flag metadata
Environment variable metadata
type ErrorHandler e = String -> e -> Maybe String #
Given a variable name and an error value, try to produce a useful error message
(<>) :: Semigroup a => a -> a -> a infixr 6 #
An associative operation.
>>>
[1,2,3] <> [4,5,6]
[1,2,3,4,5,6]
(>=>) :: Monad m => (a -> m b) -> (b -> m c) -> a -> m c infixr 1 #
Left-to-right composition of Kleisli arrows.
'(bs
' can be understood as the >=>
cs) ado
expression
do b <- bs a cs b
optional :: Alternative f => f a -> f (Maybe a) #
One or none.
It is useful for modelling any computation that is allowed to fail.
Examples
Using the Alternative
instance of Control.Monad.Except, the following functions:
>>>
import Control.Monad.Except
>>>
canFail = throwError "it failed" :: Except String Int
>>>
final = return 42 :: Except String Int
Can be combined by allowing the first function to fail:
>>>
runExcept $ canFail *> final
Left "it failed">>>
runExcept $ optional canFail *> final
Right 42
asum :: (Foldable t, Alternative f) => t (f a) -> f a #
The sum of a collection of actions using (<|>)
, generalizing concat
.
asum
is just like msum
, but generalised to Alternative
.
Examples
Basic usage:
>>>
asum [Just "Hello", Nothing, Just "World"]
Just "Hello"
splitOn :: Char -> Reader e [String] #
The reader that splits a string into a list of strings consuming the separator.
header :: String -> Info e -> Info e #
Set the help text header (it usually includes the application's name and version)
The default value of the variable
Note: specifying it means the parser won't ever fail.
parsePure :: AsUnset e => Parser e a -> [(String, String)] -> Either [(String, e)] a #
Try to parse a pure environment
prefixed :: String -> Parser e a -> Parser e a #
The string to prepend to the name of every declared environment variable
sensitive :: Parser e a -> Parser e a #
Mark the enclosed variables as sensitive to remove them from the environment once they've been parsed successfully.
switch :: String -> Mod Flag Bool -> Parser e Bool #
A simple boolean flag
Note: this parser never fails.
help :: forall (t :: Type -> Type) a. HasHelp t => String -> Mod t a #
Attach help text to the variable
helpDoc :: Parser e a -> String #
A pretty-printed list of recognized environment variables suitable for usage messages
handleError :: ErrorHandler e -> Info x -> Info e #
An error handler
defaultErrorHandler :: (AsUnset e, AsEmpty e, AsUnread e) => ErrorHandler e #
The default error handler
parseOr :: AsUnset e => (String -> IO a) -> (Info Error -> Info e) -> Parser e b -> IO (Either a b) #
Try to parse the environment
Use this if simply dying on failure (the behavior of parse
) is inadequate for your needs.
Replacements
flag :: Off a -> On a -> String -> Mod Flag a -> Parser Error a Source #
Parse a simple flag
If the variable is present and non-empty in the environment, the active value is returned, otherwise the default is used.
>>>
import Blammo.Logging (LogLevel(..))
>>>
flag (Off LevelInfo) (On LevelDebug) "DEBUG" mempty `parsePure` [("DEBUG", "1")]
Right LevelDebug
>>>
flag (Off LevelInfo) (On LevelDebug) "DEBUG" mempty `parsePure` [("DEBUG", "")]
Right LevelInfo
>>>
flag (Off LevelInfo) (On LevelDebug) "DEBUG" mempty `parsePure` []
Right LevelInfo
N.B. only the empty string is falsey:
>>>
flag (Off LevelInfo) (On LevelDebug) "DEBUG" mempty `parsePure` [("DEBUG", "false")]
Right LevelDebug
>>>
flag (Off LevelInfo) (On LevelDebug) "DEBUG" mempty `parsePure` [("DEBUG", "no")]
Right LevelDebug
Extensions
Represents a timeout in seconds or milliseconds
time :: String -> Reader Error UTCTime Source #
Read a time value using the given format
>>>
var (time "%Y-%m-%d") "TIME" mempty `parsePure` [("TIME", "1985-02-12")]
Right 1985-02-12 00:00:00 UTC
>>>
var (time "%Y-%m-%d") "TIME" mempty `parsePure` [("TIME", "10:00PM")]
Left [("TIME",UnreadError "unable to parse time as %Y-%m-%d: \"10:00PM\"")]
keyValues :: Reader Error [(Text, Text)] Source #
Read key-value pairs
>>>
var keyValues "TAGS" mempty `parsePure` [("TAGS", "foo:bar,baz:bat")]
Right [("foo","bar"),("baz","bat")]
Value-less keys are not supported:
>>>
var keyValues "TAGS" mempty `parsePure` [("TAGS", "foo,baz:bat")]
Left [("TAGS",UnreadError "Key foo has no value: \"foo\"")]
Nor are key-less values:
>>>
var keyValues "TAGS" mempty `parsePure` [("TAGS", "foo:bar,:bat")]
Left [("TAGS",UnreadError "Value bat has no key: \":bat\"")]
splitOnParse :: Char -> Reader e a -> Reader e [a] Source #
Use splitOn
then call the given Reader
on each element
splitOnParse
c pure ==splitOn
c
>>>
var (splitOnParse @Error ',' nonempty) "X" mempty `parsePure` [("X", "a,b")]
Right ["a","b"]
>>>
var (splitOnParse @Error ',' nonempty) "X" mempty `parsePure` [("X", ",,")]
Left [("X",EmptyError)]
timeout :: Reader Error Timeout Source #
Read a timeout value as seconds or milliseconds
>>>
var timeout "TIMEOUT" mempty `parsePure` [("TIMEOUT", "10")]
Right (TimeoutSeconds 10)
>>>
var timeout "TIMEOUT" mempty `parsePure` [("TIMEOUT", "10s")]
Right (TimeoutSeconds 10)
>>>
var timeout "TIMEOUT" mempty `parsePure` [("TIMEOUT", "10ms")]
Right (TimeoutMilliseconds 10)
>>>
var timeout "TIMEOUT" mempty `parsePure` [("TIMEOUT", "20m")]
Left [("TIMEOUT",UnreadError "must be {digits}(s|ms): \"20m\"")]
>>>
var timeout "TIMEOUT" mempty `parsePure` [("TIMEOUT", "2m0")]
Left [("TIMEOUT",UnreadError "must be {digits}(s|ms): \"2m0\"")]