packages feed

json-stream 0.3.0.3 → 0.3.0.4

raw patch · 4 files changed

+64/−8 lines, 4 filesPVP: minor bump suggested

API additions: PVP suggests at least a minor version bump

API changes (from Hackage documentation)

+ Data.JsonStream.Parser: arrayFound :: a -> a -> Parser a -> Parser a
+ Data.JsonStream.Parser: objectFound :: a -> a -> Parser a -> Parser a

Files

Data/JsonStream/Parser.hs view
@@ -67,6 +67,9 @@   , filterI   , takeI   , toList+    -- * SAX-like parsers+  , arrayFound+  , objectFound ) where  import           Control.Applicative@@ -222,6 +225,34 @@ arrayOf :: Parser a -> Parser a arrayOf valparse = array' (const valparse) +-- | Generate start/end objects when an element is found, in between run a parser.+-- The inner parser is not run if an array is not found.+elemFound :: Element -> a -> a -> Parser a -> Parser a+elemFound elsearch start end parser = Parser $ moreData handle+  where+    handle tok el _+      | el == elsearch = Yield start (parseAndAppend (callParse parser tok))+    handle tok _ _ = callParse ignoreVal tok++    parseAndAppend (Failed err) = Failed err+    parseAndAppend (Yield v np) = Yield v (parseAndAppend np)+    parseAndAppend (MoreData (Parser np, ntp)) = MoreData (Parser (parseAndAppend . np), ntp)+    parseAndAppend (Done ctx ntp) = Yield end (Done ctx ntp)++-- | Generate start/end values when an array is found, in between run a parser.+-- The inner parser is not run if an array is not found.+objectFound :: a -> a -> Parser a -> Parser a+objectFound = elemFound ObjectBegin++-- | Generate start/end values when an object is found, in between run a parser.+-- The inner parser is not run if an array is not found.+--+-- > >>> let test = "[[1,2,3],true,[],false,{\"key\":1}]" :: ByteString+-- > >>> parseByteString (arrayOf (arrayFound 10 20 (1 .! integer))) test :: [Int]+-- > [10,2,20,10,20]+arrayFound :: a -> a -> Parser a -> Parser a+arrayFound = elemFound ArrayBegin+ -- | Match nith item in an array. arrayWithIndexOf :: Int -> Parser a -> Parser a arrayWithIndexOf idx valparse = array' itemFn@@ -258,7 +289,7 @@     objcontent _ (Yield v np) = Yield v (objcontent True np)     objcontent _ (Failed err) = Failed err -    getLongKey acc len _ el ntok =+    getLongKey acc !len _ el ntok =       case el of         StringEnd           | Right key <- decodeUtf8' (BL.fromChunks $ reverse acc) ->@@ -332,12 +363,12 @@ longString :: Maybe Int -> Parser T.Text longString mbounds = Parser $ moreData (handle [] 0)   where-    handle acc len tok el ntok =+    handle acc !len tok el ntok =       case el of         JValue (AE.String str) -> Yield str (Done "" ntok)         StringContent str           | (Just bounds) <- mbounds, len > bounds -- If the string exceeds bounds, discard it-                          -> callParse (ignoreVal' 1) ntok+                          -> callParse (ignoreStrRestThen (Parser $ Done "")) ntok           | otherwise     -> moreData (handle (str:acc) (len + BS.length str)) ntok         StringEnd           | Right val <- decodeUtf8' (BL.fromChunks $ reverse acc)@@ -462,7 +493,7 @@     handleLongString level _ (StringContent _) ntok = moreData (handleLongString level) ntok     handleLongString 0 _ StringEnd ntok = Done "" ntok     handleLongString level _ StringEnd ntok = moreData (handleTok level) ntok-    handleLongString _ _ el _ = Failed $ "Unexpected element in handleLongStr: " ++ (show el)+    handleLongString _ _ el _ = Failed $ "Unexpected element in handleLongStr: " ++ show el      handleTok :: Int -> TokenResult -> Element -> TokenResult -> ParseResult a     handleTok 0 _ (JValue _) ntok = Done "" ntok
changelog.md view
@@ -1,2 +1,7 @@+# 0.3.0.4+- Fixed bug in safestring+- Fixed test so it doesn't depend on versions of other packages+- Added sax-like parsers+ # 0.3.0.3-Fixed wrong size of C structure in FFI that was causing a segfault.+- Fixed wrong size of C structure in FFI that was causing a segfault.
json-stream.cabal view
@@ -1,5 +1,5 @@ name:                json-stream-version:             0.3.0.3+version:             0.3.0.4 synopsis:            Incremental applicative JSON parser description:         Easy to use JSON parser fully supporting incremental parsing.                      Parsing grammar in applicative form.
test/ParserSpec.hs view
@@ -11,6 +11,8 @@ import Data.Text.Encoding (encodeUtf8) import Control.Monad (forM_) import Data.Text.Encoding (encodeUtf8)+import qualified Data.Vector as Vec+import qualified Data.HashMap.Strict as HMap  import Data.JsonStream.Parser import Data.JsonStream.TokenParser@@ -103,14 +105,25 @@         msg = parseLazyByteString parser (BL.fromChunks test) :: [Int]     msg `shouldBe` [1] +  it "arrayFound generates events" $ do+    let test = ["[[1,2,3],true,[],false,{\"key\":1}]"]+        parser = arrayOf (arrayFound 10 20 (1 .! integer))+        msg = parseLazyByteString parser (BL.fromChunks test) :: [Int]+    msg `shouldBe` [10,2,20,10,20] +  it "objectFound generates events" $ do+    let test = ["[[1,2,3],true,[],false,{\"key\":1}]"]+        parser = arrayOf (objectFound 10 20 ("key" .: integer))+        msg = parseLazyByteString parser (BL.fromChunks test) :: [Int]+    msg `shouldBe` [10,1,20]+ specEdge :: Spec specEdge = describe "Edge cases" $ do   it "Correct incremental parsing 1" $ do     let msg1 = "[ {\"test1\"  :[1,true,false,null,-3.591e+1,[12,13]], \"test2\":\"123\\r\\n\\\"\\u0041\"}]"         pmsg = BL.fromChunks $ map BS.singleton msg1         res = parseLazyByteString value pmsg :: [AE.Value]-    show res `shouldBe` "[Array (fromList [Object fromList [(\"test2\",String \"123\\r\\n\\\"A\"),(\"test1\",Array (fromList [Number 1.0,Bool True,Bool False,Null,Number -35.91,Array (fromList [Number 12.0,Number 13.0])]))]])]"+    res `shouldBe` [Array (Vec.fromList [Object $ HMap.fromList [("test2",String "123\r\n\"A"),("test1",Array (Vec.fromList [Number 1.0,Bool True,Bool False,Null,Number (-35.91),Array (Vec.fromList [Number 12.0,Number 13.0])]))]])]    it "Correct incremental parsing 2" $ do     let msg1 = "{\"test1\"  :[1,true,false,null,-3.591e+1,[12,13]], \"test2\":\"test2string\"}"@@ -266,8 +279,15 @@     let test1 = "[\"\", \"\", true]"         onechar = BL.fromChunks $ map BS.singleton $ BS.unpack test1         parser = arrayOf bool-        res = parseByteString parser test1 :: [Bool]+        res = parseLazyByteString parser onechar :: [Bool]     res `shouldBe` [True]++  it "Correctly parses safeString when sliced" $ do+    let test1 = "[\"looooooooooong\", \"short\"]"+        onechar = BL.fromChunks $ map BS.singleton $ BS.unpack test1+        parser = arrayOf (safeString 6)+        res = parseLazyByteString parser onechar :: [T.Text]+    res `shouldBe` ["short"]   -- testLexer (start:rest) = iter rest (tokenParser start)