packages feed

wai-predicates 0.5 → 0.6

raw patch · 9 files changed

+158/−82 lines, 9 filesdep ~bytestring-fromPVP ok

version bump matches the API change (PVP)

Dependency ranges changed: bytestring-from

API changes (from Hackage documentation)

- Data.Predicate: def :: t -> Predicate a f t -> Predicate a f t
- Data.Predicate: mapFail :: (f -> Result f' t) -> Predicate a f t -> Predicate a f' t
- Data.Predicate: mapOkay :: (t -> Result f t') -> Predicate a f t -> Predicate a f t'
- Data.Predicate: opt :: Predicate a f t -> Predicate a f (Maybe t)
- Network.Wai.Predicate.Error: Error :: !Status -> Maybe ByteString -> Error
+ Network.Wai.Predicate: def :: a -> Predicate r Error a -> Predicate r Error a
+ Network.Wai.Predicate: opt :: Predicate r Error a -> Predicate r Error (Maybe a)
+ Network.Wai.Predicate.Error: NotAvailable :: Reason
+ Network.Wai.Predicate.Error: TypeError :: Reason
+ Network.Wai.Predicate.Error: addLabel :: ByteString -> Error -> Error
+ Network.Wai.Predicate.Error: data Reason
+ Network.Wai.Predicate.Error: e400 :: Error
+ Network.Wai.Predicate.Error: e405 :: Error
+ Network.Wai.Predicate.Error: e406 :: Error
+ Network.Wai.Predicate.Error: e415 :: Error
+ Network.Wai.Predicate.Error: e500 :: Error
+ Network.Wai.Predicate.Error: instance Eq Reason
+ Network.Wai.Predicate.Error: instance Show Reason
+ Network.Wai.Predicate.Error: isReasonOf :: Reason -> Error -> Bool
+ Network.Wai.Predicate.Error: labels :: Error -> [ByteString]
+ Network.Wai.Predicate.Error: reason :: Error -> Maybe Reason
+ Network.Wai.Predicate.Error: setMessage :: ByteString -> Error -> Error
+ Network.Wai.Predicate.Error: setReason :: Reason -> Error -> Error
+ Network.Wai.Predicate.Error: setSource :: ByteString -> Error -> Error
+ Network.Wai.Predicate.Error: setStatus :: Status -> Error -> Error
+ Network.Wai.Predicate.Error: source :: Error -> Maybe ByteString
+ Network.Wai.Predicate.Utility: (&) :: a -> (a -> b) -> b
- Network.Wai.Predicate.Error: err :: Status -> ByteString -> Error
+ Network.Wai.Predicate.Error: err :: Status -> Error
- Network.Wai.Predicate.Error: status :: Error -> !Status
+ Network.Wai.Predicate.Error: status :: Error -> Status

Files

CHANGELOG.md view
@@ -1,3 +1,10 @@+0.6+-----------------------------------------------------------------------------+- Move `def` and `opt` from `Data.Predicate` to `Network.Wai.Predicate` and+  make both specific to `Predicate r Error t`.+- Remove `mapOkay` and `mapFail`.+- Update `bytestring-from` dependency.+ 0.5 ----------------------------------------------------------------------------- - Update dependencies constraints.
src/Data/Predicate.hs view
@@ -17,10 +17,6 @@     , (.&.)     , (.|.)     , (|||)-    , opt-    , def-    , mapOkay-    , mapFail     , exec     -- * Result     , module Data.Predicate.Result@@ -108,31 +104,6 @@ -- | Alias of 'orElse'. (|||) :: Predicate a f t -> Predicate a f t' -> Predicate a f (Either t t') (|||) = orElse---- | Like 'fmap', but only maps the @Okay@ metadata to another result.-mapOkay :: (t -> Result f t') -> Predicate a f t -> Predicate a f t'-mapOkay f p a =-    case p a of-        Okay _ x -> f x-        Fail   x -> Fail x---- | Like 'mapOkay', but for the @Fail@ case.-mapFail :: (f -> Result f' t) -> Predicate a f t -> Predicate a f' t-mapFail f p a =-    case p a of-        Fail   x -> f x-        Okay d x -> Okay d x---- | A predicate modifier which makes the given predicate optional,--- i.e. the @Okay@ metadata type becomes a 'Maybe' and in the failure-case--- 'Nothing' is returned.-opt :: Predicate a f t -> Predicate a f (Maybe t)-opt = fmap (result (const $ return Nothing) (\d x -> Okay d (Just x)))---- | A predicate modifier which returns as @Okay@ metadata the provided default--- value if the given predicate fails.-def :: t -> Predicate a f t -> Predicate a f t-def t = fmap (result (const $ return t) Okay)  exec :: Predicate a f t -> a -> (f -> b) -> (t -> b) -> b exec p a g f = case p a of
src/Network/Wai/Predicate.hs view
@@ -8,6 +8,9 @@     ( module Data.Predicate     , request +    , def+    , opt+     , query     , hasQuery @@ -29,12 +32,12 @@     , module Network.Wai.Predicate.Error     ) where +import Control.Monad (when) import Data.ByteString (ByteString) import Data.ByteString.From import Data.CaseInsensitive (original) import Data.List (find)-import Data.Monoid-import Data.Maybe (isJust)+import Data.Maybe (isNothing) import Data.Predicate import Data.Vault.Lazy (Key) import Data.Word@@ -49,55 +52,90 @@  import qualified Data.Vault.Lazy as Vault -request :: (HasRequest r) => Predicate r f Request+def :: a -> Predicate r Error a -> Predicate r Error a+def a = fmap $+    result (\e -> if not (TypeError `isReasonOf` e) then return a else Fail e)+           Okay++opt :: Predicate r Error a -> Predicate r Error (Maybe a)+opt = fmap $+    result (\e -> if not (TypeError `isReasonOf` e) then return Nothing else Fail e)+           (\d -> Okay d . Just)++request :: HasRequest r => Predicate r f Request request = return . getRequest  query :: (HasQuery r, FromByteString a) => ByteString -> Predicate r Error a-query k r = case lookupQuery k r of-    [] -> Fail (err status400 ("Missing query '" <> k <> "'."))-    qq -> either (Fail . err status400) return (readValues qq)+query k r =+    case lookupQuery k r of+        [] -> Fail . addLabel "query" $ notAvailable k+        qq -> either (Fail . addLabel "query" . typeError k)+                     return+                     (readValues qq) -hasQuery :: (HasQuery r) => ByteString -> Predicate r Error ()+hasQuery :: HasQuery r => ByteString -> Predicate r Error () hasQuery k r =-    if null (lookupQuery k r)-        then Fail (err status400 ("Missing query '" <> k <> "'."))-        else return ()+    when (null (lookupQuery k r)) $+        (Fail . addLabel "query" $ notAvailable k)  header :: (HasHeaders r, FromByteString a) => HeaderName -> Predicate r Error a-header k r = case lookupHeader k r of-    [] -> Fail (err status400 ("Missing header '" <> original k <> "'."))-    hh -> either (Fail . err status400) return (readValues hh)+header k r =+    case lookupHeader k r of+        [] -> Fail . addLabel "header" $ notAvailable (original k)+        hh -> either (Fail . addLabel "header" . typeError (original k))+                     return+                     (readValues hh) -hasHeader :: (HasHeaders r) => HeaderName -> Predicate r Error ()+hasHeader :: HasHeaders r => HeaderName -> Predicate r Error () hasHeader k r =-    if isJust $ find ((k ==) . fst) (headers r)-        then return ()-        else Fail (err status400 ("Missing header '" <> original k <> "'."))+    when (isNothing (find ((k ==) . fst) (headers r))) $+        (Fail . addLabel "header" $ notAvailable (original k))  segment :: (HasPath r, FromByteString a) => Word -> Predicate r Error a-segment i r = case lookupSegment i r of-    Nothing -> Fail (err status400 "Path segment index out of bounds.")-    Just  s -> either (Fail . err status400) return (readValues [s])+segment i r =+    case lookupSegment i r of+        Nothing -> Fail $+            e400 & setMessage "Path segment index out of bounds."+                 . addLabel "path"+        Just  s -> either (\m -> Fail (e400 & addLabel "path" . setReason TypeError . setMessage m))+                          return+                          (readValues [s]) -hasSegment :: (HasPath r) => Word -> Predicate r Error ()+hasSegment :: HasPath r => Word -> Predicate r Error () hasSegment i r =-    if isJust $ lookupSegment i r-        then return ()-        else Fail (err status400 "Path segment index out of bounds.")+    when (isNothing (lookupSegment i r)) $+        Fail (e400 & addLabel "path" . setMessage "Path segment index out of bounds.")  cookie :: (HasCookies r, FromByteString a) => ByteString -> Predicate r Error a-cookie k r = case lookupCookie k r of-    [] -> Fail (err status400 ("Missing cookie '" <> k <> "'."))-    cc -> either (Fail . err status400) return (readValues cc)+cookie k r =+    case lookupCookie k r of+        [] -> Fail . addLabel "cookie" $ notAvailable k+        cc -> either (Fail . addLabel "cookie" . typeError k)+                     return+                     (readValues cc) -hasCookie :: (HasCookies r) => ByteString -> Predicate r Error ()+hasCookie :: HasCookies r => ByteString -> Predicate r Error () hasCookie k r =-    if null (lookupCookie k r)-        then Fail (err status400 ("Missing cookie '" <> k <> "'."))-        else return ()+    when (null (lookupCookie k r)) $+        (Fail . addLabel "cookie" $ notAvailable k)  fromVault :: HasVault r => Key a -> Predicate r Error a-fromVault k r = case Vault.lookup k (requestVault r) of-    Nothing -> Fail (err status500 "Vault does not contain key.")-    Just  a -> return a+fromVault k r =+    case Vault.lookup k (requestVault r) of+        Just  a -> return a+        Nothing -> Fail $+            e500 & setReason NotAvailable+                 . setMessage "Vault does not contain key."+                 . addLabel "vault"++-----------------------------------------------------------------------------+-- Internal++notAvailable :: ByteString -> Error+notAvailable k = e400 & setReason NotAvailable . setSource k+{-# INLINE notAvailable #-}++typeError :: ByteString -> ByteString -> Error+typeError k m = e400 & setReason TypeError . setSource k . setMessage m+{-# INLINE typeError #-} 
src/Network/Wai/Predicate/Accept.hs view
@@ -17,14 +17,14 @@ import Data.Maybe import Data.Predicate import Data.Singletons.TypeLits (Symbol)-import Network.HTTP.Types import Network.Wai.Predicate.Error import Network.Wai.Predicate.Request import Network.Wai.Predicate.MediaType+import Network.Wai.Predicate.Utility  import qualified Network.Wai.Predicate.Parser.MediaType as M -accept :: (HasHeaders r)+accept :: HasHeaders r        => ByteString        -> ByteString        -> Predicate r Error (Media (t :: Symbol) (s :: Symbol))@@ -34,7 +34,7 @@         then return (Media t s 1.0 [])         else case findMediaType t s mtypes of             m:_ -> Okay (1.0 - mediaQuality m) m-            []  -> Fail (err status406 msg)+            []  -> Fail (e406 & setMessage msg)       where         msg = "Expected 'Accept: " <> t <> "/" <> s <> "'." 
src/Network/Wai/Predicate/Content.hs view
@@ -17,14 +17,14 @@ import Data.Predicate import Data.Singletons.TypeLits (Symbol) import Data.Maybe-import Network.HTTP.Types.Status import Network.Wai.Predicate.Error import Network.Wai.Predicate.MediaType import Network.Wai.Predicate.Request+import Network.Wai.Predicate.Utility  import qualified Network.Wai.Predicate.Parser.MediaType as M -contentType :: (HasHeaders r)+contentType :: HasHeaders r             => ByteString             -> ByteString             -> Predicate r Error (Media (t :: Symbol) (s :: Symbol))@@ -32,7 +32,7 @@     let mtypes = M.readMediaTypes "content-type" r in     case findContentType t s mtypes of         m:_ -> Okay (1.0 - mediaQuality m) m-        []  -> Fail (err status415 msg)+        []  -> Fail (e415 & setMessage msg)   where     msg = "Expected 'Content-Type: " <> t <> "/" <> s <> "'." 
src/Network/Wai/Predicate/Error.hs view
@@ -2,18 +2,70 @@ -- License, v. 2.0. If a copy of the MPL was not distributed with this -- file, You can obtain one at http://mozilla.org/MPL/2.0/. -module Network.Wai.Predicate.Error where+module Network.Wai.Predicate.Error+    ( Error+    , Reason (..)+    , err+    , e400+    , e405+    , e406+    , e415+    , e500+    , status+    , message+    , reason+    , source+    , labels+    , setStatus+    , setMessage+    , setReason+    , setSource+    , addLabel+    , isReasonOf+    ) where  import Data.ByteString (ByteString) import Network.HTTP.Types.Status +data Reason+    = NotAvailable+    | TypeError+    deriving (Eq, Show)+ -- | The error type used as meta-data for @Fail@ in all WAI predicates. data Error = Error     { status  :: !Status          -- ^ HTTP status code     , message :: Maybe ByteString -- ^ optional status message+    , reason  :: Maybe Reason     -- ^ optional reason for this error+    , source  :: Maybe ByteString -- ^ optional source of this erro+    , labels  :: [ByteString]     -- ^ optional free-text labels     } deriving (Eq, Show) --- | Convenience function to construct 'Error' values from--- status code and body message.-err :: Status -> ByteString -> Error-err s = Error s . Just+err :: Status -> Error+err s = Error s Nothing Nothing Nothing []++setStatus :: Status -> Error -> Error+setStatus s e = e { status = s }++setMessage :: ByteString -> Error -> Error+setMessage m e = e { message = Just m }++setReason :: Reason -> Error -> Error+setReason r e = e { reason = Just r }++setSource :: ByteString -> Error -> Error+setSource s e = e { source = Just s }++addLabel :: ByteString -> Error -> Error+addLabel l e = e { labels = l : labels e }++isReasonOf :: Reason -> Error -> Bool+isReasonOf r e = maybe False (r ==) (reason e)++e400, e405, e406, e415, e500 :: Error+e400 = err status400+e405 = err status405+e406 = err status406+e415 = err status415+e500 = err status500+
src/Network/Wai/Predicate/Utility.hs view
@@ -4,7 +4,7 @@  {-# LANGUAGE OverloadedStrings #-} -module Network.Wai.Predicate.Utility (readValues) where+module Network.Wai.Predicate.Utility (readValues, (&)) where  import Data.ByteString (ByteString) import Data.ByteString.From@@ -18,3 +18,7 @@     res (Right x) _         = Right x     res _         (Left  x) = Left (fromString x) +infixl 1 &+(&) :: a -> (a -> b) -> b+a & f = f a+{-# INLINE (&) #-}
test/Tests/Wai/Predicate.hs view
@@ -4,9 +4,9 @@ module Tests.Wai.Predicate (tests) where  import Data.ByteString (ByteString)-import Network.HTTP.Types.Status import Network.Wai.Predicate import Network.Wai.Predicate.Request+import Network.Wai.Predicate.Utility import Test.Tasty import Test.Tasty.HUnit import Tests.Wai.Util@@ -29,7 +29,8 @@     Okay 0 (Media "application" "json" 1.0 []) @=? (accept "application" "json") rq0      let rq1 = fromRequest . withHeader "Accept" "foo/bar" $ defRequest "/"-    Fail (err status406 ("Expected 'Accept: application/json'.")) @=? (accept "application" "json") rq1+    Fail (e406 & setMessage "Expected 'Accept: application/json'.")+        @=? (accept "application" "json") rq1  testAcceptThrift :: IO () testAcceptThrift = do@@ -37,7 +38,8 @@     Okay 0 (Media "application" "x-thrift" 1.0 []) @=? (accept "application" "x-thrift") rq0      let rq1 = fromRequest . json $ defRequest "/"-    Fail (err status406 ("Expected 'Accept: application/x-thrift'.")) @=? (accept "application" "x-thrift") rq1+    Fail (e406 & setMessage "Expected 'Accept: application/x-thrift'.")+        @=? (accept "application" "x-thrift") rq1  testAcceptAll :: IO () testAcceptAll = do@@ -51,7 +53,8 @@     Okay 0 (Media "text" "plain" 1.0 []) @=? (contentType "text" "plain") rq0      let rq1 = fromRequest . withHeader "Content-Type" "text/html" $ defRequest "/"-    Fail (err status415 ("Expected 'Content-Type: text/plain'.")) @=? (contentType "text" "plain") rq1+    Fail (e415 & setMessage "Expected 'Content-Type: text/plain'.")+        @=? (contentType "text" "plain") rq1  testContentTypeAll :: IO () testContentTypeAll = do@@ -64,7 +67,8 @@     Okay 0 ("y" :: ByteString) @=? (query "x") rq0      let rq1 = fromRequest $ defRequest "/"-    Fail (err status400 ("Missing query 'x'.")) @=? (query "x" :: Predicate Req Error ByteString) rq1+    Fail (e400 & setReason NotAvailable . setSource "x" . addLabel "query")+        @=? (query "x" :: Predicate Req Error ByteString) rq1  testQueryOpt :: IO () testQueryOpt = do
wai-predicates.cabal view
@@ -1,5 +1,5 @@ name:                wai-predicates-version:             0.5+version:             0.6 synopsis:            WAI request predicates license:             OtherLicense license-file:        LICENSE@@ -56,7 +56,7 @@         attoparsec       >= 0.10   && < 0.12       , base             == 4.*       , bytestring       >= 0.9    && < 0.11-      , bytestring-from  == 0.2.*+      , bytestring-from  >= 0.2    && < 0.4       , cookie           == 0.4.*       , case-insensitive >= 1.1    && < 1.3       , http-types       == 0.8.*