config-schema 1.1.0.0 → 1.2.0.0
raw patch · 7 files changed
+133/−63 lines, 7 filesdep ~basedep ~config-valuePVP ok
version bump matches the API change (PVP)
Dependency ranges changed: base, config-value
API changes (from Hackage documentation)
- Config.Schema.Spec: instance Config.Schema.Spec.HasSpec GHC.Real.Rational
- Config.Schema.Types: [IntegerSpec] :: PrimValueSpec Integer
- Config.Schema.Types: [RationalSpec] :: PrimValueSpec Rational
+ Config.Schema.Spec: instance Config.Schema.Spec.HasSpec GHC.Natural.Natural
+ Config.Schema.Spec: instance Config.Schema.Spec.HasSpec GHC.Types.Double
+ Config.Schema.Spec: instance Config.Schema.Spec.HasSpec GHC.Types.Float
+ Config.Schema.Spec: instance Config.Schema.Spec.HasSpec a => Config.Schema.Spec.HasSpec (GHC.Base.NonEmpty a)
+ Config.Schema.Spec: instance GHC.Real.Integral a => Config.Schema.Spec.HasSpec (GHC.Real.Ratio a)
+ Config.Schema.Spec: integerSpec :: ValueSpec Integer
+ Config.Schema.Spec: naturalSpec :: ValueSpec Natural
+ Config.Schema.Spec: numberSpec :: ValueSpec Number
+ Config.Schema.Spec: rationalSpec :: ValueSpec Rational
+ Config.Schema.Spec: textSpec :: ValueSpec Text
+ Config.Schema.Spec: trueOrFalseSpec :: ValueSpec Bool
+ Config.Schema.Types: [NumberSpec] :: PrimValueSpec Number
Files
- ChangeLog.md +7/−0
- config-schema.cabal +4/−4
- src/Config/Schema/Docs.hs +6/−4
- src/Config/Schema/Load.hs +1/−19
- src/Config/Schema/Load/Error.hs +7/−6
- src/Config/Schema/Spec.hs +105/−25
- src/Config/Schema/Types.hs +3/−5
ChangeLog.md view
@@ -1,5 +1,12 @@ # Revision history for config-schema +## 1.2.0.0++* Update to build against `config-value-0.7.0.0`+* Added additional specs and instances to `Config.Schema.Spec`+* Primitive number spec now only matches `Number`, previous+ `IntegerSpec` is now derived in terms of `NumberSpec`+ ## 1.1.0.0 * Simplify field types of `ValueSpecMismatch`
config-schema.cabal view
@@ -1,6 +1,6 @@ cabal-version: 2.2 name: config-schema-version: 1.1.0.0+version: 1.2.0.0 synopsis: Schema definitions for the config-value package description: This package makes it possible to defined schemas for use when loading configuration files using the config-value format.@@ -17,7 +17,7 @@ extra-source-files: ChangeLog.md README.md homepage: https://github.com/glguy/config-schema bug-reports: https://github.com/glguy/config-schema/issues-tested-with: GHC==7.10.3, GHC==8.0.2, GHC==8.2.2, GHC==8.4.4, GHC==8.6.5+tested-with: GHC==8.0.2, GHC==8.2.2, GHC==8.4.4, GHC==8.6.5, GHC==8.8.1 source-repository head type: git@@ -33,8 +33,8 @@ Config.Schema.Types build-depends:- base >=4.8 && <4.13,- config-value >=0.6 && <0.7,+ base >=4.8 && <4.14,+ config-value ^>=0.7, containers >=0.5 && <0.7, free >=4.12 && <5.2, kan-extensions >=5.0.2 && <5.3,
src/Config/Schema/Docs.hs view
@@ -1,4 +1,4 @@-{-# Language RecursiveDo, OverloadedStrings, GADTs, GeneralizedNewtypeDeriving #-}+{-# Language RecursiveDo, OverloadedStrings, GADTs, GeneralizedNewtypeDeriving, CPP #-} {-| Module : Config.Schema.Docs@@ -42,7 +42,6 @@ import Data.List (intersperse) import Data.List.NonEmpty (NonEmpty((:|))) import Data.Map (Map)-import Data.Monoid (Monoid(..)) import qualified Data.Map as Map import qualified Data.Semigroup as S import Data.Text (Text)@@ -51,6 +50,10 @@ (Doc, fsep, text, (<>), ($+$), (<+>), nest, empty, hsep, parens) import Prelude hiding ((<>)) +#if !MIN_VERSION_base(4,11,0)+import Data.Monoid (Monoid(..))+#endif+ import Config.Schema.Spec import Config.Schema.Types @@ -126,8 +129,7 @@ valueDoc w = case w of TextSpec -> pure "text"- IntegerSpec -> pure "integer"- RationalSpec -> pure "number"+ NumberSpec -> pure "number" AtomSpec a -> pure ("`" <> txt a <> "`") AnyAtomSpec -> pure "atom" SectionsSpec l s -> sectionsDoc l s
src/Config/Schema/Load.hs view
@@ -25,7 +25,6 @@ import Control.Monad.Trans.Class (lift) import Control.Monad.Trans.State (StateT(..), runStateT, state) import Control.Monad.Trans.Except (Except, runExcept, throwE, withExcept)-import Data.Ratio (numerator, denominator) import Data.List.NonEmpty (NonEmpty) import qualified Data.List.NonEmpty as NonEmpty import Data.Text (Text)@@ -98,10 +97,7 @@ -- | Match a primitive value specification against a single value. getValue2 :: Value p -> PrimValueSpec a -> Except (Problem p) a getValue2 (Text _ t) TextSpec = pure t-getValue2 (Number _ _ n) IntegerSpec = pure n-getValue2 (Floating _ a b) IntegerSpec | Just i <- floatingToInteger a b = pure i-getValue2 (Number _ _ n) RationalSpec = pure (fromInteger n)-getValue2 (Floating _ a b) RationalSpec = pure (floatingToRational a b)+getValue2 (Number _ n) NumberSpec = pure n getValue2 (List _ xs) (ListSpec w) = getList w xs getValue2 (Atom _ b) AnyAtomSpec = pure (atomName b) getValue2 (Atom _ b) (AtomSpec a)@@ -146,17 +142,3 @@ | key == k = (Just v, xs) | otherwise = case lookupSection key xs of (res, xs') -> (res, s:xs')------------------------------------------------------------------------------ | Interpret a @config-value@ floating point number as a 'Rational'.-floatingToRational :: Integer -> Integer -> Rational-floatingToRational x y = fromInteger x * 10^^y---- | Interpret a @config-value@ floating point number as an 'Integer'--- if possible.-floatingToInteger :: Integer -> Integer -> Maybe Integer-floatingToInteger x y- | denominator r == 1 = Just (numerator r)- | otherwise = Nothing- where r = floatingToRational x y
src/Config/Schema/Load/Error.hs view
@@ -1,4 +1,4 @@-{-# Language GADTs, OverloadedStrings #-}+{-# Language GADTs, OverloadedStrings, CPP #-} {-| Module : Config.Schema.Load.Error Description : Error types and rendering for Load module@@ -45,11 +45,14 @@ import Text.PrettyPrint (Doc, fsep, ($+$), nest, text, vcat, (<+>), empty, punctuate, comma, int, colon, hcat)-import Data.Monoid ((<>)) import Config import Config.Schema.Types +#if !MIN_VERSION_base(4,11,0)+import Data.Monoid ((<>))+#endif+ -- | Newtype wrapper for schema load errors. data ValueSpecMismatch p = -- | Problem value and list of specification failures@@ -80,8 +83,7 @@ -- | Describe outermost shape of a 'PrimValueSpec' describeSpec :: PrimValueSpec a -> Text describeSpec TextSpec = "text"-describeSpec IntegerSpec = "integer"-describeSpec RationalSpec = "number"+describeSpec NumberSpec = "number" describeSpec AnyAtomSpec = "atom" describeSpec (AtomSpec a) = "atom `" <> a <> "`" describeSpec (ListSpec _) = "list"@@ -93,8 +95,7 @@ -- | Describe outermost shape of a 'Value' describeValue :: Value p -> Text describeValue Text{} = "text"-describeValue Number{} = "integer"-describeValue Floating{} = "number"+describeValue Number{} = "number" describeValue (Atom _ a) = "atom `" <> atomName a <> "`" describeValue Sections{} = "sections" describeValue List{} = "list"
src/Config/Schema/Spec.hs view
@@ -1,4 +1,4 @@-{-# Language FlexibleInstances, OverloadedStrings #-}+{-# Language ScopedTypeVariables, OverloadedStrings #-} {-| Module : Config.Schema.Spec@@ -30,6 +30,11 @@ , listSpec , customSpec , namedSpec+ , numberSpec+ , integerSpec+ , naturalSpec+ , rationalSpec+ , textSpec , HasSpec(..) -- * Specifying sections@@ -43,6 +48,7 @@ -- * Derived specifications , oneOrList , yesOrNoSpec+ , trueOrFalseSpec , stringSpec , numSpec , fractionalSpec@@ -51,7 +57,7 @@ ) where -import Data.Bits (Bits, toIntegralSized)+import Data.Bits (FiniteBits, isSigned, toIntegralSized, finiteBitSize) import Data.Functor.Alt (Alt(..)) import Data.Int import Data.List.NonEmpty (NonEmpty)@@ -59,8 +65,11 @@ import Data.Text (Text) import qualified Data.Text as Text import Data.Word+import Data.Ratio+import GHC.Natural (Natural) import Config.Schema.Types+import Config.Number (Number, numberToInteger, numberToRational) ------------------------------------------------------------------------ -- 'ValueSpec' builders@@ -139,35 +148,72 @@ -- > username: random -- > -- Generates: Config { userName = Random, retries = 5 } --- | Class of value specifications that don't require arguments.+-- | Class of value specifications without parameters. class HasSpec a where anySpec :: ValueSpec a-instance HasSpec Text where anySpec = primValueSpec TextSpec-instance HasSpec Integer where anySpec = primValueSpec IntegerSpec-instance HasSpec Rational where anySpec = primValueSpec RationalSpec-instance HasSpec Int where anySpec = sizedBitsSpec "machine-bit signed"-instance HasSpec Int8 where anySpec = sizedBitsSpec "8-bit signed"-instance HasSpec Int16 where anySpec = sizedBitsSpec "16-bit signed"-instance HasSpec Int32 where anySpec = sizedBitsSpec "32-bit signed"-instance HasSpec Int64 where anySpec = sizedBitsSpec "64-bit signed"-instance HasSpec Word where anySpec = sizedBitsSpec "machine-bit unsigned"-instance HasSpec Word8 where anySpec = sizedBitsSpec "8-bit unsigned"-instance HasSpec Word16 where anySpec = sizedBitsSpec "16-bit unsigned"-instance HasSpec Word32 where anySpec = sizedBitsSpec "32-bit unsigned"-instance HasSpec Word64 where anySpec = sizedBitsSpec "64-bit unsigned"+instance HasSpec Text where anySpec = textSpec+instance HasSpec Integer where anySpec = integerSpec+instance HasSpec Int where anySpec = sizedBitsSpec+instance HasSpec Int8 where anySpec = sizedBitsSpec+instance HasSpec Int16 where anySpec = sizedBitsSpec+instance HasSpec Int32 where anySpec = sizedBitsSpec+instance HasSpec Int64 where anySpec = sizedBitsSpec+instance HasSpec Word where anySpec = sizedBitsSpec+instance HasSpec Word8 where anySpec = sizedBitsSpec+instance HasSpec Word16 where anySpec = sizedBitsSpec+instance HasSpec Word32 where anySpec = sizedBitsSpec+instance HasSpec Word64 where anySpec = sizedBitsSpec +-- | @since 1.2.0.0+instance HasSpec Natural where anySpec = naturalSpec++-- | @since 1.2.0.0+instance HasSpec Double where anySpec = fractionalSpec++-- | @since 1.2.0.0+instance HasSpec Float where anySpec = fractionalSpec++-- | For 'Ratio' and 'Rational'+--+-- @since 1.2.0.0+instance Integral a => HasSpec (Ratio a) where+ anySpec = fractionalSpec++-- | Zero or more elements in a list instance HasSpec a => HasSpec [a] where- anySpec = primValueSpec (ListSpec anySpec)+ anySpec = listSpec anySpec +-- | One or more elements in a list+--+-- @since 1.2.0.0+instance HasSpec a => HasSpec (NonEmpty a) where+ anySpec = nonemptySpec anySpec++-- | Left-biased, untagged union of specs instance (HasSpec a, HasSpec b) => HasSpec (Either a b) where anySpec = Left <$> anySpec <!> Right <$> anySpec -sizedBitsSpec :: (Integral a, Bits a) => Text -> ValueSpec a-sizedBitsSpec name = customSpec name (primValueSpec IntegerSpec) check+{-# INLINE sizedBitsSpec #-}+sizedBitsSpec :: forall a. (Integral a, FiniteBits a) => ValueSpec a+sizedBitsSpec = customSpec label integerSpec check where+ signText = if isSigned (0::a) then "signed" else "unsigned"++ label = Text.pack (show (finiteBitSize (0::a)) ++ "-bit " ++ signText)+ check i = case toIntegralSized i of Nothing -> Left "out of bounds" Just j -> Right j +-- | Specification for matching any non-negative, integral number+--+-- @since 1.2.0.0+naturalSpec :: ValueSpec Natural+naturalSpec = customSpec "non-negative" integerSpec check+ where+ check i+ | i < 0 = Left "negative number"+ | otherwise = Right (fromInteger i)+ -- | Specification for matching a particular atom. atomSpec :: Text -> ValueSpec () atomSpec = primValueSpec . AtomSpec@@ -178,18 +224,47 @@ -- | Specification for matching any text as a 'String' stringSpec :: ValueSpec String-stringSpec = Text.unpack <$> anySpec+stringSpec = Text.unpack <$> textSpec -- | Specification for matching any integral number. numSpec :: Num a => ValueSpec a-numSpec = fromInteger <$> anySpec+numSpec = fromInteger <$> integerSpec +-- | Specification for matching any text literal+--+-- @since 1.2.0.0+textSpec :: ValueSpec Text+textSpec = primValueSpec TextSpec+ -- | Specification for matching any fractional number. -- -- @since 0.2.0.0 fractionalSpec :: Fractional a => ValueSpec a-fractionalSpec = fromRational <$> anySpec+fractionalSpec = fromRational <$> rationalSpec +-- | Specification for matching any fractional number.+--+-- @since 1.2.0.0+numberSpec :: ValueSpec Number+numberSpec = primValueSpec NumberSpec++-- | Specification for matching any integral number.+--+-- @since 1.2.0.0+integerSpec :: ValueSpec Integer+integerSpec = customSpec "integral" numberSpec check+ where+ check n =+ case numberToInteger n of+ Nothing -> Left "fractional number"+ Just i -> Right i++-- | Specification for matching any number as a 'Rational'.+--+-- @since 1.2.0.0+rationalSpec :: ValueSpec Rational+rationalSpec = numberToRational <$> numberSpec+ -- | Specification for matching a list of values each satisfying a -- given element specification. listSpec :: ValueSpec a -> ValueSpec [a]@@ -241,12 +316,17 @@ customSpec lbl w f = primValueSpec (CustomSpec lbl (f <$> w)) --- | Specification for using @yes@ and @no@ to represent booleans 'True'+-- | Specification for using atoms @yes@ and @no@ to represent booleans 'True' -- and 'False' respectively yesOrNoSpec :: ValueSpec Bool-yesOrNoSpec = True <$ atomSpec (Text.pack "yes")- <!> False <$ atomSpec (Text.pack "no")+yesOrNoSpec = True <$ atomSpec "yes" <!> False <$ atomSpec "no" +-- | Specification for using atoms @true@ and @false@ to represent booleans 'True'+-- and 'False' respectively.+--+-- @since 1.2.0.0+trueOrFalseSpec :: ValueSpec Bool+trueOrFalseSpec = True <$ atomSpec "true" <!> False <$ atomSpec "false" -- | Matches a non-empty list. --
src/Config/Schema/Types.hs view
@@ -36,6 +36,7 @@ ) where +import Config.Number (Number) import Control.Applicative (Const(..)) import Control.Applicative.Free (Ap, liftAp, runAp, runAp_) import Data.Functor.Alt (Alt(..))@@ -58,11 +59,8 @@ -- | Matches any string literal TextSpec :: PrimValueSpec Text - -- | Matches integral numbers- IntegerSpec :: PrimValueSpec Integer-- -- | Matches any number- RationalSpec :: PrimValueSpec Rational+ -- | Matches numbers+ NumberSpec :: PrimValueSpec Number -- | Matches any atom AnyAtomSpec :: PrimValueSpec Text