Safe Haskell | None |
---|---|
Language | Haskell2010 |
- data a :*> b = a :*> b
- data s :> t
- data a :>: s
- data ConfigCode k
- = Record (ConfigCode k) (ConfigCode k)
- | Label Symbol (ConfigCode k)
- | Descr (ConfigCode k) Symbol
- | List (ConfigCode k)
- | Option (ConfigCode k)
- | Type k
- type family ToConfigCode a :: ConfigCode *
- type family NoDesc a :: ConfigCode *
- type family ToConfig a f :: *
- data MaybeO a
- data Id a = Id a
- data Source
- = ConfigFileYaml SBS
- | ShellEnv [(String, String)]
- | CommandLine [String]
- data ConfigFile
- data ShellEnv
- data CommandLine
- data Tagged cfg = Tagged {
- fromTagged :: ToConfig cfg Id
- data TaggedM cfg = TaggedM {
- fromTaggedM :: ToConfig cfg Maybe
- type Result cfg = Either Error (Tagged cfg)
- data Error
- configify :: forall cfg tm. (tm ~ TaggedM cfg, Show tm, Monoid tm, Freeze cfg, FromJSON tm, HasParseShellEnv cfg, HasParseCommandLine cfg, CanonicalizePartial cfg) => [Source] -> Result cfg
- configify' :: forall cfg tm. (tm ~ TaggedM cfg, Show tm, Monoid tm, Freeze cfg, FromJSON tm, HasParseShellEnv cfg, HasParseCommandLine cfg, CanonicalizePartial cfg) => tm -> [Source] -> Result cfg
- parseConfigFile :: FromJSON (TaggedM cfg) => SBS -> Either Error (TaggedM cfg)
- renderConfigFile :: (Freeze cfg, t ~ Tagged cfg, ToJSON (TaggedM cfg)) => t -> SBS
- type Env = [(String, String)]
- class HasParseShellEnv cfg where
- parseShellEnv :: Env -> Either Error (TaggedM cfg)
- type Args = [String]
- class HasParseCommandLine cfg where
- parseCommandLine :: [String] -> Either Error (TaggedM cfg)
- primitiveParseCommandLine :: HasParseShellEnv cfg => [String] -> Either Error (TaggedM cfg)
- parseArgs :: Args -> Either String Env
- parseArgsWithEqSign :: String -> Either String Env
- parseArgsWithSpace :: String -> String -> Either String Env
- parseArgName :: String -> String
- (>>.) :: forall cfg ps r. (Sel cfg ps, ToValE cfg ps ~ Done r) => Tagged cfg -> Proxy ps -> r
- type family ToVal a p :: Maybe *
- type family OrElse x y :: Maybe k
- data CMaybe a where
- orElse :: CMaybe a -> CMaybe b -> CMaybe (OrElse a b)
- type family ToValueMaybe a :: Maybe *
- toValueMaybe :: CMaybe a -> CMaybe (ToValueMaybe a)
- class NothingValue a where
- nothingValue :: Proxy a -> CMaybe (ToValueMaybe a)
- class Sel cfg ps where
- class Sel' cfg ps where
- type ToValE a p = ToExc (LookupFailed a p) (ToVal a p)
- data Exc a b
- data LookupFailed a p
- type family ToExc a x :: Exc k l
- merge :: forall cfg tm ti. (tm ~ TaggedM cfg, ti ~ Tagged cfg, Freeze cfg, Monoid tm, CanonicalizePartial cfg) => [tm] -> Either Error ti
- freeze :: forall cfg tm ti. (tm ~ TaggedM cfg, ti ~ Tagged cfg, Freeze cfg) => tm -> Either Error ti
- thaw :: forall cfg tm ti. (tm ~ TaggedM cfg, ti ~ Tagged cfg, Freeze cfg) => ti -> tm
- class Freeze c where
- class CanonicalizePartial a where
- canonicalizePartial :: TaggedM a -> TaggedM a
- emptyPartial :: TaggedM a -> Bool
- docs :: (HasToDoc a, HasRenderDoc ConfigFile, HasRenderDoc ShellEnv, HasRenderDoc CommandLine) => Proxy a -> ST
- data Doc
- data DocOptional
- concatDoc :: Doc -> Doc -> Doc
- class HasToDoc a where
- class HasRenderDoc t where
config types
Construction of config records (cons
for record fields).
a :*> b infixr 6 |
Add descriptive text to record field for documentation.
data ConfigCode k Source
Record (ConfigCode k) (ConfigCode k) infixr 6 | |
Label Symbol (ConfigCode k) | |
Descr (ConfigCode k) Symbol | |
List (ConfigCode k) | |
Option (ConfigCode k) | |
Type k |
type family ToConfigCode a :: ConfigCode * Source
Map user-provided config type to ConfigCode
types.
ToConfigCode (a :*> b) = Record (ToConfigCode a) (ToConfigCode b) | |
ToConfigCode (s :> a) = Label s (ToConfigCode a) | |
ToConfigCode (a :>: s) = Descr (ToConfigCode a) s | |
ToConfigCode [a] = List (ToConfigCode a) | |
ToConfigCode (Maybe a) = Option (ToConfigCode a) | |
ToConfigCode a = Type a |
type family NoDesc a :: ConfigCode * Source
Filter Descr
constructors from ConfigCode
.
sources
tagged values
Tagged | |
|
TaggedM | |
|
Eq (ToConfig cfg Maybe) => Eq (TaggedM cfg) | |
Show (ToConfig cfg Maybe) => Show (TaggedM cfg) | |
ToJSON a => ToJSON (TaggedM (Type * a)) | instance ToJSON Type |
((~) * t (ToConfig cfg Maybe), (~) * (ToConfig (Option * cfg) Maybe) (MaybeO t''), ToJSON (TaggedM cfg)) => ToJSON (TaggedM (Option * cfg)) | instance ToJSON Option |
((~) * t (ToConfig cfg Maybe), ToJSON (TaggedM cfg)) => ToJSON (TaggedM (List * cfg)) | instance ToJSON List |
(ToJSON (TaggedM cfg), KnownSymbol s) => ToJSON (TaggedM (Label * s cfg)) | instance ToJSON Label |
((~) * t1 (ToConfig cfg1 Maybe), ToJSON (TaggedM cfg1), (~) * t2 (ToConfig cfg2 Maybe), ToJSON (TaggedM cfg2)) => ToJSON (TaggedM (Record * cfg1 cfg2)) | instance ToJSON Record |
FromJSON a => FromJSON (TaggedM (Type * a)) | instance FromJSON Type |
FromJSON (TaggedM cfg) => FromJSON (TaggedM (Option * cfg)) | instance ParseJSON Option |
FromJSON (TaggedM cfg) => FromJSON (TaggedM (List * cfg)) | instance ParseJSON List |
(FromJSON (TaggedM cfg), KnownSymbol s) => FromJSON (TaggedM (Label * s cfg)) |
|
(FromJSON (TaggedM cfg1), FromJSON (TaggedM cfg2)) => FromJSON (TaggedM (Record * cfg1 cfg2)) | instance FromJSON Record |
Monoid (TaggedM a) => Monoid (TaggedM (Option * a)) | |
Monoid (TaggedM (List * a)) | Lists are initialized empty by default. Append overwrites left values with right values. (If we tried to append list elements recursively, there would be awkward questions about matching list lengths.) |
Monoid (TaggedM (Label * s (Type * a))) | There is no |
Monoid (TaggedM a) => Monoid (TaggedM (Label * s a)) | If one of two configs is |
(Monoid (TaggedM a), Monoid (TaggedM b)) => Monoid (TaggedM (Record * a b)) |
results and errors
the main function
configify :: forall cfg tm. (tm ~ TaggedM cfg, Show tm, Monoid tm, Freeze cfg, FromJSON tm, HasParseShellEnv cfg, HasParseCommandLine cfg, CanonicalizePartial cfg) => [Source] -> Result cfg Source
configify' :: forall cfg tm. (tm ~ TaggedM cfg, Show tm, Monoid tm, Freeze cfg, FromJSON tm, HasParseShellEnv cfg, HasParseCommandLine cfg, CanonicalizePartial cfg) => tm -> [Source] -> Result cfg Source
yaml / json
shell env
class HasParseShellEnv cfg where Source
(Typeable * a, FromJSON (TaggedM (Type * a))) => HasParseShellEnv (Type * a) | |
HasParseShellEnv a => HasParseShellEnv (Option * a) | |
HasParseShellEnv a => HasParseShellEnv (List * a) | You can provide a list value via the shell environment by providing a single element. This element will be put into a list implicitly. (A more general approach that allows for yaml-encoded list values in shell variables is more tricky to design, implement, and use: If you have a list of sub-configs and don't want the entire sub-config to be yaml-encoded, but use a longer shell variable name to go further down to deeper sub-configs, there is a lot of ambiguity. It may be possible to resolve that at run-time, but it's more tricky.) |
(KnownSymbol path, HasParseShellEnv a) => HasParseShellEnv (Label * path a) | The paths into the recursive structure of the config file are concatenated to shell variable names with separating '_'. (It is still ok to have '_' in your config path names. This parser chops off complete matching names, whether they contain '_' or not, and only then worries about trailing '_'.) |
(HasParseShellEnv a, HasParseShellEnv b) => HasParseShellEnv (Record * a b) |
cli
class HasParseCommandLine cfg where Source
HasParseShellEnv cfg => HasParseCommandLine cfg |
primitiveParseCommandLine :: HasParseShellEnv cfg => [String] -> Either Error (TaggedM cfg) Source
Very basic fist approach: read --(key)(=|s+)(value)
;
construct shell env from keys and names, and use parseShellEnv
on
the command line. If it doesn't like the syntax used in the
command line, it will crash. I hope for this to get much fancier
in the future.
parseArgName :: String -> String Source
accessing config values
(>>.) :: forall cfg ps r. (Sel cfg ps, ToValE cfg ps ~ Done r) => Tagged cfg -> Proxy ps -> r infix 7 Source
Map a Tagged
config value and a type-level path to the part of
the config value the path points to. Trigger an informative type
error if path does not exist.
options
type family ToValueMaybe a :: Maybe * Source
ToValueMaybe (Just x) = Just (Maybe x) | |
ToValueMaybe Nothing = Nothing |
toValueMaybe :: CMaybe a -> CMaybe (ToValueMaybe a) Source
class NothingValue a where Source
nothingValue :: Proxy a -> CMaybe (ToValueMaybe a) Source
NothingValue (Nothing *) | |
NothingValue (Just * x) |
cfg traversal
Sel' cfg ps => Sel cfg ps | |
((~) (ConfigCode *) cfg (Option * cfg'), NothingValue (ToVal cfg' ps), Sel cfg' ps) => Sel (Option * cfg') ps | |
Sel (Record * cfg' cfg'') ([] Symbol) | |
((~) (ConfigCode *) cfg (Label * p cfg'), (~) * t (ToConfig cfg Id), Sel cfg' ps, KnownSymbol p) => Sel (Label * p cfg') ((:) Symbol p ps) | |
((~) (ConfigCode *) cfg (Record * cfg' cfg''), Sel cfg' ((:) Symbol p ps), Sel cfg'' ((:) Symbol p ps)) => Sel (Record * cfg' cfg'') ((:) Symbol p ps) |
static lookup error handling
type ToValE a p = ToExc (LookupFailed a p) (ToVal a p) Source
data LookupFailed a p Source
merge configs
merge :: forall cfg tm ti. (tm ~ TaggedM cfg, ti ~ Tagged cfg, Freeze cfg, Monoid tm, CanonicalizePartial cfg) => [tm] -> Either Error ti Source
freeze :: forall cfg tm ti. (tm ~ TaggedM cfg, ti ~ Tagged cfg, Freeze cfg) => tm -> Either Error ti Source
Freeze (Type * c) | |
((~) * (ToConfig (Option * c) Maybe) (MaybeO tm), (~) * (ToConfig (Option * c) Id) (MaybeO ti), (~) * tm (ToConfig c Maybe), (~) * ti (ToConfig c Id), Freeze c) => Freeze (Option * c) | FIXME: if a non-optional part of an optional sub-config is
missing, the |
Freeze c => Freeze (List * c) | |
(KnownSymbol s, Freeze t) => Freeze (Label * s t) | |
(Freeze a, Freeze b) => Freeze (Record * a b) |
class CanonicalizePartial a where Source
canonicalizePartial :: TaggedM a -> TaggedM a Source
emptyPartial :: TaggedM a -> Bool Source
CanonicalizePartial (Type * a) | |
((~) (ConfigCode *) cfg (Option * cfg'), CanonicalizePartial cfg') => CanonicalizePartial (Option * cfg') | |
((~) (ConfigCode *) cfg (List * cfg'), CanonicalizePartial cfg') => CanonicalizePartial (List * cfg') | |
((~) (ConfigCode *) cfg (Label * s cfg'), CanonicalizePartial cfg') => CanonicalizePartial (Label * s cfg') | |
(CanonicalizePartial cfg, CanonicalizePartial cfg') => CanonicalizePartial (Record * cfg cfg') |
docs
docs :: (HasToDoc a, HasRenderDoc ConfigFile, HasRenderDoc ShellEnv, HasRenderDoc CommandLine) => Proxy a -> ST Source
data DocOptional Source
Typeable * a => HasToDoc (Type * a) | |
HasToDoc a => HasToDoc (Option * a) | |
HasToDoc a => HasToDoc (List * a) | |
(HasToDoc a, KnownSymbol path, KnownSymbol descr) => HasToDoc (Descr * (Label * path a) descr) | |
(KnownSymbol path, HasToDoc a) => HasToDoc (Label * path a) | |
(HasToDoc a, HasToDoc b) => HasToDoc (Record * a b) |
class HasRenderDoc t where Source