validate-input 0.3.0.0 → 0.4.0.0
raw patch · 3 files changed
+64/−13 lines, 3 filesdep +semigroupsPVP ok
version bump matches the API change (PVP)
Dependencies added: semigroups
API changes (from Hackage documentation)
- Data.Validator: instance (Monad m, Monoid e) => Alternative (ValidationT e m)
- Data.Validator: instance (Monad m, Monoid e) => MonadPlus (ValidationT e m)
- Data.Validator: instance HasLength ByteString
- Data.Validator: instance HasLength Text
- Data.Validator: instance HasLength [a]
- Data.Validator: instance Monad m => Applicative (ValidationT e m)
- Data.Validator: instance Monad m => Functor (ValidationT e m)
- Data.Validator: instance Monad m => Monad (ValidationT e m)
- Data.Validator: instance MonadTrans (ValidationT e)
+ Data.Validator: conformsPredTrans :: Monad m => (a -> Maybe b) -> e -> TransValidationRuleT e m a b
+ Data.Validator: conformsPredTransM :: Monad m => (a -> m (Maybe b)) -> e -> TransValidationRuleT e m a b
+ Data.Validator: instance (GHC.Base.Monad m, GHC.Base.Monoid e) => GHC.Base.Alternative (Data.Validator.ValidationT e m)
+ Data.Validator: instance (GHC.Base.Monad m, GHC.Base.Monoid e) => GHC.Base.MonadPlus (Data.Validator.ValidationT e m)
+ Data.Validator: instance Control.Monad.Trans.Class.MonadTrans (Data.Validator.ValidationT e)
+ Data.Validator: instance Data.Validator.HasLength Data.ByteString.Internal.ByteString
+ Data.Validator: instance Data.Validator.HasLength Data.ByteString.Lazy.Internal.ByteString
+ Data.Validator: instance Data.Validator.HasLength Data.Text.Internal.Lazy.Text
+ Data.Validator: instance Data.Validator.HasLength Data.Text.Internal.Text
+ Data.Validator: instance Data.Validator.HasLength [a]
+ Data.Validator: instance GHC.Base.Monad m => GHC.Base.Applicative (Data.Validator.ValidationT e m)
+ Data.Validator: instance GHC.Base.Monad m => GHC.Base.Functor (Data.Validator.ValidationT e m)
+ Data.Validator: instance GHC.Base.Monad m => GHC.Base.Monad (Data.Validator.ValidationT e m)
+ Data.Validator: nonEmptyList :: Monad m => e -> TransValidationRuleT e m [a] (NonEmpty a)
+ Data.Validator: requiredValue :: Monad m => e -> TransValidationRuleT e m (Maybe a) a
+ Data.Validator: type TransValidationRule e a b = TransValidationRuleT e Identity a b
+ Data.Validator: type TransValidationRuleT e m a b = a -> ValidationT e m b
- Data.Validator: runValidator :: ValidationRule e a -> a -> Either e a
+ Data.Validator: runValidator :: TransValidationRule e a b -> a -> Either e b
- Data.Validator: runValidatorT :: Monad m => ValidationRuleT e m a -> a -> m (Either e a)
+ Data.Validator: runValidatorT :: Monad m => TransValidationRuleT e m a b -> a -> m (Either e b)
- Data.Validator: type ValidationRuleT e m a = a -> ValidationT e m a
+ Data.Validator: type ValidationRuleT e m a = TransValidationRuleT e m a a
Files
- README.md +15/−4
- src/Data/Validator.hs +47/−8
- validate-input.cabal +2/−1
README.md view
@@ -24,8 +24,16 @@ = Example { ex_username :: T.Text , ex_dogs :: Int+ , ex_friendName :: Maybe T.Text } deriving (Show) +data ExampleChecked+ = ExampleChecked+ { exc_username :: T.Text+ , exc_dogs :: Int+ , exc_friendName :: T.Text+ } deriving (Show)+ main :: IO () main = do putStrLn "Check results:"@@ -40,17 +48,20 @@ checkNumber = smallerThan 5 "No more than 5 dogs allowed" -checkExample :: Monad m => ValidationRuleT String m Example+checkExample :: Monad m => TransValidationRuleT String m Example ExampleChecked checkExample e =- Example <$> checkUsername (ex_username e)- <*> checkNumber (ex_dogs e)+ ExampleChecked+ <$> checkUsername (ex_username e)+ <*> checkNumber (ex_dogs e)+ <*> requiredValue "You must provide a friend name!" (ex_friendName e) -example :: Either String Example+example :: Either String ExampleChecked example = runValidator checkExample $ Example { ex_username = "alex" , ex_dogs = 23+ , ex_friendName = Nothing } ```
src/Data/Validator.hs view
@@ -4,7 +4,9 @@ {-# LANGUAGE OverloadedStrings #-} module Data.Validator ( -- * Core monad and runners- ValidationM, ValidationT, ValidationRule, ValidationRuleT+ ValidationM, ValidationT+ , ValidationRule, ValidationRuleT+ , TransValidationRule, TransValidationRuleT , runValidator, runValidatorT -- * Combinators , (>=>), (<=<)@@ -13,6 +15,9 @@ , largerThan, smallerThan, valueBetween , matchesRegex , conformsPred, conformsPredM+ -- * Transforming checks+ , requiredValue, nonEmptyList+ , conformsPredTrans, conformsPredTransM -- * Helper classes and types , HasLength(..), ConvertibleStrings(..) , Int64@@ -29,6 +34,7 @@ import Data.Int import Data.String.Conversions import Text.Regex.PCRE.Heavy+import qualified Data.List.NonEmpty as NEL import qualified Data.Text as T import qualified Data.Text.Lazy as TL import qualified Data.ByteString as BS@@ -43,12 +49,12 @@ deriving (Monad, Functor, Applicative, Alternative, MonadPlus, MonadTrans) -- | Run a validation on a type 'a'-runValidator :: ValidationRule e a -> a -> Either e a+runValidator :: TransValidationRule e a b -> a -> Either e b runValidator a b = runIdentity $ runValidatorT a b {-# INLINE runValidator #-} -- | Run a validation on a type 'a'-runValidatorT :: Monad m => ValidationRuleT e m a -> a -> m (Either e a)+runValidatorT :: Monad m => TransValidationRuleT e m a b -> a -> m (Either e b) runValidatorT validationSteps input = runEitherT $ unValidationT (validationSteps input) {-# INLINE runValidatorT #-}@@ -57,8 +63,14 @@ type ValidationRule e a = ValidationRuleT e Identity a -- | A validation rule. Combine using @('>=>')@ or @('<=<')@-type ValidationRuleT e m a = a -> ValidationT e m a+type ValidationRuleT e m a = TransValidationRuleT e m a a +-- | A transforming validation rule. Combine using @('>=>')@ or @('<=<')@+type TransValidationRule e a b = TransValidationRuleT e Identity a b++-- | A transforming validation rule. Combine using @('>=>')@ or @('<=<')@+type TransValidationRuleT e m a b = a -> ValidationT e m b+ -- | All types that have a length, eg. 'String', '[a]', 'Vector a', etc. class HasLength a where getLength :: a -> Int64@@ -124,6 +136,11 @@ valueBetween lowerBound upperBound e = largerThan lowerBound e >=> smallerThan upperBound e {-# INLINE valueBetween #-} +-- | Checks that a value matches a regular expression+matchesRegex :: (ConvertibleStrings SBS a, ConvertibleStrings a SBS, Monad m) => Regex -> e -> ValidationRuleT e m a+matchesRegex r = conformsPred (=~ r)+{-# INLINE matchesRegex #-}+ -- | Check that a value conforms a predicate conformsPred :: Monad m => (a -> Bool) -> e -> ValidationRuleT e m a conformsPred predicate e obj = unless (predicate obj) (checkFailed e) >> return obj@@ -136,7 +153,29 @@ unless res (checkFailed e) >> return obj {-# INLINE conformsPredM #-} --- | Checks that a value matches a regular expression-matchesRegex :: (ConvertibleStrings SBS a, ConvertibleStrings a SBS, Monad m) => Regex -> e -> ValidationRuleT e m a-matchesRegex r = conformsPred (=~ r)-{-# INLINE matchesRegex #-}+-- | Check that an optional value is actually set to 'Just a'+requiredValue :: Monad m => e -> TransValidationRuleT e m (Maybe a) a+requiredValue = conformsPredTrans id+{-# INLINE requiredValue #-}++-- | Check that a list is not empty+nonEmptyList :: Monad m => e -> TransValidationRuleT e m [a] (NEL.NonEmpty a)+nonEmptyList = conformsPredTrans NEL.nonEmpty+{-# INLINE nonEmptyList #-}++-- | Do some check returning 'Nothing' if the value is invalid and 'Just a' otherwise.+conformsPredTrans :: Monad m => (a -> Maybe b) -> e -> TransValidationRuleT e m a b+conformsPredTrans f e obj =+ case f obj of+ Nothing -> checkFailed e+ Just val -> return val+{-# INLINE conformsPredTrans #-}++-- | Do some check returning 'Nothing' if the value is invalid and 'Just a' otherwise.+conformsPredTransM :: Monad m => (a -> m (Maybe b)) -> e -> TransValidationRuleT e m a b+conformsPredTransM f e obj =+ do res <- lift $ f obj+ case res of+ Nothing -> checkFailed e+ Just val -> return val+{-# INLINE conformsPredTransM #-}
validate-input.cabal view
@@ -1,5 +1,5 @@ name: validate-input-version: 0.3.0.0+version: 0.4.0.0 synopsis: Input validation combinator library description: A small Haskell combinator library that provides a simple way of validating user provided data structures.@@ -32,6 +32,7 @@ mtl >=2.1, pcre-heavy >=1.0, string-conversions >=0.4,+ semigroups >=0.16, text >=1.2 hs-source-dirs: src default-language: Haskell2010