http-api-data 0.1.1.1 → 0.2
raw patch · 5 files changed
+122/−32 lines, 5 filesPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
- Web.HttpApiData.Internal: parseBoundedCaseInsensitiveTextData :: (Show a, Bounded a, Enum a) => Text -> Either Text a
- Web.HttpApiData.Internal: readEitherTextData :: Read a => Text -> Either Text a
- Web.HttpApiData.Internal: readMaybeTextData :: Read a => Text -> Maybe a
+ Web.HttpApiData: parseBoundedTextData :: (Show a, Bounded a, Enum a) => Text -> Either Text a
+ Web.HttpApiData: parseHeaderMaybe :: FromHttpApiData a => ByteString -> Maybe a
+ Web.HttpApiData: parseHeaderWithPrefix :: FromHttpApiData a => ByteString -> ByteString -> Either Text a
+ Web.HttpApiData: parseQueryParamMaybe :: FromHttpApiData a => Text -> Maybe a
+ Web.HttpApiData: parseQueryParamWithPrefix :: FromHttpApiData a => Text -> Text -> Either Text a
+ Web.HttpApiData: parseUrlPieceMaybe :: FromHttpApiData a => Text -> Maybe a
+ Web.HttpApiData: parseUrlPieceWithPrefix :: FromHttpApiData a => Text -> Text -> Either Text a
+ Web.HttpApiData: readTextData :: Read a => Text -> Either Text a
+ Web.HttpApiData: showTextData :: Show a => a -> Text
+ Web.HttpApiData.Internal: parseBoundedTextData :: (Show a, Bounded a, Enum a) => Text -> Either Text a
+ Web.HttpApiData.Internal: parseHeaderWithPrefix :: FromHttpApiData a => ByteString -> ByteString -> Either Text a
+ Web.HttpApiData.Internal: parseQueryParamWithPrefix :: FromHttpApiData a => Text -> Text -> Either Text a
+ Web.HttpApiData.Internal: readTextData :: Read a => Text -> Either Text a
Files
- CHANGELOG.md +9/−0
- Web/HttpApiData.hs +15/−0
- Web/HttpApiData/Internal.hs +97/−30
- http-api-data.cabal +1/−1
- test/Spec.hs +0/−1
CHANGELOG.md view
@@ -1,3 +1,12 @@+0.2+---++* Export helper functions from `Web.HttpApiData`:+ * `parseUrlPieceMaybe`, `parseHeaderMaybe`, `parseQueryParamMaybe`+ * `parseUrlPieceWithPrefix`, `parseHeaderWithPrefix`, `parseQueryParamWithPrefix`+ * `showTextData`, `readTextData`, `parseBoundedTextData`+* Fix AMP related warnings+ 0.1.1 ---
Web/HttpApiData.hs view
@@ -8,6 +8,21 @@ -- * Classes ToHttpApiData (..), FromHttpApiData (..),++ -- * @'Maybe'@ parsers+ parseUrlPieceMaybe,+ parseHeaderMaybe,+ parseQueryParamMaybe,++ -- * Prefix parsers+ parseUrlPieceWithPrefix,+ parseHeaderWithPrefix,+ parseQueryParamWithPrefix,++ -- * Other helpers+ showTextData,+ readTextData,+ parseBoundedTextData, ) where import Web.HttpApiData.Internal
Web/HttpApiData/Internal.hs view
@@ -9,11 +9,14 @@ -- such as URL pieces, headers and query parameters. module Web.HttpApiData.Internal where +#if __GLASGOW_HASKELL__ < 710 import Control.Applicative+#endif import Control.Arrow ((&&&)) import Data.Monoid import Data.ByteString (ByteString)+import qualified Data.ByteString as BS import Data.Int import Data.Word@@ -24,7 +27,7 @@ import qualified Data.Text as T import qualified Data.Text.Lazy as L -import Data.Time (Day)+import Data.Time import Data.Version #if MIN_VERSION_base(4,8,0)@@ -101,7 +104,9 @@ Just val -> Right val #if USE_TEXT_SHOW--- | Convert to URL piece using @'TextShow'@ instance.+-- | /Lower case/.+--+-- Convert to URL piece using @'TextShow'@ instance. -- The result is always lower cased. -- -- >>> showTextData True@@ -121,7 +126,9 @@ showTextData :: TextShow a => a -> Text showTextData = T.toLower . showt #else--- | Convert to URL piece using @'Show'@ instance.+-- | /Lower case/.+--+-- Convert to URL piece using @'Show'@ instance. -- The result is always lower cased. -- -- >>> showTextData True@@ -141,8 +148,11 @@ showt = T.pack . show #endif --- | Parse given text case insensitive and return the rest of the input.+-- | /Case insensitive/. --+-- Parse given text case insensitive and then parse the rest of the input+-- using @'parseUrlPiece'@.+-- -- >>> parseUrlPieceWithPrefix "Just " "just 10" :: Either Text Int -- Right 10 -- >>> parseUrlPieceWithPrefix "Left " "left" :: Either Text Bool@@ -161,12 +171,49 @@ where (prefix, rest) = T.splitAt (T.length pattern) input +-- $setup+-- >>> data BasicAuthToken = BasicAuthToken Text deriving (Show)+-- >>> instance FromHttpApiData BasicAuthToken where parseHeader h = BasicAuthToken <$> parseHeaderWithPrefix "Basic " h; parseQueryParam p = BasicAuthToken <$> parseQueryParam p++-- | Parse given bytestring then parse the rest of the input using @'parseHeader'@.+--+-- @+-- data BasicAuthToken = BasicAuthToken Text deriving (Show)+--+-- instance FromHttpApiData BasicAuthToken where+-- parseHeader h = BasicAuthToken \<$\> parseHeaderWithPrefix "Basic " h+-- parseQueryParam p = BasicAuthToken \<$\> parseQueryParam p+-- @+--+-- >>> parseHeader "Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==" :: Either Text BasicAuthToken+-- Right (BasicAuthToken "QWxhZGRpbjpvcGVuIHNlc2FtZQ==")+parseHeaderWithPrefix :: FromHttpApiData a => ByteString -> ByteString -> Either Text a+parseHeaderWithPrefix pattern input+ | pattern `BS.isPrefixOf` input = parseHeader (BS.drop (BS.length pattern) input)+ | otherwise = defaultParseError (showt input)++-- | /Case insensitive/.+--+-- Parse given text case insensitive and then parse the rest of the input+-- using @'parseQueryParam'@.+--+-- >>> parseQueryParamWithPrefix "z" "z10" :: Either Text Int+-- Right 10+parseQueryParamWithPrefix :: FromHttpApiData a => Text -> Text -> Either Text a+parseQueryParamWithPrefix pattern input+ | T.toLower pattern == T.toLower prefix = parseQueryParam rest+ | otherwise = defaultParseError input+ where+ (prefix, rest) = T.splitAt (T.length pattern) input+ #if USE_TEXT_SHOW--- | Parse values case insensitively based on @'TextShow'@ instance.+-- | /Case insensitive/. ----- >>> parseBoundedCaseInsensitiveTextData "true" :: Either Text Bool+-- Parse values case insensitively based on @'TextShow'@ instance.+--+-- >>> parseBoundedTextData "true" :: Either Text Bool -- Right True--- >>> parseBoundedCaseInsensitiveTextData "FALSE" :: Either Text Bool+-- >>> parseBoundedTextData "FALSE" :: Either Text Bool -- Right False -- -- This can be used as a default implementation for enumeration types:@@ -178,36 +225,47 @@ -- showt = genericShowt -- -- instance FromHttpApiData MyData where--- parseUrlPiece = parseBoundedCaseInsensitiveTextData+-- parseUrlPiece = parseBoundedTextData -- @-parseBoundedCaseInsensitiveTextData :: forall a. (TextShow a, Bounded a, Enum a) => Text -> Either Text a+parseBoundedTextData :: (TextShow a, Bounded a, Enum a) => Text -> Either Text a #else--- | Parse values case insensitively based on @'Show'@ instance.+-- | /Case insensitive/. ----- >>> parseBoundedCaseInsensitiveTextData "true" :: Either Text Bool+-- Parse values case insensitively based on @'Show'@ instance.+--+-- >>> parseBoundedTextData "true" :: Either Text Bool -- Right True--- >>> parseBoundedCaseInsensitiveTextData "FALSE" :: Either Text Bool+-- >>> parseBoundedTextData "FALSE" :: Either Text Bool -- Right False -- -- This can be used as a default implementation for enumeration types: -- -- >>> data MyData = Foo | Bar | Baz deriving (Show, Bounded, Enum)--- >>> instance FromHttpApiData MyData where parseUrlPiece = parseBoundedCaseInsensitiveTextData+-- >>> instance FromHttpApiData MyData where parseUrlPiece = parseBoundedTextData -- >>> parseUrlPiece "foo" :: Either Text MyData -- Right Foo-parseBoundedCaseInsensitiveTextData :: forall a. (Show a, Bounded a, Enum a) => Text -> Either Text a+parseBoundedTextData :: (Show a, Bounded a, Enum a) => Text -> Either Text a #endif-parseBoundedCaseInsensitiveTextData = parseMaybeTextData (flip lookup values . T.toLower)+parseBoundedTextData = parseMaybeTextData (flip lookup values . T.toLower) where- values = map (showTextData &&& id) [minBound..maxBound :: a]---- | Parse URL piece using @'Read'@ instance.-readMaybeTextData :: Read a => Text -> Maybe a-readMaybeTextData = readMaybe . T.unpack+ values = map (showTextData &&& id) [minBound..maxBound] -- | Parse URL piece using @'Read'@ instance.-readEitherTextData :: Read a => Text -> Either Text a-readEitherTextData = parseMaybeTextData readMaybeTextData+--+-- Use for types which do not involve letters:+--+-- >>> readTextData "1991-06-02" :: Either Text Day+-- Right 1991-06-02+--+-- This parser is case sensitive and will not match @'showTextData'@+-- in presense of letters:+--+-- >>> readTextData (showTextData True) :: Either Text Bool+-- Left "could not parse: `true'"+--+-- See @'parseBoundedTextData'@.+readTextData :: Read a => Text -> Either Text a+readTextData = parseMaybeTextData (readMaybe . T.unpack) -- | Run @'Reader'@ as HTTP API data parser. runReader :: Reader a -> Text -> Either Text a@@ -226,7 +284,7 @@ parseBounded reader input = do n <- runReader reader input if (n > h || n < l)- then Left ("out of bounds: `" <> input <> "' (should be between " <> T.pack (show l) <> " and " <> T.pack (show h) <> ")")+ then Left ("out of bounds: `" <> input <> "' (should be between " <> showt l <> " and " <> showt h <> ")") else Right (fromInteger n) where l = toInteger (minBound :: a)@@ -267,6 +325,10 @@ instance ToHttpApiData Word16 where toUrlPiece = showt instance ToHttpApiData Word32 where toUrlPiece = showt instance ToHttpApiData Word64 where toUrlPiece = showt++-- |+-- >>> toUrlPiece (fromGregorian 2015 10 03)+-- "2015-10-03" instance ToHttpApiData Day where toUrlPiece = T.pack . show instance ToHttpApiData String where toUrlPiece = T.pack@@ -302,13 +364,13 @@ -- >>> parseUrlPiece "_" :: Either Text () -- Right () instance FromHttpApiData () where- parseUrlPiece "_" = return ()+ parseUrlPiece "_" = pure () parseUrlPiece s = defaultParseError s instance FromHttpApiData Char where parseUrlPiece s = case T.uncons s of- Just (c, s') | T.null s' -> return c+ Just (c, s') | T.null s' -> pure c _ -> defaultParseError s -- |@@ -317,16 +379,17 @@ instance FromHttpApiData Version where parseUrlPiece s = case reverse (readP_to_S parseVersion (T.unpack s)) of- ((x, ""):_) -> return x+ ((x, ""):_) -> pure x _ -> defaultParseError s #if MIN_VERSION_base(4,8,0)+-- | Parsing a @'Void'@ value is always an error, considering @'Void'@ as a data type with no constructors. instance FromHttpApiData Void where parseUrlPiece _ = Left "Void cannot be parsed!" #endif -instance FromHttpApiData Bool where parseUrlPiece = parseBoundedCaseInsensitiveTextData-instance FromHttpApiData Ordering where parseUrlPiece = parseBoundedCaseInsensitiveTextData+instance FromHttpApiData Bool where parseUrlPiece = parseBoundedTextData+instance FromHttpApiData Ordering where parseUrlPiece = parseBoundedTextData instance FromHttpApiData Double where parseUrlPiece = runReader rational instance FromHttpApiData Float where parseUrlPiece = runReader rational instance FromHttpApiData Int where parseUrlPiece = parseBounded (signed decimal)@@ -343,8 +406,12 @@ instance FromHttpApiData String where parseUrlPiece = Right . T.unpack instance FromHttpApiData Text where parseUrlPiece = Right instance FromHttpApiData L.Text where parseUrlPiece = Right . L.fromStrict-instance FromHttpApiData Day where parseUrlPiece = readEitherTextData +-- |+-- >>> toGregorian <$> parseUrlPiece "2016-12-01"+-- Right (2016,12,1)+instance FromHttpApiData Day where parseUrlPiece = readTextData+ instance FromHttpApiData All where parseUrlPiece = fmap All . parseUrlPiece instance FromHttpApiData Any where parseUrlPiece = fmap Any . parseUrlPiece @@ -359,7 +426,7 @@ -- Right (Just 123) instance FromHttpApiData a => FromHttpApiData (Maybe a) where parseUrlPiece s- | T.toLower (T.take 7 s) == "nothing" = return Nothing+ | T.toLower (T.take 7 s) == "nothing" = pure Nothing | otherwise = Just <$> parseUrlPieceWithPrefix "Just " s -- |
http-api-data.cabal view
@@ -1,5 +1,5 @@ name: http-api-data-version: 0.1.1.1+version: 0.2 license: BSD3 license-file: LICENSE author: Nickolay Kudasov <nickolay.kudasov@gmail.com>
test/Spec.hs view
@@ -17,7 +17,6 @@ import Test.QuickCheck import Web.HttpApiData-import Web.HttpApiData.Internal instance Arbitrary T.Text where arbitrary = T.pack <$> arbitrary