salak-0.2.4: src/Salak.hs
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE RecordWildCards #-}
-- |
-- Module: Salak
-- Copyright: (c) 2019 Daniel YU
-- License: BSD3
-- Maintainer: leptonyu@gmail.com
-- Stability: experimental
-- Portability: portable
--
-- Configuration Loader for Production in Haskell.
--
module Salak(
-- * How to use this library
-- $use
-- * Source
Selector
, SourcePack
, SourcePackT
, Reload(..)
, load
, loadJSON
, loadYaml
, loadEnv
-- * Salak
, defaultLoadSalak
, loadSalak
, PropConfig(..)
, HasSourcePack(..)
, fetch
, require
-- * Utilities
, ReloadableSourcePack
, runReloadable
, Prop
, FromProp(..)
, PResult(..)
, readPrimitive
, readSelect
, err
) where
import Control.Monad (unless)
import Control.Monad.IO.Class (MonadIO)
import Control.Monad.Reader
import Data.Default
import Data.Text (Text)
import Salak.Dynamic
import Salak.Env
import Salak.Json
import Salak.Prop
import Salak.Types
data PropConfig = PropConfig
{ configFileKey :: Maybe String
, commandLine :: ParseCommandLine
}
instance Default PropConfig where
def = PropConfig Nothing defaultParseCommandLine
loadSalak :: Monad m => ReaderT SourcePack m a -> SourcePackT m () -> m a
loadSalak a spm = do
(es, sp) <- runSourcePackT spm
unless (null es) $ do
fail (head es)
runReaderT a sp
defaultLoadSalak :: MonadIO m => PropConfig -> ReaderT SourcePack m a -> m a
defaultLoadSalak PropConfig{..} a = loadSalak a $ do
loadCommandLine commandLine
loadEnv
go configFileKey
where
go (Just file) = loadYaml file
go _ = return ()
class Monad m => HasSourcePack m where
askSourcePack :: m SourcePack
fetch :: (HasSourcePack m, FromProp a) => Text -> m (Either String a)
fetch key = askSourcePack >>= return . search key
require :: (HasSourcePack m, FromProp a) => Text -> m a
require k = do
x <- fetch k
case x of
Left e -> fail e
Right v -> return v
instance Monad m => HasSourcePack (ReaderT SourcePack m) where
askSourcePack = ask
-- $use
--
-- | This library default a standard configuration load process. It can load properties from `CommandLine`, `Environment`,
-- `JSON value` and `Yaml` files. They all load to the same format `SourcePack`. Earler property source has higher order
-- to load property. For example:
--
-- > CommandLine: --package.a.enabled=true
-- > Environment: PACKAGE_A_ENABLED: false
--
-- > lookup "package.a.enabled" properties => Just True
--
-- `CommandLine` has higher order then `Environment`, for the former load properties earler then later.
--
-- Usage:
--
-- > data Config = Config
-- > { name :: Text
-- > , dir :: Maybe Text
-- > , ext :: Int
-- > } deriving (Eq, Show)
-- >
-- > instance FromProp Config where
-- > fromProp = Config
-- > <$> "user"
-- > <*> "pwd"
-- > <*> "ext" .?= 1
--
-- > main = do
-- > c :: Config <- defaultLoadSalak def $ require ""
-- > print c
--
-- > λ> c
-- > Config {name = "daniel", dir = Nothing, ext = 1}