Copyright | Copyright © 2015 PivotCloud Inc. |
---|---|
License | MIT |
Maintainer | Lars Kuhtz <lkuhtz@pivotmail.com> |
Stability | experimental |
Safe Haskell | None |
Language | Haskell2010 |
This module provides tools for defining Maybe configuration types.
- maybeOption :: a -> Bool -> (a -> a) -> Maybe a -> Maybe a
Simple Maybe Values
Optional configuration values are supposed to be encoded by wrapping
the respective type with Maybe
.
For simple values the standard FromJSON
instance from the aeson
package can be used along with the ..:
operator.
data LogConfig = LogConfig { _logLevel ∷ !Int , _logFile ∷ !(Maybe String) } $(makeLenses ''LogConfig) defaultLogConfig ∷ LogConfig defaultLogConfig = LogConfig { _logLevel = 1 , _logFile = Nothing } instance FromJSON (LogConfig → LogConfig) where parseJSON = withObject "LogConfig" $ \o → id <$< logLevel ..: "LogLevel" % o <*< logFile ..: "LogConfig" % o instance ToJSON LogConfig where toJSON config = object [ "LogLevel" .= _logLevel config , "LogConfig" .= _logFile config ]
When defining command line option parsers with .::
and %::
all
options are optional. When an option is not present on the command
line the default value is used. For Maybe
values it is therefore
enough to wrap the parsed value into Just
.
pLogConfig ∷ MParser LogConfig pLogConfig = id <$< logLevel .:: option auto % long "log-level" % metavar "INTEGER" % help "log level" <*< logFile .:: fmap Just % strOption % long "log-file" % metavar "FILENAME" % help "log file name"
Record Maybe Values
For Maybe
types that wrap product (record) types the following orphan FromJSON
instance is provided:
instance (FromJSON (a → a), FromJSON a) ⇒ FromJSON (Maybe a → Maybe a) parseJSON Null = pure (const Nothing) parseJSON v = f <$> parseJSON v <*> parseJSON v where f g _ Nothing = Just g f _ g (Just x) = Just (g x)
(Using an orphan instance is generally problematic but convenient in this case. It's unlikely that an instance for this type is needed elsewhere. If this is an issue for you, please let me know. In that case we can define a new type for optional configuration values.)
The semantics are as follows:
- If the parsed configuration value is
Null
the result isNothing
. If the parsed configuration value is not
Null
then the result is an update function that- updates the given default value if this value is
Just x
or - is a constant function that returns the value that is parsed
from the configuration using the
FromJSON
instance for the configuration type.
- updates the given default value if this value is
Note, that this instance requires an FromJSON
instance for the
configuration type itself as well as a FromJSON
instance for the update
function of the configuration type. The former can be defined by means of the
latter as follows:
instance FromJSON MyType where parseJSON v = parseJSON v <*> pure defaultMyType
This instance will cause the usage of defaultMyType
as default value if the
default value that is given to the configuration parser is Nothing
and the
parsed configuration is not Null
.
:: a | default value that is used if base configuration is |
-> Bool | whether to enable this parser or not (usually is a boolean option parser) |
-> (a -> a) | update function (usually given as applicative 'MParser a') |
-> Maybe a | the base value that is updated (usually the result of parsing the configuration file) |
-> Maybe a |
Command line parser for record Maybe
values
Example:
data Setting = Setting { _setA ∷ !Int , _setB ∷ !String } deriving (Show, Read, Eq, Ord, Typeable) $(makeLenses ''Setting) defaultSetting ∷ Setting defaultSetting = Setting { _setA = 0 , _setB = 1 } instance ToJSON Setting where toJSON setting = object [ "a" .= _setA setting , "b" .= _setB setting ] instance FromJSON (Setting → Setting) where parseJSON = withObject "Setting" $ \o → id <$< setA ..: "a" % o <*< setB ..: "b" % o instance FromJSON Setting where parseJSON v = parseJSON v <*> pure defaultSetting pSetting ∷ MParser Setting pSetting = id <$< setA .:: option auto % short 'a' <> metavar "INT" <> help "set a" <*< setB .:: option auto % short 'b' <> metavar "INT" <> help "set b" -- | Use 'Setting' as 'Maybe' in a configuration: -- data Config = Config { _maybeSetting ∷ !(Maybe Setting) } deriving (Show, Read, Eq, Ord, Typeable) $(makeLenses ''Config) defaultConfig ∷ Config defaultConfig = Config { _maybeSetting = defaultSetting } instance ToJSON Config where toJSON config = object [ "setting" .= maybeSetting ] instance FromJSON (Config → Config) where parseJSON = withObject "Config" $ \o → id <$< maybeSetting %.: "setting" % o pConfig ∷ MParser Config pConfig = id <$< maybeSetting %:: (maybeOption defaultSetting <$> pEnableSetting <*> pSetting) where pEnableSetting = boolOption % long "setting-enable" <> value False <> help "Enable configuration flags for setting"