mmzk-env 0.2.1.0 → 0.2.1.1
raw patch · 4 files changed
+77/−3 lines, 4 filesPVP: major bump suggested
API removals or changes: PVP suggests a major version bump
API changes (from Hackage documentation)
- Data.Env.EnumParser: instance (GHC.Internal.Enum.Enum a, GHC.Internal.Show.Show a, GHC.Internal.Enum.Bounded a) => Data.Env.TypeParser.TypeParser (Data.Env.EnumParser.EnumParser a)
- Data.Env.EnumParser: instance GHC.Internal.Show.Show a => GHC.Internal.Show.Show (Data.Env.EnumParser.EnumParser a)
- Data.Env.ExtractFields: instance (GHC.Internal.Generics.Generic a, Data.Env.ExtractFields.GExtractFields (GHC.Internal.Generics.Rep a)) => Data.Env.ExtractFields.ExtractFields a
- Data.Env.ExtractFields: instance GHC.Internal.Generics.Selector s => Data.Env.ExtractFields.GExtractFields (GHC.Internal.Generics.M1 GHC.Internal.Generics.S s (GHC.Internal.Generics.K1 i a))
- Data.Env.ExtractFields: instance forall k (f :: k -> *) (c :: GHC.Internal.Generics.Meta). Data.Env.ExtractFields.GExtractFields f => Data.Env.ExtractFields.GExtractFields (GHC.Internal.Generics.M1 GHC.Internal.Generics.C c f)
- Data.Env.ExtractFields: instance forall k (f :: k -> *) (c :: GHC.Internal.Generics.Meta). Data.Env.ExtractFields.GExtractFields f => Data.Env.ExtractFields.GExtractFields (GHC.Internal.Generics.M1 GHC.Internal.Generics.D c f)
- Data.Env.ExtractFields: instance forall k (f :: k -> *) (g :: k -> *). (Data.Env.ExtractFields.GExtractFields f, Data.Env.ExtractFields.GExtractFields g) => Data.Env.ExtractFields.GExtractFields (f GHC.Internal.Generics.:*: g)
- Data.Env.RecordParser: instance (Data.Env.TypeParser.TypeParser a, GHC.Internal.Generics.Selector s) => Data.Env.RecordParser.GRecordParser (GHC.Internal.Generics.M1 GHC.Internal.Generics.S s (GHC.Internal.Generics.K1 i a))
- Data.Env.RecordParser: instance (GHC.Internal.Generics.Generic a, Data.Env.RecordParser.GRecordParser (GHC.Internal.Generics.Rep a)) => Data.Env.RecordParser.RecordParser a
- Data.Env.RecordParser: instance forall k (f :: k -> *) (c :: GHC.Internal.Generics.Meta). Data.Env.RecordParser.GRecordParser f => Data.Env.RecordParser.GRecordParser (GHC.Internal.Generics.M1 GHC.Internal.Generics.C c f)
- Data.Env.RecordParser: instance forall k (f :: k -> *) (c :: GHC.Internal.Generics.Meta). Data.Env.RecordParser.GRecordParser f => Data.Env.RecordParser.GRecordParser (GHC.Internal.Generics.M1 GHC.Internal.Generics.D c f)
- Data.Env.RecordParser: instance forall k (f :: k -> *) (g :: k -> *). (Data.Env.RecordParser.GRecordParser f, Data.Env.RecordParser.GRecordParser g) => Data.Env.RecordParser.GRecordParser (f GHC.Internal.Generics.:*: g)
- Data.Env.RecordParserW: instance (Data.Env.TypeParserW.TypeParserW p a, GHC.Internal.Generics.Selector s) => Data.Env.RecordParserW.GRecordParserW (GHC.Internal.Generics.M1 GHC.Internal.Generics.S s (GHC.Internal.Generics.K1 i (p, a)))
- Data.Env.RecordParserW: instance (GHC.Internal.Generics.Generic (a 'Data.Env.RecordParserW.Dec), Data.Env.RecordParserW.GRecordParserW (GHC.Internal.Generics.Rep (a 'Data.Env.RecordParserW.Dec)), GHC.Internal.Generics.Generic (a 'Data.Env.RecordParserW.Res), Data.Env.RecordParserW.GRecordParsedType (GHC.Internal.Generics.Rep (a 'Data.Env.RecordParserW.Dec)) () GHC.Types.~ GHC.Internal.Generics.Rep (a 'Data.Env.RecordParserW.Res) ()) => Data.Env.RecordParserW.RecordParserW (a 'Data.Env.RecordParserW.Dec)
- Data.Env.RecordParserW: instance GHC.Internal.Show.Show Data.Env.RecordParserW.ColumnType
- Data.Env.RecordParserW: instance forall k (f :: k -> *) (c :: GHC.Internal.Generics.Meta). Data.Env.RecordParserW.GRecordParserW f => Data.Env.RecordParserW.GRecordParserW (GHC.Internal.Generics.M1 GHC.Internal.Generics.C c f)
- Data.Env.RecordParserW: instance forall k (f :: k -> *) (c :: GHC.Internal.Generics.Meta). Data.Env.RecordParserW.GRecordParserW f => Data.Env.RecordParserW.GRecordParserW (GHC.Internal.Generics.M1 GHC.Internal.Generics.D c f)
- Data.Env.RecordParserW: instance forall k (f :: k -> *) (g :: k -> *). (Data.Env.RecordParserW.GRecordParserW f, Data.Env.RecordParserW.GRecordParserW g) => Data.Env.RecordParserW.GRecordParserW (f GHC.Internal.Generics.:*: g)
- Data.Env.TypeParser: ($dmparseType) :: (TypeParser a, Generic a, GTypeParser (Rep a)) => String -> Either String a
- Data.Env.TypeParser: instance Data.Env.TypeParser.TypeParser GHC.Internal.Base.String
- Data.Env.TypeParser: instance Data.Env.TypeParser.TypeParser GHC.Internal.Int.Int16
- Data.Env.TypeParser: instance Data.Env.TypeParser.TypeParser GHC.Internal.Int.Int32
- Data.Env.TypeParser: instance Data.Env.TypeParser.TypeParser GHC.Internal.Int.Int64
- Data.Env.TypeParser: instance Data.Env.TypeParser.TypeParser GHC.Internal.Int.Int8
- Data.Env.TypeParser: instance Data.Env.TypeParser.TypeParser GHC.Internal.Word.Word16
- Data.Env.TypeParser: instance Data.Env.TypeParser.TypeParser GHC.Internal.Word.Word32
- Data.Env.TypeParser: instance Data.Env.TypeParser.TypeParser GHC.Internal.Word.Word64
- Data.Env.TypeParser: instance Data.Env.TypeParser.TypeParser GHC.Internal.Word.Word8
- Data.Env.TypeParser: instance Data.Env.TypeParser.TypeParser a => Data.Env.TypeParser.TypeParser (GHC.Internal.Maybe.Maybe a)
- Data.Env.TypeParser: instance Data.Env.TypeParser.TypeParser a => Data.Env.TypeParser.TypeParser (GHC.Tuple.Solo a)
- Data.Env.TypeParserW: instance (Data.Env.TypeParserW.TypeParserW p1 GHC.Internal.Base.String, Data.Env.TypeParserW.TypeParserW p2 GHC.Internal.Base.String) => Data.Env.TypeParserW.TypeParserW (p1, p2) GHC.Internal.Base.String
- Data.Env.TypeParserW: instance Data.Env.TypeParser.TypeParser a => Data.Env.TypeParserW.TypeParserW (GHC.Tuple.Solo a) a
- Data.Env.Witness.DefaultNum: instance (Data.Env.TypeParser.TypeParser a, GHC.Internal.Num.Num a, GHC.Internal.TypeNats.KnownNat n) => Data.Env.TypeParserW.TypeParserW (Data.Env.Witness.DefaultNum.DefaultNum n a) a
- Data.Env.Witness.DefaultString: instance (Data.Env.TypeParser.TypeParser a, GHC.Internal.Data.String.IsString a, GHC.Internal.TypeLits.KnownSymbol s) => Data.Env.TypeParserW.TypeParserW (Data.Env.Witness.DefaultString.DefaultString s a) a
+ Data.Env.DefaultBool: DefaultBool :: Bool -> DefaultBool (def :: Bool)
+ Data.Env.DefaultBool: boolDefault :: BoolDefault b => Proxy b -> Bool
+ Data.Env.DefaultBool: class BoolDefault (b :: Bool)
+ Data.Env.DefaultBool: instance Data.Env.DefaultBool.BoolDefault 'GHC.Types.False
+ Data.Env.DefaultBool: instance Data.Env.DefaultBool.BoolDefault 'GHC.Types.True
+ Data.Env.DefaultBool: instance Data.Env.DefaultBool.BoolDefault def => Data.Env.TypeParser.TypeParser (Data.Env.DefaultBool.DefaultBool def)
+ Data.Env.DefaultBool: instance GHC.Classes.Eq (Data.Env.DefaultBool.DefaultBool def)
+ Data.Env.DefaultBool: instance GHC.Classes.Ord (Data.Env.DefaultBool.DefaultBool def)
+ Data.Env.DefaultBool: instance GHC.Show.Show (Data.Env.DefaultBool.DefaultBool def)
+ Data.Env.DefaultBool: newtype DefaultBool (def :: Bool)
+ Data.Env.EnumParser: instance (GHC.Enum.Enum a, GHC.Show.Show a, GHC.Enum.Bounded a) => Data.Env.TypeParser.TypeParser (Data.Env.EnumParser.EnumParser a)
+ Data.Env.EnumParser: instance GHC.Show.Show a => GHC.Show.Show (Data.Env.EnumParser.EnumParser a)
+ Data.Env.ExtractFields: instance (GHC.Generics.Generic a, Data.Env.ExtractFields.GExtractFields (GHC.Generics.Rep a)) => Data.Env.ExtractFields.ExtractFields a
+ Data.Env.ExtractFields: instance GHC.Generics.Selector s => Data.Env.ExtractFields.GExtractFields (GHC.Generics.M1 GHC.Generics.S s (GHC.Generics.K1 i a))
+ Data.Env.ExtractFields: instance forall k (f :: k -> *) (c :: GHC.Generics.Meta). Data.Env.ExtractFields.GExtractFields f => Data.Env.ExtractFields.GExtractFields (GHC.Generics.M1 GHC.Generics.C c f)
+ Data.Env.ExtractFields: instance forall k (f :: k -> *) (c :: GHC.Generics.Meta). Data.Env.ExtractFields.GExtractFields f => Data.Env.ExtractFields.GExtractFields (GHC.Generics.M1 GHC.Generics.D c f)
+ Data.Env.ExtractFields: instance forall k (f :: k -> *) (g :: k -> *). (Data.Env.ExtractFields.GExtractFields f, Data.Env.ExtractFields.GExtractFields g) => Data.Env.ExtractFields.GExtractFields (f GHC.Generics.:*: g)
+ Data.Env.RecordParser: instance (Data.Env.TypeParser.TypeParser a, GHC.Generics.Selector s) => Data.Env.RecordParser.GRecordParser (GHC.Generics.M1 GHC.Generics.S s (GHC.Generics.K1 i a))
+ Data.Env.RecordParser: instance (GHC.Generics.Generic a, Data.Env.RecordParser.GRecordParser (GHC.Generics.Rep a)) => Data.Env.RecordParser.RecordParser a
+ Data.Env.RecordParser: instance forall k (f :: k -> *) (c :: GHC.Generics.Meta). Data.Env.RecordParser.GRecordParser f => Data.Env.RecordParser.GRecordParser (GHC.Generics.M1 GHC.Generics.C c f)
+ Data.Env.RecordParser: instance forall k (f :: k -> *) (c :: GHC.Generics.Meta). Data.Env.RecordParser.GRecordParser f => Data.Env.RecordParser.GRecordParser (GHC.Generics.M1 GHC.Generics.D c f)
+ Data.Env.RecordParser: instance forall k (f :: k -> *) (g :: k -> *). (Data.Env.RecordParser.GRecordParser f, Data.Env.RecordParser.GRecordParser g) => Data.Env.RecordParser.GRecordParser (f GHC.Generics.:*: g)
+ Data.Env.RecordParserW: instance (Data.Env.TypeParserW.TypeParserW p a, GHC.Generics.Selector s) => Data.Env.RecordParserW.GRecordParserW (GHC.Generics.M1 GHC.Generics.S s (GHC.Generics.K1 i (p, a)))
+ Data.Env.RecordParserW: instance (GHC.Generics.Generic (a 'Data.Env.RecordParserW.Dec), Data.Env.RecordParserW.GRecordParserW (GHC.Generics.Rep (a 'Data.Env.RecordParserW.Dec)), GHC.Generics.Generic (a 'Data.Env.RecordParserW.Res), Data.Env.RecordParserW.GRecordParsedType (GHC.Generics.Rep (a 'Data.Env.RecordParserW.Dec)) () GHC.Types.~ GHC.Generics.Rep (a 'Data.Env.RecordParserW.Res) ()) => Data.Env.RecordParserW.RecordParserW (a 'Data.Env.RecordParserW.Dec)
+ Data.Env.RecordParserW: instance GHC.Show.Show Data.Env.RecordParserW.ColumnType
+ Data.Env.RecordParserW: instance forall k (f :: k -> *) (c :: GHC.Generics.Meta). Data.Env.RecordParserW.GRecordParserW f => Data.Env.RecordParserW.GRecordParserW (GHC.Generics.M1 GHC.Generics.C c f)
+ Data.Env.RecordParserW: instance forall k (f :: k -> *) (c :: GHC.Generics.Meta). Data.Env.RecordParserW.GRecordParserW f => Data.Env.RecordParserW.GRecordParserW (GHC.Generics.M1 GHC.Generics.D c f)
+ Data.Env.RecordParserW: instance forall k (f :: k -> *) (g :: k -> *). (Data.Env.RecordParserW.GRecordParserW f, Data.Env.RecordParserW.GRecordParserW g) => Data.Env.RecordParserW.GRecordParserW (f GHC.Generics.:*: g)
+ Data.Env.TypeParser: instance Data.Env.TypeParser.TypeParser GHC.Base.String
+ Data.Env.TypeParser: instance Data.Env.TypeParser.TypeParser GHC.Int.Int16
+ Data.Env.TypeParser: instance Data.Env.TypeParser.TypeParser GHC.Int.Int32
+ Data.Env.TypeParser: instance Data.Env.TypeParser.TypeParser GHC.Int.Int64
+ Data.Env.TypeParser: instance Data.Env.TypeParser.TypeParser GHC.Int.Int8
+ Data.Env.TypeParser: instance Data.Env.TypeParser.TypeParser GHC.Word.Word16
+ Data.Env.TypeParser: instance Data.Env.TypeParser.TypeParser GHC.Word.Word32
+ Data.Env.TypeParser: instance Data.Env.TypeParser.TypeParser GHC.Word.Word64
+ Data.Env.TypeParser: instance Data.Env.TypeParser.TypeParser GHC.Word.Word8
+ Data.Env.TypeParser: instance Data.Env.TypeParser.TypeParser a => Data.Env.TypeParser.TypeParser (GHC.Maybe.Maybe a)
+ Data.Env.TypeParser: instance Data.Env.TypeParser.TypeParser a => Data.Env.TypeParser.TypeParser (Solo a)
+ Data.Env.TypeParserW: instance (Data.Env.TypeParserW.TypeParserW p1 GHC.Base.String, Data.Env.TypeParserW.TypeParserW p2 GHC.Base.String) => Data.Env.TypeParserW.TypeParserW (p1, p2) GHC.Base.String
+ Data.Env.TypeParserW: instance Data.Env.TypeParser.TypeParser a => Data.Env.TypeParserW.TypeParserW (Solo a) a
+ Data.Env.Witness.DefaultNum: instance (Data.Env.TypeParser.TypeParser a, GHC.Num.Num a, GHC.TypeNats.KnownNat n) => Data.Env.TypeParserW.TypeParserW (Data.Env.Witness.DefaultNum.DefaultNum n a) a
+ Data.Env.Witness.DefaultString: instance (Data.Env.TypeParser.TypeParser a, Data.String.IsString a, GHC.TypeLits.KnownSymbol s) => Data.Env.TypeParserW.TypeParserW (Data.Env.Witness.DefaultString.DefaultString s a) a
- Data.Env: class (ExtractFields a, RecordParserW a) => EnvSchemaW (a :: k)
+ Data.Env: class (ExtractFields a, RecordParserW a) => EnvSchemaW a
- Data.Env.ExtractFields: class ExtractFields (a :: k)
+ Data.Env.ExtractFields: class ExtractFields a
- Data.Env.ExtractFields: extractFields :: forall {k} (a :: k). ExtractFields a => [String]
+ Data.Env.ExtractFields: extractFields :: forall a. ExtractFields a => [String]
- Data.Env.ExtractFields: getEnvRaw :: forall {k} (a :: k) m. (MonadIO m, ExtractFields a) => (String -> String) -> m (Map String String)
+ Data.Env.ExtractFields: getEnvRaw :: forall a m. (MonadIO m, ExtractFields a) => (String -> String) -> m (Map String String)
- Data.Env.ExtractFields: getEnvRawCamelCaseToUpperSnake :: forall {k} (a :: k) m. (MonadIO m, ExtractFields a) => m (Map String String)
+ Data.Env.ExtractFields: getEnvRawCamelCaseToUpperSnake :: forall a m. (MonadIO m, ExtractFields a) => m (Map String String)
- Data.Env.RecordParserW: class RecordParserW (a :: k) where {
+ Data.Env.RecordParserW: class RecordParserW a where {
- Data.Env.RecordParserW: type Di (f :: Type -> Type) (c :: ColumnType) a = Column c f a a
+ Data.Env.RecordParserW: type Di f c a = Column c (f a) a
- Data.Env.RecordParserW: type RecordParsedType (a :: k);
+ Data.Env.RecordParserW: type RecordParsedType a;
- Data.Env.RecordParserW: type family Column (t :: ColumnType) p a
+ Data.Env.RecordParserW: type family Column (t :: ColumnType) (p :: Type) (a :: Type)
- Data.Env.TypeParser: parseType :: TypeParser a => String -> Either String a
+ Data.Env.TypeParser: parseType :: (TypeParser a, Generic a, GTypeParser (Rep a)) => String -> Either String a
- Data.Env.TypeParserW: class TypeParserW (p :: k) a | p -> a
+ Data.Env.TypeParserW: class TypeParserW p a | p -> a
- Data.Env.TypeParserW: data Solo a
+ Data.Env.TypeParserW: data () => Solo a
- Data.Env.Witness.DefaultNum: data DefaultNum (n :: Nat) (a :: k)
+ Data.Env.Witness.DefaultNum: data DefaultNum (n :: Nat) a
- Data.Env.Witness.DefaultString: data DefaultString (s :: Symbol) (a :: k)
+ Data.Env.Witness.DefaultString: data DefaultString (s :: Symbol) a
Files
- CHANGELOG.md +7/−1
- mmzk-env.cabal +4/−2
- src/Data/Env/DefaultBool.hs +43/−0
- test/DefaultBoolSpec.hs +23/−0
CHANGELOG.md view
@@ -1,6 +1,12 @@ # Revision history for mmzk-env +## 0.2.1.1 -- 2026-03-22++* Added `DefaultBool` for `Bool` fields with a type-level default value.+* Added `DataKinds` to default extensions.++ ## 0.2.1.0 -- 2025-11-30 * Add the missing `validateEnvW` and `validateEnvWWith` functions for validating environment variables with witness types.@@ -16,7 +22,7 @@ * Add `RecordParserW` for witnessed record parsing. * Add `TypeParserW` for witnessed type parsing. * Add `DefaultNum` witness type for providing default numeric values.- + * Add convenient `Maybe` result variants for parsers. * Add runnable example executables in `app/`:
mmzk-env.cabal view
@@ -1,6 +1,6 @@ cabal-version: 2.4 name: mmzk-env-version: 0.2.1.0+version: 0.2.1.1 synopsis: Read environment variables into a user-defined data type description:@@ -51,6 +51,7 @@ import: settings exposed-modules: Data.Env+ Data.Env.DefaultBool Data.Env.EnumParser Data.Env.ExtractFields Data.Env.RecordParser@@ -70,13 +71,14 @@ test-suite test import: settings main-is: Spec.hs+ type: exitcode-stdio-1.0 other-modules: BasicTypeParserSpec+ DefaultBoolSpec DefaultWitnessSpec EnumParserSpec RecordParserSpec RecordParserWSpec- type: exitcode-stdio-1.0 build-depends: base >=4.16 && <5, containers,
+ src/Data/Env/DefaultBool.hs view
@@ -0,0 +1,43 @@+-- |+-- Module: Data.Env.DefaultBool+-- Description: A helper type for Bool fields with a type-level default value.+--+-- This module provides 'DefaultBool', a newtype wrapping 'Bool' whose+-- 'TypeParser' instance returns a type-level default when the input is empty.+--+-- Example usage:+--+-- > data Config = Config+-- > { debug :: DefaultBool 'False+-- > , verbose :: DefaultBool 'True+-- > } deriving (Show, Generic, EnvSchema)+-- >+-- > -- DEBUG unset → DefaultBool False+-- > -- DEBUG=True → DefaultBool True+-- > -- DEBUG=False → DefaultBool False+module Data.Env.DefaultBool where++import Data.Env.TypeParser (TypeParser(..))+import Data.Proxy (Proxy(..))++-- | A 'Bool' field with a type-level default.+--+-- When the environment variable is absent (empty string) the field takes the+-- value @def@; otherwise the string is parsed as a regular 'Bool'.+newtype DefaultBool (def :: Bool) = DefaultBool Bool+ deriving (Show, Eq, Ord)++-- | Reflect a type-level 'Bool' to a value-level 'Bool'.+class BoolDefault (b :: Bool) where+ boolDefault :: Proxy b -> Bool++instance BoolDefault 'True where+ boolDefault _ = True++instance BoolDefault 'False where+ boolDefault _ = False++instance BoolDefault def => TypeParser (DefaultBool def) where+ parseType "" = Right (DefaultBool (boolDefault (Proxy :: Proxy def)))+ parseType s = DefaultBool <$> parseType s+ {-# INLINE parseType #-}
+ test/DefaultBoolSpec.hs view
@@ -0,0 +1,23 @@+module DefaultBoolSpec ( spec ) where++import Data.Either ( isLeft )+import Data.Env.DefaultBool+import Data.Env.TypeParser+import Test.Hspec++spec :: Spec+spec = describe "DefaultBool" do+ it "parses True" do+ parseType @(DefaultBool 'False) "True" `shouldBe` Right (DefaultBool True)+ parseType @(DefaultBool 'True) "True" `shouldBe` Right (DefaultBool True)+ it "parses False" do+ parseType @(DefaultBool 'False) "False" `shouldBe` Right (DefaultBool False)+ parseType @(DefaultBool 'True) "False" `shouldBe` Right (DefaultBool False)+ it "defaults to False when empty" do+ parseType @(DefaultBool 'False) "" `shouldBe` Right (DefaultBool False)+ it "defaults to True when empty" do+ parseType @(DefaultBool 'True) "" `shouldBe` Right (DefaultBool True)+ it "fails to parse other values" do+ parseType @(DefaultBool 'False) "1" `shouldSatisfy` isLeft+ parseType @(DefaultBool 'False) "true" `shouldSatisfy` isLeft+ parseType @(DefaultBool 'False) "false" `shouldSatisfy` isLeft