conferer 1.0.0.0 → 1.0.0.1
raw patch · 8 files changed
+97/−6 lines, 8 filesPVP: minor bump suggested
API additions: PVP suggests at least a minor version bump
API changes (from Hackage documentation)
+ Conferer: mkConfig' :: Defaults -> [SourceCreator] -> IO Config
+ Conferer.Config: addSources :: [SourceCreator] -> Config -> IO Config
+ Conferer.Config: type Defaults = [(Key, Dynamic)]
+ Conferer.Config.Internal: addSources :: [SourceCreator] -> Config -> IO Config
+ Conferer.FromConfig.Internal: unFile :: File -> FilePath
Files
- CHANGELOG.md +16/−0
- conferer.cabal +3/−2
- src/Conferer.hs +9/−0
- src/Conferer/Config.hs +5/−0
- src/Conferer/Config/Internal.hs +6/−1
- src/Conferer/FromConfig/Internal.hs +8/−2
- test/Conferer/FromConfig/FileSpec.hs +3/−1
- test/ConfererSpec.hs +47/−0
CHANGELOG.md view
@@ -8,9 +8,25 @@ Nothing +## [v1.0.0.1] - 2021-01-17++### Fixed++* In the `File`'s `FromConfig` instance, if the default is present and it's type+is `File`, it throws, which doesn't follow the rest of the library.++### Added++* Add `mkConfig'` which allows creating a config by passing a list of defaults and+a list of source creators.+* Add `addSources`, which allows to add several sources to a config.+* Define the type `Defaults`, which is a list of associations from `Key` to+`Dynamic`.+ ## [v1.0.0.0] - 2020-12-29 First release [Unreleased]: https://github.com/ludat/conferer/compare/conferer_v1.0.0.0...HEAD [v1.0.0.0]: https://github.com/ludat/conferer/releases/tag/v0.0.0.0...conferer_v1.0.0.0+[v1.0.0.1]: https://github.com/ludat/conferer/releases/tag/conferer_v1.0.0.0...conferer_v1.0.0.1
conferer.cabal view
@@ -4,10 +4,10 @@ -- -- see: https://github.com/sol/hpack ----- hash: d0ab7e2b51d28b44a470332f5c24414b3d885483251fb269e6f5e18c00993788+-- hash: e95018cf9b8ebe424a2926412853affcae168760a3b9ea0530fbf3a4c1d83b14 name: conferer-version: 1.0.0.0+version: 1.0.0.1 synopsis: Configuration management library description: Library to abstract the parsing of many haskell config values from different config sources@@ -82,6 +82,7 @@ Conferer.Source.NamespacedSpec Conferer.Source.NullSpec Conferer.Source.PropertiesFileSpec+ ConfererSpec Spec Paths_conferer hs-source-dirs:
src/Conferer.hs view
@@ -16,6 +16,7 @@ -- * Creating a Config mkConfig+ , mkConfig' -- * Getting values from a config -- | These functions allow you to get any type that implements 'FromConfig' , fetch@@ -40,6 +41,7 @@ import qualified Conferer.Source.Env as Env import qualified Conferer.Source.CLIArgs as Cli import qualified Conferer.Source.PropertiesFile as PropertiesFile+import Conferer.Config (Defaults) -- | Use the 'FromConfig' instance to get a value of type @a@ from the config -- using some default fallback. The most common use for this is creating a custom@@ -80,3 +82,10 @@ >>= addSource (Cli.fromConfig) >>= addSource (Env.fromConfig appName) >>= addSource (PropertiesFile.fromConfig "config.file")++-- | Create a 'Config' with the given defaults and source creators.+-- The sources will take precedence by the order they have in the list (earlier in+-- the list means it's tried first).+-- If the requested key is not found in any source it'll be looked up in the defaults.+mkConfig' :: Defaults -> [SourceCreator] -> IO Config+mkConfig' defaults sources = addSources sources . addDefaults defaults $ emptyConfig
src/Conferer/Config.hs view
@@ -17,9 +17,11 @@ -- * Config creation and initialization , emptyConfig , addSource+ , addSources , addDefault , addDefaults , addKeyMappings+ , Defaults -- * Re-Exports , module Conferer.Key , (&)@@ -29,3 +31,6 @@ import Conferer.Config.Internal.Types import Conferer.Key import Data.Function+import Data.Dynamic (Dynamic)++type Defaults = [(Key, Dynamic)]
src/Conferer/Config/Internal.hs view
@@ -13,7 +13,7 @@ {-# LANGUAGE FlexibleContexts #-} module Conferer.Config.Internal where -import Control.Monad (forM, msum)+import Control.Monad (foldM, forM, msum) import Data.Dynamic import Data.List (sort, nub, union) import Data.Text (Text)@@ -213,6 +213,11 @@ config { configSources = configSources config ++ [ newSource ] }++-- | Instantiate several 'Source's using a 'SourceCreator's and a 'Config' and add+-- them to the config in the order defined by the list+addSources :: [SourceCreator] -> Config -> IO Config+addSources sources config = foldM (flip addSource) config sources -- orElse :: IO KeyLookupResult -> IO KeyLookupResult -> IO KeyLookupResult -- orElse getKey1 getKey2 = do
src/Conferer/FromConfig/Internal.hs view
@@ -176,11 +176,17 @@ File FilePath deriving (Show, Eq, Ord, Read) +unFile :: File -> FilePath+unFile (File f) = f+ instance IsString File where fromString s = File s instance FromConfig File where- fetchFromConfig key config = do+ fetchFromConfig key config' = do+ defaultPath <- fetchFromDefaults @File key config'+ let config = removeDefault key config'+ filepath <- fetchFromConfig @(Maybe String) key config extension <- fetchFromConfig @(Maybe String) (key /. "extension") config@@ -194,7 +200,7 @@ $ applyIfPresent FilePath.replaceBaseName basename $ applyIfPresent FilePath.replaceExtension extension $ applyIfPresent FilePath.replaceFileName filename- $ fromMaybe "" filepath+ $ fromMaybe (unFile $ fromMaybe "" defaultPath) filepath if FilePath.isValid constructedFilePath then return $ File constructedFilePath else throwMissingRequiredKeys @String
test/Conferer/FromConfig/FileSpec.hs view
@@ -11,6 +11,8 @@ spec = do context "File fromConfig" $ do describe "fetching a File from config" $ do+ ensureFetchParses @File [] [("", toDyn $ File "file.png")] $+ File "file.png" ensureFetchThrows @File [] [] $ aMissingRequiredKeys @String [ "some.key"@@ -21,7 +23,7 @@ ] ensureFetchThrows @File [] [("", toDyn False)] $- aTypeMismatchWithDefaultError @String "some.key" False+ aTypeMismatchWithDefaultError @File "some.key" False context "with whole path in root" $ do ensureFetchParses @File [ ("", pack $ "some" </> "file.png")
+ test/ConfererSpec.hs view
@@ -0,0 +1,47 @@+{-# LANGUAGE TypeApplications #-}+-- {-# LANGUAGE DeriveGeneric #-}+-- {-# LANGUAGE TypeApplications #-}++module ConfererSpec where++import Test.Hspec++import Data.Text (Text)+import Conferer.FromConfig ( FromConfig(fetchFromConfig) )+import Conferer.Source.InMemory (fromConfig)+import Data.Dynamic (toDyn)+import Conferer.Config (Config)+import Conferer (mkConfig', Key)++spec :: Spec+spec = do+ describe "mkConfig'" $ do+ let a = fromConfig [("keyPresentInBoth", "valueInA"), ("keyPresentOnlyInA", "valueInA")]+ b = fromConfig [("keyPresentInBoth", "valueInB"), ("keyPresentOnlyInB", "valueInB")]+ shouldHaveKeyWithValue :: Config -> Key -> Text -> Expectation+ shouldHaveKeyWithValue config key expected = do+ actual <- fetchFromConfig key config+ actual `shouldBe` expected+ describe "the precedence of the sources is defined by the order in the list" $ do+ it "if several sources have a value for the key, the first source in the list that has it is used" $ do+ config <- mkConfig' [] [a, b]++ config `shouldHaveKeyWithValue` "keyPresentInBoth" $ "valueInA"+ it "if only one source has a value for the key, that source is used" $ do+ config <- mkConfig' [] [a, b]++ config `shouldHaveKeyWithValue` "keyPresentOnlyInB" $ "valueInB"+ it "if the key is not present in any source, it doesn't retrieve any value" $ do+ config <- mkConfig' [] [a, b]++ value <- fetchFromConfig "keyNotPresentInAnySource" config+ value `shouldBe` (Nothing :: Maybe Text)+ describe "adds the defaults to the config" $ do+ it "if the key is present in a source and in the default, it uses the first source that has it" $ do+ config <- mkConfig' [("keyPresentOnlyInA", toDyn @Text "defaultValue")] [a]++ config `shouldHaveKeyWithValue` "keyPresentOnlyInA" $ "valueInA"+ it "if the key is not present in any source but it's in a default, it uses the default" $ do+ config <- mkConfig' [("keyPresentOnlyInA", toDyn @Text "defaultValue")] [b]++ config `shouldHaveKeyWithValue` "keyPresentOnlyInA" $ "defaultValue"