packages feed

validate-input 0.1.0.0 → 0.2.0.0

raw patch · 3 files changed

+108/−47 lines, 3 filesdep +QuickCheckdep +hspecdep +validate-inputPVP ok

version bump matches the API change (PVP)

Dependencies added: QuickCheck, hspec, validate-input

API changes (from Hackage documentation)

- Data.Validator: (+>>) :: Monad m => (a -> ValidationT e m a) -> (a -> ValidationT e m a) -> a -> ValidationT e m a
- Data.Validator: ValidationT :: EitherT e m a -> ValidationT e m a
- Data.Validator: newtype ValidationT e m a
- Data.Validator: unValidationT :: ValidationT e m a -> EitherT e m a
+ Data.Validator: (<=<) :: Monad m => (b -> m c) -> (a -> m b) -> a -> m c
+ Data.Validator: (>=>) :: Monad m => (a -> m b) -> (b -> m c) -> a -> m c
+ Data.Validator: data ValidationT e m a
+ Data.Validator: type ValidationRule e a = ValidationRuleT e Identity a
+ Data.Validator: type ValidationRuleT e m a = a -> ValidationT e m a
- Data.Validator: conformsPred :: Monad m => (a -> Bool) -> e -> a -> ValidationT e m a
+ Data.Validator: conformsPred :: Monad m => (a -> Bool) -> e -> ValidationRuleT e m a
- Data.Validator: conformsPredM :: Monad m => (a -> m Bool) -> e -> a -> ValidationT e m a
+ Data.Validator: conformsPredM :: Monad m => (a -> m Bool) -> e -> ValidationRuleT e m a
- Data.Validator: largerThan :: (Monad m, Ord a) => a -> e -> a -> ValidationT e m a
+ Data.Validator: largerThan :: (Monad m, Ord a) => a -> e -> ValidationRuleT e m a
- Data.Validator: lengthBetween :: (Monad m, HasLength a) => Int64 -> Int64 -> e -> a -> ValidationT e m a
+ Data.Validator: lengthBetween :: (Monad m, HasLength a) => Int64 -> Int64 -> e -> ValidationRuleT e m a
- Data.Validator: matchesRegex :: (Stringable a, Monad m) => Regex -> e -> a -> ValidationT e m a
+ Data.Validator: matchesRegex :: (Stringable a, Monad m) => Regex -> e -> ValidationRuleT e m a
- Data.Validator: maxLength :: (Monad m, HasLength a) => Int64 -> e -> a -> ValidationT e m a
+ Data.Validator: maxLength :: (Monad m, HasLength a) => Int64 -> e -> ValidationRuleT e m a
- Data.Validator: minLength :: (Monad m, HasLength a) => Int64 -> e -> a -> ValidationT e m a
+ Data.Validator: minLength :: (Monad m, HasLength a) => Int64 -> e -> ValidationRuleT e m a
- Data.Validator: notEmpty :: (Monad m, HasLength a) => e -> a -> ValidationT e m a
+ Data.Validator: notEmpty :: (Monad m, HasLength a) => e -> ValidationRuleT e m a
- Data.Validator: runValidator :: (a -> ValidationM e a) -> a -> Either e a
+ Data.Validator: runValidator :: ValidationRule e a -> a -> Either e a
- Data.Validator: runValidatorT :: Monad m => (a -> ValidationT e m a) -> a -> m (Either e a)
+ Data.Validator: runValidatorT :: Monad m => ValidationRuleT e m a -> a -> m (Either e a)
- Data.Validator: smallerThan :: (Monad m, Ord a) => a -> e -> a -> ValidationT e m a
+ Data.Validator: smallerThan :: (Monad m, Ord a) => a -> e -> ValidationRuleT e m a
- Data.Validator: valueBetween :: (Monad m, Ord a) => a -> a -> e -> a -> ValidationT e m a
+ Data.Validator: valueBetween :: (Monad m, Ord a) => a -> a -> e -> ValidationRuleT e m a

Files

src/Data/Validator.hs view
@@ -1,22 +1,21 @@ {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-} {-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE QuasiQuotes #-} module Data.Validator-    ( -- * core monad and runners-      ValidationM, ValidationT(..)+    ( -- * Core monad and runners+      ValidationM, ValidationT, ValidationRule, ValidationRuleT     , runValidator, runValidatorT-      -- * combinators-    , (+>>)-      -- * checks+      -- * Combinators+    , (>=>), (<=<)+      -- * Checks     , minLength, maxLength, lengthBetween, notEmpty     , largerThan, smallerThan, valueBetween     , matchesRegex     , conformsPred, conformsPredM-      -- * helper classes and types+      -- * Helper classes and types     , HasLength(..), Stringable(..)     , Int64-      -- * reexports+      -- * Regular expression helpers     , re, mkRegexQQ, Regex     ) where@@ -43,90 +42,100 @@       deriving (Monad, Functor, Applicative, Alternative, MonadPlus, MonadTrans)  -- | Run a validation on a type 'a'-runValidator :: (a -> ValidationM e a) -> a -> Either e a+runValidator :: ValidationRule e a -> a -> Either e a runValidator a b = runIdentity $ runValidatorT a b+{-# INLINE runValidator #-}  -- | Run a validation on a type 'a'-runValidatorT :: Monad m => (a -> ValidationT e m a) -> a -> m (Either e a)+runValidatorT :: Monad m => ValidationRuleT e m a -> a -> m (Either e a) runValidatorT validationSteps input =     runEitherT $ unValidationT (validationSteps input)+{-# INLINE runValidatorT #-} +-- | A validation rule. Combine using @('>=>')@ or @('<=<')@+type ValidationRule e a = ValidationRuleT e Identity a++-- | A validation rule. Combine using @('>=>')@ or @('<=<')@+type ValidationRuleT e m a = a -> ValidationT e m a+ -- | All types that have a length, eg. 'String', '[a]', 'Vector a', etc. class HasLength a where     getLength :: a -> Int64  instance HasLength [a] where     getLength = fromIntegral . length+    {-# INLINE getLength #-}  instance HasLength T.Text where     getLength = fromIntegral . T.length+    {-# INLINE getLength #-}  instance HasLength TL.Text where     getLength = TL.length+    {-# INLINE getLength #-}  instance HasLength BS.ByteString where     getLength = fromIntegral . BS.length+    {-# INLINE getLength #-}  instance HasLength BSL.ByteString where     getLength = BSL.length+    {-# INLINE getLength #-}  -- | Mark a custom check as failed checkFailed :: Monad m => e -> ValidationT e m a checkFailed = ValidationT . left {-# INLINE checkFailed #-} --- | Combine two checks-(+>>) :: Monad m => (a -> ValidationT e m a) -> (a -> ValidationT e m a) -> a -> ValidationT e m a-(+>>) m1 m2 a =-    m1 a >>= m2-{-# INLINE (+>>) #-}- -- | Check that the value is at least N elements long-minLength :: (Monad m, HasLength a) => Int64 -> e -> a -> ValidationT e m a-minLength lowerBound e obj =-    largerThan lowerBound e (getLength obj) >> return obj+minLength :: (Monad m, HasLength a) => Int64 -> e -> ValidationRuleT e m a+minLength lowerBound e obj = largerThan lowerBound e (getLength obj) >> return obj+{-# INLINE minLength #-}  -- | Check that the value is at maxium N elements long-maxLength :: (Monad m, HasLength a) => Int64 -> e -> a -> ValidationT e m a+maxLength :: (Monad m, HasLength a) => Int64 -> e -> ValidationRuleT e m a maxLength upperBound e obj =     smallerThan upperBound e (getLength obj) >> return obj+{-# INLINE maxLength #-}  -- | Check that the value's length is between N and M-lengthBetween :: (Monad m, HasLength a) => Int64 -> Int64 -> e -> a -> ValidationT e m a-lengthBetween lowerBound upperBound e obj =-    valueBetween lowerBound upperBound e (getLength obj) >> return obj+lengthBetween :: (Monad m, HasLength a) => Int64 -> Int64 -> e -> ValidationRuleT e m a+lengthBetween lowerBound upperBound e obj = valueBetween lowerBound upperBound e (getLength obj) >> return obj+{-# INLINE lengthBetween #-}  -- | Specialized minLength with N = 1-notEmpty :: (Monad m, HasLength a) => e -> a -> ValidationT e m a+notEmpty :: (Monad m, HasLength a) => e -> ValidationRuleT e m a notEmpty = minLength 1 {-# INLINE notEmpty #-}  -- | Check that a value is larger than N-largerThan :: (Monad m, Ord a) => a -> e -> a -> ValidationT e m a+largerThan :: (Monad m, Ord a) => a -> e -> ValidationRuleT e m a largerThan lowerBound = conformsPred (>= lowerBound)+{-# INLINE largerThan #-}  -- | Check that a value is smaller than N-smallerThan :: (Monad m, Ord a) => a -> e -> a -> ValidationT e m a+smallerThan :: (Monad m, Ord a) => a -> e -> ValidationRuleT e m a smallerThan upperBound = conformsPred (<= upperBound)+{-# INLINE smallerThan #-}  -- | Check that a value is between M and N-valueBetween :: (Monad m, Ord a) => a -> a -> e -> a -> ValidationT e m a-valueBetween lowerBound upperBound e obj =-    (largerThan lowerBound e +>> smallerThan upperBound e) obj+valueBetween :: (Monad m, Ord a) => a -> a -> e -> ValidationRuleT e m a+valueBetween lowerBound upperBound e = largerThan lowerBound e >=> smallerThan upperBound e+{-# INLINE valueBetween #-}  -- | Check that a value conforms a predicate-conformsPred :: Monad m => (a -> Bool) -> e -> a -> ValidationT e m a-conformsPred predicate e obj =-    do unless (predicate obj) $ checkFailed e-       return obj+conformsPred :: Monad m => (a -> Bool) -> e -> ValidationRuleT e m a+conformsPred predicate e obj = unless (predicate obj) (checkFailed e) >> return obj+{-# INLINE conformsPred #-}  -- | Check that a value conforms a predicate-conformsPredM :: Monad m => (a -> m Bool) -> e -> a -> ValidationT e m a+conformsPredM :: Monad m => (a -> m Bool) -> e -> ValidationRuleT e m a conformsPredM predicate e obj =     do res <- lift $ predicate obj-       unless res $ checkFailed e-       return obj+       unless res (checkFailed e) >> return obj+{-# INLINE conformsPredM #-}  -- | Checks that a value matches a regular expression-matchesRegex :: (Stringable a, Monad m) => Regex -> e -> a -> ValidationT e m a-matchesRegex r = conformsPred (\obj -> obj =~ r)+matchesRegex :: (Stringable a, Monad m) => Regex -> e -> ValidationRuleT e m a+matchesRegex r = conformsPred (=~ r)+{-# INLINE matchesRegex #-}
+ test/Spec.hs view
@@ -0,0 +1,39 @@+{-# LANGUAGE ScopedTypeVariables #-}+module Main where++import Data.Validator++import Test.Hspec+import Test.QuickCheck++errMsg :: String+errMsg = "oops"++main :: IO ()+main =+    hspec $+    do describe "conformsPred" $+        do it "should result in error when value does not conform pred" $+            property $ \(i :: Int) ->+                i <= 5 ==> runValidator (conformsPred (>5) errMsg) i == Left errMsg+           it "should result in error when value does conform pred" $+            property $ \(i :: Int) ->+                i > 5 ==> runValidator (conformsPred (>5) errMsg) i == Right i+       describe "minLength" $+        do it "should result in error when string is to small" $+            property $ \(str :: String) (i :: Int64) ->+                fromIntegral (length str) < i ==>+                runValidator (minLength i errMsg) str == Left errMsg+           it "should allow strings with correct size to pass" $+            property $ \(str :: String) (i :: Int64) ->+                            fromIntegral (length str) >= i ==>+                            runValidator (minLength i errMsg) str == Right str+       describe "maxLength" $+        do it "should result in error when string is to large" $+            property $ \(str :: String) (i :: Int64) ->+                fromIntegral (length str) > i ==>+                runValidator (maxLength i errMsg) str == Left errMsg+           it "should allow strings with correct size to pass" $+            property $ \(str :: String) (i :: Int64) ->+                fromIntegral (length str) <= i ==>+                runValidator (maxLength i errMsg) str == Right str
validate-input.cabal view
@@ -1,7 +1,8 @@ name:                validate-input-version:             0.1.0.0+version:             0.2.0.0 synopsis:            Input validation combinator library-description:         A small Haskell combinator library that provides a simple way of validating user provided data structures.+description:         A small Haskell combinator library that provides a simple way of+                     validating user provided data structures. homepage:            https://github.com/agrafix/validate-input bug-reports:         https://github.com/agrafix/validate-input/issues license:             MIT@@ -22,13 +23,25 @@ library   exposed-modules:     Data.Validator   build-depends:-                      base >=4.6 && <5,-                      bytestring >=0.10,-                      either >=4.3,-                      mtl >=2.1,-                      pcre-heavy >=0.2,-                      stringable >=0.1,-                      text >=1.2+                       base >=4.6 && <5,+                       bytestring >=0.10,+                       either >=4.3,+                       mtl >=2.1,+                       pcre-heavy >=0.2,+                       stringable >=0.1,+                       text >=1.2   hs-source-dirs:      src   default-language:    Haskell2010   ghc-options:         -auto-all -Wall -fno-warn-orphans++test-suite validate-input-tests+  type:                exitcode-stdio-1.0+  hs-source-dirs:      test+  main-is:             Spec.hs+  build-depends:+                       base >=4.6 && <5,+                       hspec >=2.1,+                       QuickCheck >=2.7,+                       validate-input+  ghc-options:         -auto-all -Wall -fno-warn-orphans+  default-language:    Haskell2010