packages feed

list-t-html-parser 0.2.1.0 → 0.2.2.0

raw patch · 4 files changed

+211/−7 lines, 4 filesdep +case-insensitivedep +conversiondep +conversion-textdep ~base-preludedep ~html-tokenizerdep ~textPVP ok

version bump matches the API change (PVP)

Dependencies added: case-insensitive, conversion, conversion-text, hspec, html-entities, list-t-attoparsec, list-t-html-parser, list-t-text

Dependency ranges changed: base-prelude, html-tokenizer, text

API changes (from Hackage documentation)

+ ListT.HTMLParser: html :: Monad m => Parser m Builder
+ ListT.HTMLParser: instance Eq ErrorDetails
+ ListT.HTMLParser: many1 :: Monad m => Parser m a -> Parser m [a]

Files

+ hspec/Main.hs view
@@ -0,0 +1,91 @@+module Main where++import BasePrelude+import Test.Hspec+import Conversion+import Conversion.Text+import Data.Text (Text)+import qualified HTMLTokenizer.Parser+import qualified ListT.Attoparsec+import qualified ListT.HTMLParser+import qualified ListT.Text+import qualified ListT.HTMLParser as P+++main =+  hspec $ do+    it "Backtracking" $ do+      let +        text = "<a><b></b></a>"+        parser = +          a <|> b+          where+            a = +              do+                P.openingTag+                P.openingTag+                P.openingTag+                return 1+            b =+              do+                P.openingTag+                P.openingTag+                P.closingTag+                P.closingTag+                return 2+      result <- parse parser text+      shouldBe result (Right 2)+    it "Complex" $ do+      let +        text = "<a><b><c></c></b></a>"+        parser = +          a <|> b+          where+            a = +              do+                P.openingTag+                b <|> c+                P.openingTag+                return 1+              where+                b =+                  do+                    ("b", _, _) <- P.openingTag+                    P.closingTag+                c =+                  do+                    ("b", _, _) <- P.openingTag+                    ("c", _, _) <- P.openingTag+                    P.closingTag+            b =+              do+                P.openingTag+                P.openingTag+                P.openingTag+                P.closingTag+                P.closingTag+                P.closingTag+                return 2+      result <- parse parser text+      shouldBe result (Right 2)++++-- | Scrape the body of a GET response using an HTML parser.+parse :: ListT.HTMLParser.Parser IO a -> Text -> IO (Either Error a)+parse parser =+  fmap (either (Left . parseSomeException) id) . try .+  fmap (either (Left . Error_Parsing) Right) .+  ListT.HTMLParser.run parser . ListT.Attoparsec.textParser HTMLTokenizer.Parser.token . +  ListT.Text.stream 2+  where+    parseSomeException e =+      fromMaybe (error $ showString "Unexpected exception: " $ shows e $ "") $+        Error_Lexing <$> fromException e++data Error =+  -- | A tokenization failure+  Error_Lexing ListT.Attoparsec.ParsingFailure |+  -- | A token-stream parsing failure+  Error_Parsing ListT.HTMLParser.Error+  deriving (Show, Eq)
library/ListT/HTMLParser.hs view
@@ -11,7 +11,9 @@   closingTag,   text,   comment,+  html,   -- * Combinators+  many1,   manyTill,   skipTill,   total,@@ -23,8 +25,11 @@ import Control.Monad.Trans.Either hiding (left, right) import ListT (ListT) import Data.Text (Text)+import qualified Data.Text.Lazy.Builder as Text (Builder)+import qualified Data.Text.Lazy.Builder as Text.Builder import qualified ListT as L import qualified HTMLTokenizer.Parser as HT+import qualified ListT.HTMLParser.Renderer as Renderer   -- |@@ -46,7 +51,7 @@   ErrorDetails_UnexpectedToken |   -- | End of input   ErrorDetails_EOI-  deriving (Show)+  deriving (Show, Eq)  instance Monad m => Monad (Parser m) where   return =@@ -62,11 +67,13 @@   (<|>) a b =     Parser $ EitherT $ StateT $ \(incoming, backtrack) -> do       (aResult, (incoming', backtrack')) <- flip runStateT (incoming, []) $ runEitherT $ unwrap $ a-      case aResult of-        Left _ -> do-          flip runStateT (foldr L.cons incoming' backtrack', []) $ runEitherT $ unwrap $ b-        Right aResult -> do-          return (Right aResult, (incoming', backtrack'))+      (result'', (incoming'', backtrack'')) <-+        case aResult of+          Left _ -> do+            flip runStateT (foldl' (flip L.cons) incoming' backtrack', []) $ runEitherT $ unwrap $ b+          Right aResult -> do+            return (Right aResult, (incoming', backtrack'))+      return (result'', (incoming'', backtrack'' <> backtrack))  instance Monad m => MonadPlus (Parser m) where   mzero = empty@@ -127,6 +134,12 @@     _ -> throwError (Just ErrorDetails_UnexpectedToken)  -- |+-- Apply a parser at least one time.+many1 :: Monad m => Parser m a -> Parser m [a]+many1 a =+  (:) <$> a <*> many a++-- | -- Apply a parser multiple times until another parser is satisfied. -- Returns results of both parsers. manyTill :: Monad m => Parser m a -> Parser m b -> Parser m ([a], b)@@ -151,3 +164,28 @@ total :: Monad m => Parser m a -> Parser m a total a =   a <* eoi++-- |+-- The textual HTML representation of a proper HTML tree node.+-- +-- Useful for consuming HTML-formatted snippets.+html :: Monad m => Parser m Text.Builder+html =+  enclosingTag <|> brokenOpenTag <|> text' <|> comment'+  where+    enclosingTag =+      do+        ot@(n, _, False) <- openingTag  +        theHTML <- mconcat <$> many html+        ct <- closingTag+        guard $ ct == n+        return $ Renderer.openingTag ot <> theHTML <> Renderer.closingTag ct+    brokenOpenTag =+      Renderer.openingTag . repair <$> openingTag+      where+        repair (name, attrs, _) = (name, attrs, True)+    text' =+      Renderer.text <$> text+    comment' =+      Renderer.comment <$> comment+
+ library/ListT/HTMLParser/Renderer.hs view
@@ -0,0 +1,45 @@+module ListT.HTMLParser.Renderer where++import BasePrelude hiding (fromString)+import Data.Text (Text)+import Data.Text.Lazy.Builder+import HTMLTokenizer.Parser (Token(..), OpeningTag, ClosingTag, Attribute)+import qualified Data.CaseInsensitive as CI+import qualified HTMLEntities.Builder+++openingTag :: OpeningTag -> Builder+openingTag (name, attrs, closed) =+  singleton '<' <>+  ciText name <>+  mconcat (map (mappend (singleton ' ') . attribute) attrs) <>+  bool (singleton '>') (fromString "/>") closed++attribute :: Attribute -> Builder+attribute (name, value) =+  maybe id (flip mappend . mappend (fromString "=\"") . flip mappend (singleton '"') . HTMLEntities.Builder.text) value $+  ciText name++ciText :: CI.CI Text -> Builder+ciText =+  HTMLEntities.Builder.text . CI.foldedCase  ++closingTag :: ClosingTag -> Builder+closingTag name =+  fromString "</" <> ciText name <> singleton '>'++text :: Text -> Builder+text =+  HTMLEntities.Builder.text++comment :: Text -> Builder+comment content =+  fromString "<!--" <> fromText content <> fromString "-->"++token :: Token -> Builder+token =+  \case+    Token_OpeningTag x -> openingTag x+    Token_ClosingTag x -> closingTag x+    Token_Text x -> text x+    Token_Comment x -> comment x
list-t-html-parser.cabal view
@@ -1,7 +1,7 @@ name:   list-t-html-parser version:-  0.2.1.0+  0.2.2.0 synopsis:   Streaming HTML parser category:@@ -37,6 +37,7 @@   hs-source-dirs:     library   other-modules:+    ListT.HTMLParser.Renderer   exposed-modules:     ListT.HTMLParser   ghc-options:@@ -48,7 +49,36 @@   build-depends:     list-t == 0.4.*,     html-tokenizer >= 0.2.1 && < 0.3,+    html-entities >= 1.0.1 && < 1.2,+    case-insensitive == 1.2.*,     text >= 1 && < 1.3,     either == 4.*,     mtl-prelude >= 1 && < 3,     base-prelude >= 0.1.19 && < 0.2+++test-suite hspec+  type:+    exitcode-stdio-1.0+  hs-source-dirs:+    hspec+  main-is:+    Main.hs+  ghc-options:+    -threaded+    "-with-rtsopts=-N"+    -funbox-strict-fields+  default-extensions:+    Arrows, BangPatterns, ConstraintKinds, DataKinds, DefaultSignatures, DeriveDataTypeable, DeriveFoldable, DeriveFunctor, DeriveGeneric, DeriveTraversable, EmptyDataDecls, FlexibleContexts, FlexibleInstances, FunctionalDependencies, GADTs, GeneralizedNewtypeDeriving, ImpredicativeTypes, LambdaCase, LiberalTypeSynonyms, MagicHash, MultiParamTypeClasses, MultiWayIf, NoImplicitPrelude, NoMonomorphismRestriction, OverloadedStrings, PatternGuards, ParallelListComp, QuasiQuotes, RankNTypes, RecordWildCards, ScopedTypeVariables, StandaloneDeriving, TemplateHaskell, TupleSections, TypeFamilies, TypeOperators, UnboxedTuples+  default-language:+    Haskell2010+  build-depends:+    hspec == 2.1.*,+    list-t-html-parser,+    list-t-attoparsec == 0.2.*,+    list-t-text == 0.2.*,+    html-tokenizer,+    conversion == 1.*,+    conversion-text == 1.*,+    text,+    base-prelude