packages feed

cfg 0.0.2.3 → 0.0.2.4

raw patch · 6 files changed

+176/−9 lines, 6 filesdep ~basedep ~containersdep ~doctestPVP: minor bump suggested

API additions: PVP suggests at least a minor version bump

Dependency ranges changed: base, containers, doctest

API changes (from Hackage documentation)

+ Cfg: instance Cfg.Parser.ConfigParser Cfg.AppConfig6
+ Cfg: instance Cfg.Source.ConfigSource Cfg.AppConfig6
+ Cfg: instance Cfg.Source.Default.DefaultSource Cfg.AppConfig6
+ Cfg: instance GHC.Generics.Generic Cfg.AppConfig6
+ Cfg: instance GHC.Show.Show Cfg.AppConfig6
+ Cfg.Optional: OptionalConfig :: Maybe a -> OptionalConfig a
+ Cfg.Optional: [getOptionalConfig] :: OptionalConfig a -> Maybe a
+ Cfg.Optional: allAbsent :: KeyTree k v -> Bool
+ Cfg.Optional: instance Cfg.Parser.ConfigParser a => Cfg.Parser.ConfigParser (Cfg.Optional.OptionalConfig a)
+ Cfg.Optional: instance Cfg.Source.ConfigSource a => Cfg.Source.ConfigSource (Cfg.Optional.OptionalConfig a)
+ Cfg.Optional: instance GHC.Classes.Eq a => GHC.Classes.Eq (Cfg.Optional.OptionalConfig a)
+ Cfg.Optional: instance GHC.Classes.Ord a => GHC.Classes.Ord (Cfg.Optional.OptionalConfig a)
+ Cfg.Optional: instance GHC.Show.Show a => GHC.Show.Show (Cfg.Optional.OptionalConfig a)
+ Cfg.Optional: newtype OptionalConfig a
+ Cfg.Parser: ExpectedForestFoundValue :: Text -> ConfigParseError

Files

cfg.cabal view
@@ -1,6 +1,6 @@ cabal-version: 3.0 name:          cfg-version:       0.0.2.3+version:       0.0.2.4 synopsis:   Type directed application configuration parsing and accessors @@ -59,8 +59,8 @@     UndecidableInstances    build-depends:-    , base           >=4.16.0 && <4.20-    , containers     >=0.6    && <0.7+    , base           >=4.16.0 && <5+    , containers     >=0.6     , free           >=5.0.1  && <5.3     , mtl            >=2.1    && <2.4     , pretty-simple  >=4.0    && <4.2@@ -86,6 +86,7 @@     Cfg.Deriving.Value     Cfg.Env     Cfg.Env.Keys+    Cfg.Optional     Cfg.Options     Cfg.Parser     Cfg.Parser.Config@@ -112,6 +113,7 @@     Cfg.Deriving.KeyModifierSpec     Cfg.Env.KeysSpec     Cfg.EnvSpec+    Cfg.OptionalSpec     Cfg.ParserSpec     Cfg.SourceSpec     Spec@@ -134,4 +136,4 @@   main-is:        Main.hs   build-depends:     , cfg-    , doctest  >=0.21.1 && <0.23+    , doctest  >=0.21.1
src/Cfg.hs view
@@ -341,6 +341,7 @@ import Data.Text (Text) import GHC.Generics import KeyTree+import Cfg.Optional (OptionalConfig)  -- | @since 0.0.1.0 getConfigRaw@@ -479,5 +480,20 @@     via (ConfigOpts [StripPrefix "appConfig", StripSuffix "Settings", ToUpper] AppConfig5)  instance DefaultSource AppConfig5 where+  defaults "appConfigEnvironment" = Just "Development"+  defaults _ = Nothing++-- Example 6+data AppConfig6 = AppConfig6+  { appConfigWarpSettings :: OptionalConfig WarpConfig+  , appConfigRedisSettings :: RedisConfig+  , appConfigEnvironment :: Environment+  }+  deriving (Generic, Show)+  deriving+    (ConfigSource, ConfigParser)+    via (ConfigOpts [StripPrefix "appConfig", StripSuffix "Settings", ToUpper] AppConfig6)++instance DefaultSource AppConfig6 where   defaults "appConfigEnvironment" = Just "Development"   defaults _ = Nothing
+ src/Cfg/Optional.hs view
@@ -0,0 +1,25 @@+module Cfg.Optional where++import Cfg.Parser (ConfigParser (..), ConfigParseError (ExpectedForestFoundValue))+import Cfg.Source (ConfigSource (..))+import Control.Monad.Free+import Data.Map.Strict qualified as M+import KeyTree++-- True when no leaf in the subtree carries a value.+allAbsent :: KeyTree k v -> Bool+allAbsent (Free m) = all allAbsent (M.elems m)+allAbsent (Pure _) = False++newtype OptionalConfig a = OptionalConfig {getOptionalConfig :: Maybe a}+  deriving newtype (Eq, Ord, Show)++instance ConfigParser a => ConfigParser (OptionalConfig a) where+  parseConfig cfg@(Free _) =+    if allAbsent cfg+      then Right $ OptionalConfig Nothing+      else OptionalConfig . Just <$> parseConfig cfg+  parseConfig (Pure val) = Left $ ExpectedForestFoundValue val++instance ConfigSource a => ConfigSource (OptionalConfig a) where+  configSource = configSource @a
src/Cfg/Parser.hs view
@@ -80,6 +80,10 @@       Text       -- ^ The key that was missing       Text+  | -- | Expected to find a subtree aka a 'Free' with a map in it, but instead+    -- we found a 'Pure'.+    ExpectedForestFoundValue+      Text       -- ^ The value that was found   | -- | Expected to find a 'Pure' with a value but instead found a subtree     ExpectedValueFoundForest@@ -122,7 +126,7 @@  -- | @since 0.0.1.0 instance ValueParser () where-  parser = string "()" >> pure ()+  parser = void $ string "()"  -- | @since 0.0.1.0 instance ConfigParser ()@@ -203,7 +207,7 @@  -- | @since 0.0.2.0 minus :: Parser Text-minus = liftA2 (T.cons) (char '-') number+minus = liftA2 T.cons (char '-') number  -- | @since 0.0.2.0 number :: Parser Text@@ -211,7 +215,7 @@  -- | @since 0.0.2.0 decimal :: Parser Text-decimal = option "" $ (T.cons) <$> char '.' <*> number+decimal = option "" $ T.cons <$> char '.' <*> number  -- | @since 0.0.2.0 integral :: (Read a) => Parser a@@ -219,7 +223,7 @@  -- | @since 0.0.2.0 fractional :: (Read a) => Parser a-fractional = fmap rd $ liftA2 (<>) integral decimal+fractional = rd <$> liftA2 (<>) integral decimal  -- | @since 0.0.1.0 instance ValueParser Double where
src/Cfg/Parser/Config.hs view
@@ -42,7 +42,7 @@   => ConfigOptions   -> KeyTree Text Text   -> Either ConfigParseError a-defaultParseConfig opts tree = fmap to $ gParseConfig opts tree+defaultParseConfig opts tree = to <$> gParseConfig opts tree  -- | This class is the generic version of 'ConfigParser'. It recurses on the -- generic structure of a type, building up a return type for the parser.
+ test/Cfg/OptionalSpec.hs view
@@ -0,0 +1,120 @@+module Cfg.OptionalSpec where++import Cfg.Deriving.Config+import Cfg.Parser+import Data.Map.Strict (empty, fromList)+import Data.Text (Text)+import GHC.Generics (Generic (..))+import KeyTree+import Test.Hspec+import Cfg.Source (ConfigSource (..))+import Cfg.Optional (OptionalConfig (..))+import Cfg.Source.Default (DefaultSource)++data SubSubTyCon = SubSubDataCon+  { subSubKey1 :: Text+  , subSubKey2 :: Int+  }+  deriving (Generic, Show, Eq, DefaultSource)+  deriving (ConfigParser, ConfigSource) via (Config SubSubTyCon)++data SubTyCon = SubDataCon+  { subKey2 :: Int+  , subKey1 :: OptionalConfig SubSubTyCon+  }+  deriving (Generic, Show, Eq, DefaultSource)+  deriving (ConfigParser, ConfigSource) via (Config SubTyCon)++data RootTyCon = RootDataCon+  { key1 :: Bool+  , key2 :: SubTyCon+  }+  deriving (Generic, Show, Eq, DefaultSource)+  deriving (ConfigParser, ConfigSource) via (Config RootTyCon)++spec :: Spec+spec = do+  describe "configParser" $ do+    it "should parse a type from the sample config containing a present optional config" $ do+      let+        subSubConfig = SubSubDataCon "Hello World" 27+        subConfig = SubDataCon 64 (OptionalConfig $ Just subSubConfig)+        expected = RootDataCon True subConfig+        underTest =+          Free $+            fromList+              [ ("key1", Pure "True")+              ,+                ( "key2"+                , Free $+                    fromList+                      [ ("subKey1"+                        , Free $ fromList+                          [ ("subSubKey1", Pure "Hello World")+                          , ("subSubKey2", Pure "27")+                          ]+                        )+                      , ("subKey2", Pure "64")+                      ]+                )+              ]+      parseConfig underTest `shouldBe` Right expected+    it "should parse a type from the sample config with a missing optional config" $ do+      let+        subConfig = SubDataCon 64 (OptionalConfig Nothing)+        expected = RootDataCon True subConfig+        underTest =+          Free $+            fromList+              [ ("key1", Pure "True")+              , ("key2"+                , Free $ fromList+                    [ ("subKey2", Pure "64")+                    , ("subKey1", Free empty)+                    ]+                )+              ]+      parseConfig underTest `shouldBe` Right expected+    it "should parse Nothing when optional config has key stubs but no values (env source style)" $ do+      let+        subConfig = SubDataCon 64 (OptionalConfig Nothing)+        expected = RootDataCon True subConfig+        underTest =+          Free $+            fromList+              [ ("key1", Pure "True")+              , ("key2"+                , Free $ fromList+                    [ ("subKey2", Pure "64")+                    , ("subKey1"+                      , Free $ fromList+                          [ ("subSubKey1", Free empty)+                          , ("subSubKey2", Free empty)+                          ]+                      )+                    ]+                )+              ]+      parseConfig underTest `shouldBe` Right expected+  describe "configSource" $ do+    it "should create a tree from the sample config" $ do+      let+        expected =+          Free $+            fromList+              [ ("key1", Free empty)+              ,+                ( "key2"+                , Free $+                    fromList+                      [ ("subKey1"+                        , Free $ fromList+                          [ ("subSubKey1", Free empty)+                          , ("subSubKey2", Free empty)+                          ]+                        )+                      , ("subKey2", Free empty)+                      ]+                )+              ]+      configSource @RootTyCon `shouldBe` expected