pandoc-utils 0.4.0 → 0.5.0
raw patch · 8 files changed
+313/−126 lines, 8 filesPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
- Text.Pandoc.Utils: class IsString a
- Text.Pandoc.Utils: class IsText a
- Text.Pandoc.Utils: class IsString s => ToString s
- Text.Pandoc.Utils: class IsString s => ToText s
- Text.Pandoc.Utils: fromString :: IsString a => String -> a
- Text.Pandoc.Utils: fromText :: IsText a => Text -> a
- Text.Pandoc.Utils: instance (GHC.Types.Char GHC.Types.~ c) => Text.Pandoc.Utils.IsText [c]
- Text.Pandoc.Utils: instance (GHC.Types.Char GHC.Types.~ c) => Text.Pandoc.Utils.ToString [c]
- Text.Pandoc.Utils: instance (GHC.Types.Char GHC.Types.~ c) => Text.Pandoc.Utils.ToText [c]
- Text.Pandoc.Utils: instance Text.Pandoc.Utils.IsText Data.Text.Internal.Text
- Text.Pandoc.Utils: instance Text.Pandoc.Utils.ToString Data.Text.Internal.Text
- Text.Pandoc.Utils: instance Text.Pandoc.Utils.ToText Data.Text.Internal.Text
- Text.Pandoc.Utils: toString :: ToString s => s -> String
- Text.Pandoc.Utils: toText :: ToText s => s -> Text
+ Text.Pandoc.Filter.Utils: convertFilter :: ToPartialFilter Identity f p => f -> p -> p
+ Text.Pandoc.Filter.Utils: convertFilterM :: (Monad m, ToPartialFilter m f p) => f -> p -> m p
+ Text.Pandoc.Utils.String: class IsString a
+ Text.Pandoc.Utils.String: class IsText a
+ Text.Pandoc.Utils.String: class IsString s => ToString s
+ Text.Pandoc.Utils.String: class IsString s => ToText s
+ Text.Pandoc.Utils.String: fromString :: IsString a => String -> a
+ Text.Pandoc.Utils.String: fromText :: IsText a => Text -> a
+ Text.Pandoc.Utils.String: instance (GHC.Types.Char GHC.Types.~ c) => Text.Pandoc.Utils.String.IsText [c]
+ Text.Pandoc.Utils.String: instance (GHC.Types.Char GHC.Types.~ c) => Text.Pandoc.Utils.String.ToString [c]
+ Text.Pandoc.Utils.String: instance (GHC.Types.Char GHC.Types.~ c) => Text.Pandoc.Utils.String.ToText [c]
+ Text.Pandoc.Utils.String: instance Text.Pandoc.Utils.String.IsText Data.Text.Internal.Text
+ Text.Pandoc.Utils.String: instance Text.Pandoc.Utils.String.ToString Data.Text.Internal.Text
+ Text.Pandoc.Utils.String: instance Text.Pandoc.Utils.String.ToText Data.Text.Internal.Text
+ Text.Pandoc.Utils.String: toString :: ToString s => s -> String
+ Text.Pandoc.Utils.String: toText :: ToText s => s -> Text
- Text.Pandoc.Filter.Utils: getConcatedFilter :: Foldable t => t (PartialFilter p) -> p -> p
+ Text.Pandoc.Filter.Utils: getConcatedFilter :: (Foldable t, Walkable a b) => t (PartialFilter a) -> b -> b
- Text.Pandoc.Filter.Utils: getConcatedFilterM :: (Foldable t, Monad m) => t (PartialFilterM m p) -> p -> m p
+ Text.Pandoc.Filter.Utils: getConcatedFilterM :: (Foldable t, Monad m, Walkable a b) => t (PartialFilterM m a) -> b -> m b
Files
- CHANGELOG.md +8/−0
- README.md +29/−12
- pandoc-utils.cabal +10/−5
- src/Text/Pandoc/Filter/Utils.hs +113/−53
- src/Text/Pandoc/Filter/Utils/AttrBuilder.hs +1/−1
- src/Text/Pandoc/Utils.hs +11/−50
- src/Text/Pandoc/Utils/String.hs +52/−0
- test/Spec.hs +89/−5
CHANGELOG.md view
@@ -1,5 +1,13 @@ # Releases +## pandoc-utils 0.5.0 (2020-5-24)++- Reorganize documentations and API.+- Add new functions `convertFilter` and `convertFilterM` to convert between+ filter functions.+- Enable implicit conversion in `getConcatedFilter` and `getConcatedFilterM`.+- Add a module exporting all the utility functions provided by the package.+ ## pandoc-utils 0.4.0 (2020-5-24) - Initial public release.
README.md view
@@ -1,11 +1,18 @@ # pandoc-utils +[](https://github.com/Krasjet/pandoc-utils/actions?query=workflow%3Abuild)+[](https://hackage.haskell.org/package/pandoc-utils)+ This package contains some useful functions for writing [Pandoc](https://pandoc.org/) filters and integrating Pandoc into Haskell-applications such as [Hakyll](https://jaspervdj.be/hakyll/). It provides a-composable wrapper for filters acting on nodes of the [Pandoc-AST](https://hackage.haskell.org/package/pandoc-types/docs/Text-Pandoc-Definition.html).+applications such as [Hakyll](https://jaspervdj.be/hakyll/). +It provides a composable wrapper for filters acting on nodes of the [Pandoc+AST](https://hackage.haskell.org/package/pandoc-types/docs/Text-Pandoc-Definition.html)+and a few functions to convert between filters. The package also provides an+attributes builder to work with attributes and some string utility functions to+handle the switch from `String` to `Text` in pandoc-types 1.20.+ ## Filter conversion/composition As an example, let us look at the `behead` and `delink` filter from [Pandoc's@@ -22,9 +29,9 @@ Since `behead` has type `Block -> Block`, while `delink` has type `Inline -> [Inline]`, they are not naturally composable. However, this package provides a-utility function `mkFilter` to convert them into a `PandocFilter`.+utility function `mkFilter` to convert them into a wrapped `PandocFilter`. ```haskell-import Text.Pandoc.Filter.Utils+import Text.Pandoc.Utils beheadFilter :: PandocFilter beheadFilter = mkFilter behead@@ -34,7 +41,7 @@ ``` `PandocFilter` is an alias for `PartialFilter Pandoc`, so you can also have `PartialFilter Inline`, etc. There is also a monadic version called-`PartialFilterM` for encapsulating monadic filters.+`PartialFilterM` for encapsulating monadic filter functions. The `PandocFilter` is a monoid so you can do something like, ```haskell@@ -55,17 +62,27 @@ let doc' = applyFilter myFilter doc writeHtml5String def doc' ```-or get an unwrapped `Pandoc -> Pandoc` filter using `getFilter` (this function-is also capable of doing implicit conversion from `PartialFilter a` to `b ->-b`).+or get an unwrapped `Pandoc -> Pandoc` filter function using `getFilter` (this+function is also capable of doing implicit conversion from `PartialFilter a` to+`b -> b`). ```haskell myPandocFilter :: Pandoc -> Pandoc myPandocFilter = getFilter myFilter ``` +If you just want to convert between Pandoc filter functions, e.g. `Inline ->+[Inline]` to `Pandoc -> Pandoc` without using the wrapped filter, there is also+`convertFilter` and `convertFilterM`+```haskell+delinkPandoc :: Pandoc -> Pandoc+delinkPandoc = convertFilter delink+```+This function is slightly more powerful than `walk` and `walkM` in that it is+also able to handle filter functions of type `a -> [a]` and `a -> m [a]`.+ For applying multiple filters, there is also a function called `applyFilters`,-which takes a list of filters and apply it to a `Pandoc` document (or subnode)-sequentially, from left to right.+which takes a list of wrapped filters and apply it to a `Pandoc` document (or+subnode) sequentially, from left to right. ```haskell myFilters :: [PandocFilter] myFilters =@@ -87,7 +104,7 @@ pandoc-utils also provides an attribute builder for handling attributes. You can create a new attributes by ```haskell-ghci> import Text.Pandoc.Filter.Utils.AttrBuilder+ghci> import Text.Pandoc.Utils ghci> import Text.Pandoc.Definition ghci> nullAttr `setId` "id" `addClass` "class" `addKVPair` ("key","value") ("id",["class"],[("key","value")])
pandoc-utils.cabal view
@@ -2,16 +2,20 @@ cabal-version: 2.0 name: pandoc-utils-version: 0.4.0+version: 0.5.0 synopsis: Utility functions to work with Pandoc in Haskell applications. description: This package contains some useful functions for writing [Pandoc](https://pandoc.org/)- filters and integrating Pandoc into Haskell applications such- as [Hakyll](https://jaspervdj.be/hakyll/). It provides a- composable wrapper for filters acting on nodes of the [Pandoc- AST](https://hackage.haskell.org/package/pandoc-types/docs/Text-Pandoc-Definition.html).+ filters and integrating Pandoc into Haskell applications such as+ [Hakyll](https://jaspervdj.be/hakyll/) and web servers. .+ It provides a composable wrapper for filters acting on nodes of the [Pandoc+ AST](https://hackage.haskell.org/package/pandoc-types/docs/Text-Pandoc-Definition.html)+ and a few functions to convert between filters. The package also provides an+ attributes builder to work with attributes and some string utility functions+ to handle the switch from 'String' to 'Text' in pandoc-types 1.20.+ . For more examples, please see the [README](https://github.com/Krasjet/pandoc-utils) on GitHub. license: MIT license-file: LICENSE@@ -35,6 +39,7 @@ ghc-options: -Wall exposed-modules: Text.Pandoc.Utils+ Text.Pandoc.Utils.String Text.Pandoc.Filter.Utils Text.Pandoc.Filter.Utils.AttrBuilder build-depends:
src/Text/Pandoc/Filter/Utils.hs view
@@ -5,25 +5,37 @@ -- | This module contains some utility functions to work with different levels -- of Pandoc filters. For example, for the conversion from @'Inline' -> -- ['Inline']@ to @'Pandoc' -> 'Pandoc'@ filter.+--+-- If you don't need to compose filters and only want to convert between Pandoc+-- filter functions, just use 'convertFilter' and 'convertFilterM'.+--+-- However, if you are working with multiple Pandoc filters of different type+-- and want to compose them, this module also provides a monoid wrapper type+-- 'PartialFilterM', which I call a "wrapped filter", and a few functions to+-- apply, compose, and convert them. module Text.Pandoc.Filter.Utils (- -- * Definitions- PartialFilterM,+ -- * Filter function conversion+ convertFilter,+ convertFilterM,+ -- * Wrapped filter definitions PartialFilter,- PandocFilterM, PandocFilter,- -- * Filter application- applyFilterM,+ PartialFilterM,+ PandocFilterM,+ -- * Filter function → Wrapped filter+ ToPartialFilter (..),+ mkConcatedFilter,+ -- * Wrapped filter application/composition applyFilter,- -- * Filter composition- applyFiltersM, applyFilters,- -- * Filter conversion- getFilterM,+ applyFilterM,+ applyFiltersM,+ -- * Wrapped filter → filter function getFilter,- getConcatedFilterM, getConcatedFilter,- ToPartialFilter (..),- mkConcatedFilter,+ getFilterM,+ getConcatedFilterM,+ -- * Wrapped filter conversion toFilterM, ) where @@ -35,7 +47,8 @@ -- | @PartialFilterM m p@ is a wrapper for any monadic @p -> m p@ Pandoc -- filters acting on a subnode (e.g. 'Inline' or 'Block') of the 'Pandoc'--- abstract syntax tree.+-- abstract syntax tree. On this page, we will call it a "wrapped" filter to+-- distinguish it from filter functions @a -> m b@. -- -- * @m@: a monad. -- * @p@: the type of a subnode of 'Pandoc' (e.g. 'Inline').@@ -47,7 +60,8 @@ -- | @PartialFilter p@ is a wrapper for ordinary @p -> p@ Pandoc filters acting -- on a subnode (e.g. 'Inline' or 'Block') of the 'Pandoc' abstract syntax--- tree.+-- tree. On this page, we will call it a "wrapped" filter to distinguish it+-- from filter functions @a -> b@. -- -- * @p@: the type of a subnode of 'Pandoc' (e.g. 'Inline'). type PartialFilter = PartialFilterM Identity@@ -64,31 +78,39 @@ -- * @m@: a monad. type PandocFilterM m = PartialFilterM m Pandoc --- | Apply an ordinary filter to @p@, which returns @p@ directly.+-- | Apply a wrapped filter to @p@, which returns @p@ directly. applyFilter- :: PartialFilter p -- ^ A wrapped partial filter.+ :: PartialFilter p -- ^ A wrapped filter. -> p -- ^ 'Pandoc' AST node. -> p -- ^ Transformed node. applyFilter = (runIdentity .) . applyFilterM --- | It is mostly the same as 'applyFilterM' and should be used when you don't--- need to apply the filter immediately. The only difference is that it will--- perform an implicit conversion if the requested filter function is of a--- different type.+-- | It is mostly the same as 'applyFilterM', which converts a wrapped monadic+-- filter to a monadic filter function, but it should be used when you don't+-- need to apply the filter immediately. There is a slight difference in that+-- it will perform an implicit conversion if the requested filter function is+-- of a different type.+--+-- For example, it can be used to convert a wrapped monadic filter+-- @'PartialFilterM' 'IO' 'Inline'@ to monadic filter function @'Block' -> 'IO'+-- 'Block'@. getFilterM :: (Monad m, Walkable a b)- => PartialFilterM m a -- ^ A wrapped partial filter on @a@.- -> (b -> m b) -- ^ Unwrapped filter function that can be directly applied to @b@.+ => PartialFilterM m a -- ^ A wrapped filter on @a@.+ -> (b -> m b) -- ^ Filter function that can be directly applied to @b@. getFilterM = applyFilterM . mkFilter --- | It is mostly the same as 'applyFilter' and should be used when you don't--- need to apply the filter immediately. The only difference is that it will--- perform an implicit conversion if the requested filter function is of a--- different type.+-- | It is mostly the same as 'applyFilter', which converts a wrapped filter to+-- a filter function, but it should be used when you don't need to apply the+-- filter immediately. There is a slight difference in that it will perform an+-- implicit conversion if the requested filter function is of a different type.+--+-- For example, it can be used to convert a wrapped filter @'PartialFilter'+-- 'Inline'@ to filter function @'Block' -> 'Block'@. getFilter :: (Walkable a b) => PartialFilter a -- ^ A wrapped partial filter on @a@.- -> (b -> b) -- ^ Unwrapped filter function that can be directly applied to @b@.+ -> (b -> b) -- ^ Filter function that can be directly applied to @b@. getFilter = applyFilter . mkFilter -- | The 'Semigroup' instance of `PartialFilterM`. @f1 <> f2@ will apply @f1@@@ -103,11 +125,12 @@ -- | A helper typeclass used as a polymorphic constructor of 'PartialFilterM'. class ToPartialFilter m f p where -- | The actual constructor of 'PartialFilterM'. It takes an ordinary filter- -- function @a -> b@ and wraps it as a 'PartialFilterM'. It can also be used- -- to convert between different types of @'PartialFilterM' m@.+ -- function @a -> b@ and wraps it as a wrapped filter 'PartialFilterM'. It+ -- can also be used to convert between different types of @'PartialFilterM'+ -- m@. mkFilter- :: f -- ^ A partial filter function, usually @a -> a@ for some @'Walkable' a p@.- -> PartialFilterM m p -- ^ Wrapped partial Pandoc filter.+ :: f -- ^ A filter function, usually @a -> a@ for some @'Walkable' a p@.+ -> PartialFilterM m p -- ^ Wrapped Pandoc filter. instance (Monad m, Walkable a p) => ToPartialFilter m (a -> a) p where mkFilter = PartialFilterM . (return .) . walk@@ -126,55 +149,92 @@ instance (Monad m, Walkable a b) => ToPartialFilter m (PartialFilterM m a) b where mkFilter = mkFilter . applyFilterM --- | Construct a 'PartialFilterM' from a list of filter functions of the same--- type. The final filter is concatenated from left to right such that the--- first element in the list will be applied first and the last element will be--- applied at the end.+-- | Construct a wrapped filter 'PartialFilterM' from a list of filter+-- functions of the same type. The final filter is concatenated from left to+-- right such that the first element in the list will be applied first and the+-- last element will be applied at the end.+--+-- For example, it can be used to convert an list of filter functions+-- @['Inline' -> ['Inline']]@ to a wrapped filter @'PandocFilter'@. mkConcatedFilter :: (Monad m, ToPartialFilter m f p, Foldable t) => t f -- ^ A list of filter functions of the same type. -> PartialFilterM m p -- ^ Concatenated filter. mkConcatedFilter = foldMap mkFilter --- | Convert an ordinary 'PartialFilter' to the monadic version+-- | Convert an ordinary wrapped filter 'PartialFilter' to the monadic version -- 'PartialFilterM'.+--+-- For example, it can be used to convert an ordinary wrapped filter+-- @'PartialFilter' 'Inline'@ to monadic wrapped filter @'PartialFilterM' 'IO'+-- 'Inline'@. toFilterM :: (Monad m) => PartialFilter p -- ^ An ordinary filter. -> PartialFilterM m p -- ^ The monadic version. toFilterM = PartialFilterM . (return .) . applyFilter --- | Apply a list of monadic partial filters sequentially, from left to--- right, i.e. the first element in the list will be applied first and the--- last element will be applied at the end.+-- | Apply a list of monadic wrapped filters sequentially, from left to right,+-- i.e. the first element in the list will be applied first and the last+-- element will be applied at the end. applyFiltersM :: (Foldable t, Monad m)- => t (PartialFilterM m p) -- ^ A list of monadic partial filters.+ => t (PartialFilterM m p) -- ^ A list of monadic wrapped filters. -> p -- ^ 'Pandoc' AST node. -> m p -- ^ Transformed node. applyFiltersM = applyFilterM . fold --- | Apply a list of partial filters sequentially, from left to right, i.e.+-- | Apply a list of wrapped filters sequentially, from left to right, i.e. -- the first element in the list will be applied first and the last element -- will be applied at the end. applyFilters :: (Foldable t)- => t (PartialFilter p) -- ^ A list of partial filter.+ => t (PartialFilter p) -- ^ A list of wrapped filter. -> p -- ^ 'Pandoc' AST node. -> p -- ^ Transformed node. applyFilters = applyFilter . fold --- | An alias for 'applyFiltersM', used when the filter is not used--- immediately.+-- | It is mostly the same as 'applyFiltersM', which converts a list of wrapped+-- monadic filter to a monadic filter function, but it should be used when you+-- don't need to apply the filter immediately. There is a slight difference in+-- that it will perform an implicit conversion if the requested filter function+-- is of a different type.+--+-- For example, it can be used to convert a list of wrapped monadic filter+-- @['PartialFilterM' 'IO' 'Inline']@ to a filter function @'Block' -> 'IO'+-- 'Block'@. getConcatedFilterM- :: (Foldable t, Monad m)- => t (PartialFilterM m p) -- ^ A list of monadic partial filters.- -> (p -> m p) -- ^ Unwrapped monadic filter applicable to @p@ directly.-getConcatedFilterM = applyFiltersM+ :: (Foldable t, Monad m, Walkable a b)+ => t (PartialFilterM m a) -- ^ A list of monadic partial filters on @a@.+ -> (b -> m b) -- ^ Monadic filter function applicable to @b@ directly.+getConcatedFilterM = applyFilterM . mkConcatedFilter --- | An alias for 'applyFilters', used when the filter is not used immediately.+-- | It is mostly the same as 'applyFilters', which converts a list of wrapped+-- filter to a filter function, but it should be used when you don't need to+-- apply the filter immediately. There is a slight difference in that it will+-- perform an implicit conversion if the requested filter function is of a+-- different type.+--+-- For example, it can be used to convert a list of wrapped filter+-- @['PartialFilter' 'Inline']@ to a filter function @'Block' -> 'Block'@. getConcatedFilter- :: (Foldable t)- => t (PartialFilter p) -- ^ A list of partial filter.- -> (p -> p) -- ^ Unwrapped filter applicable to @p@ directly.-getConcatedFilter = applyFilters+ :: (Foldable t, Walkable a b)+ => t (PartialFilter a) -- ^ A list of wrapped filter acting on @a@+ -> (b -> b) -- ^ Filter function applicable to @b@ directly.+getConcatedFilter = applyFilter . mkConcatedFilter++-- | Conversion between monadic filter functions, e.g. from @'Inline' ->+-- 'IO' ['Inline']@ filter to @'Pandoc' -> 'IO' 'Pandoc'@ filter.+convertFilterM+ :: (Monad m, ToPartialFilter m f p)+ => f -- ^ A monadic filter function.+ -> (p -> m p) -- ^ Monadic filter function acting on @p@.+convertFilterM = applyFilterM . mkFilter++-- | Conversion between filter functions, e.g. from @'Inline' -> ['Inline']@+-- filter to @'Pandoc' -> 'Pandoc'@ filter.+convertFilter+ :: (ToPartialFilter Identity f p)+ => f -- ^ A filter function.+ -> (p -> p) -- ^ Filter function acting on @p@.+convertFilter = applyFilter . mkFilter
src/Text/Pandoc/Filter/Utils/AttrBuilder.hs view
@@ -9,7 +9,7 @@ setId, ) where -import Text.Pandoc.Utils+import Text.Pandoc.Utils.String import Data.Bifunctor (bimap, first, second) import Data.Text (Text)
src/Text/Pandoc/Utils.hs view
@@ -1,52 +1,13 @@-{-# LANGUAGE TypeFamilies #-}---- | Due to the switch from 'String' to 'Text' in pandoc-types 1.20, some--- legacy filters might not work in newer versions. This module contains some--- string conversion utility functions to make filters work in across different--- versions.+-- | This module exports all the utility functions provided by this package. module Text.Pandoc.Utils (- -- * Conversions- ToString (..),- ToText (..),- IsText (..),- -- * Reexport from Data.String- IsString (..),- ) where--import qualified Data.Text as T--import Data.String (IsString (..))-import Data.Text (Text)---- | A helper typeclass for converting 'String' and 'Text' to 'String'.-class IsString s => ToString s where- -- | Convert strings to 'String'.- toString :: s -> String--instance Char ~ c => ToString [c] where- toString = id--instance ToString Text where- toString = T.unpack---- | A helper typeclass for converting 'String' and 'Text' to 'Text'.-class IsString s => ToText s where- -- | Convert strings to 'Text'.- toText :: s -> Text--instance Char ~ c => ToText [c] where- toText = T.pack--instance ToText Text where- toText = id---- | A helper typeclass for converting 'Text' to either 'String' or 'Text'.-class IsText a where- -- | Convert from 'Text' to strings- fromText :: Text -> a--instance Char ~ c => IsText [c] where- fromText = T.unpack+ -- * Filter utils+ module Text.Pandoc.Filter.Utils,+ -- * Attribute builders+ module Text.Pandoc.Filter.Utils.AttrBuilder,+ -- * String conversions+ module Text.Pandoc.Utils.String+) where -instance IsText Text where- fromText = id+import Text.Pandoc.Filter.Utils+import Text.Pandoc.Filter.Utils.AttrBuilder+import Text.Pandoc.Utils.String
+ src/Text/Pandoc/Utils/String.hs view
@@ -0,0 +1,52 @@+{-# LANGUAGE TypeFamilies #-}++-- | Due to the switch from 'String' to 'Text' in pandoc-types 1.20, some+-- legacy filters might not work in newer versions. This module contains some+-- string conversion utility functions to make filters work in across different+-- versions.+module Text.Pandoc.Utils.String (+ -- * Conversions+ ToString (..),+ ToText (..),+ IsText (..),+ -- * Reexport from Data.String+ IsString (..),+ ) where++import qualified Data.Text as T++import Data.String (IsString (..))+import Data.Text (Text)++-- | A helper typeclass for converting 'String' and 'Text' to 'String'.+class IsString s => ToString s where+ -- | Convert strings to 'String'.+ toString :: s -> String++instance Char ~ c => ToString [c] where+ toString = id++instance ToString Text where+ toString = T.unpack++-- | A helper typeclass for converting 'String' and 'Text' to 'Text'.+class IsString s => ToText s where+ -- | Convert strings to 'Text'.+ toText :: s -> Text++instance Char ~ c => ToText [c] where+ toText = T.pack++instance ToText Text where+ toText = id++-- | A helper typeclass for converting 'Text' to either 'String' or 'Text'.+class IsText a where+ -- | Convert from 'Text' to strings+ fromText :: Text -> a++instance Char ~ c => IsText [c] where+ fromText = T.unpack++instance IsText Text where+ fromText = id
test/Spec.hs view
@@ -12,8 +12,7 @@ import Test.Tasty import Test.Tasty.Hspec import Text.Pandoc.Definition-import Text.Pandoc.Filter.Utils-import Text.Pandoc.Filter.Utils.AttrBuilder+import Text.Pandoc.Utils -- * Testing data @@ -118,6 +117,9 @@ beheadFilter :: PandocFilter beheadFilter = mkFilter behead +beheadPandoc :: Pandoc -> Pandoc+beheadPandoc = convertFilter behead+ delink :: Inline -> [Inline] delink (Link _ txt _) = txt delink x = [x]@@ -125,6 +127,9 @@ delinkFilter :: PandocFilter delinkFilter = mkFilter delink +delinkPandoc :: Pandoc -> Pandoc+delinkPandoc = convertFilter delink+ myFilter :: PandocFilter myFilter = beheadFilter <> delinkFilter @@ -238,6 +243,41 @@ bl `shouldBe` expectedInlinePartial s' `shouldBe` T.pack "abcd" + describe "convertFilter" $ do+ it "converts a -> a filter to Pandoc -> Pandoc filter" $ do+ convertFilter capFilterInline docPara `shouldBe` expectedInline+ convertFilter unParaFilterBlock docPara `shouldBe` expectedBlock++ it "converts a -> a filter to b -> b partial filter" $+ convertFilter capFilterInline blockPara `shouldBe` expectedInlinePartial++ it "converts a -> [a] filter to Pandoc -> Pandoc filter" $ do+ convertFilter dupFilterInline docPara `shouldBe` expectedInlineL+ convertFilter dupFilterBlock docPara `shouldBe` expectedBlockL++ it "converts a -> [a] filter to b -> b partial filter" $+ convertFilter dupFilterInline blockPara `shouldBe` expectedInlinePartialL++ it "converts a -> m a filter to Pandoc -> m Pandoc filter" $ do+ let (doc, s) = runWriter $ convertFilterM extractFilterInlineM docPara+ doc `shouldBe` expectedInline+ s `shouldBe` T.pack "abcd"++ it "converts a -> m a filter to b -> m b filter" $ do+ let (bl, s) = runWriter $ convertFilterM extractFilterInlineM blockPara+ bl `shouldBe` expectedInlinePartial+ s `shouldBe` T.pack "abcd"++ it "converts a -> m [a] filter to Pandoc -> m Pandoc filter" $ do+ let (doc, s) = runWriter $ convertFilterM extractFilterInlineML docPara+ doc `shouldBe` expectedInlineL+ s `shouldBe` T.pack "abcd"++ it "converts a -> m [a] filter to b -> m b filter" $ do+ let (bl, s) = runWriter $ convertFilterM extractFilterInlineML blockPara+ bl `shouldBe` expectedInlinePartialL+ s `shouldBe` T.pack "abcd"+ describe "getFilter" $ do it "converts PartialFilter a to a -> a" $ do let fInline = mkFilter capFilterInline :: PartialFilter Inline@@ -294,12 +334,10 @@ it "applys merge correctly" $ applyFilter merge compPara2 `shouldBe` expectedMerge - describe "applyFilters and monoid" $ do+ describe "applyFilters" $ do it "applys PartialFilter composition from left to right" $ do applyFilter (dup <> merge) compPara `shouldBe` expectedDupMerge applyFilter (merge <> dup) compPara `shouldBe` expectedMergeDup- applyFilters [dup, merge] compPara `shouldBe` expectedDupMerge- applyFilters [merge, dup] compPara `shouldBe` expectedMergeDup it "applys PartialFilterM composition from left to right" $ do let (doc, s) = runWriter $ applyFilterM (extract <> toFilterM dup) compPara@@ -310,12 +348,58 @@ doc' `shouldBe` expectedDup s' `shouldBe` T.pack "abcdabcd" + describe "monoid instance" $ do+ it "applys PartialFilter composition from left to right" $ do+ applyFilters [dup, merge] compPara `shouldBe` expectedDupMerge+ applyFilters [merge, dup] compPara `shouldBe` expectedMergeDup++ it "applys PartialFilterM composition from left to right" $ do+ let (doc, s) = runWriter $ applyFiltersM [extract, toFilterM dup] compPara+ doc `shouldBe` expectedDup+ s `shouldBe` T.pack "abcd"++ let (doc', s') = runWriter $ applyFiltersM [toFilterM dup, extract] compPara+ doc' `shouldBe` expectedDup+ s' `shouldBe` T.pack "abcdabcd"++ let dupInl = mkFilter dupFilterInline :: PartialFilter [Inline]+ mergeInl = mkFilter mergeFilterInline :: PartialFilter [Inline]+ extractInl = mkFilter extractFilter :: PartialFilterM (Writer Text) [Inline]++ describe "getConcatedFilter" $ do+ it "converts [PartialFilter a] to a -> a, applied from left to right" $ do+ getConcatedFilter [dupInl, mergeInl] [Str "abcd"] `shouldBe` [Str "abcdabcd"]+ getConcatedFilter [mergeInl, dupInl] [Str "abcd"] `shouldBe` [Str "abcd", Str "abcd"]++ it "converts [PartialFilterM m a] to a -> m a, applied from left to right" $ do+ let (doc, s) = runWriter $ getConcatedFilterM [extractInl, toFilterM dupInl] [Str "abcd"]+ doc `shouldBe` [Str "abcd", Str "abcd"]+ s `shouldBe` T.pack "abcd"++ let (doc', s') = runWriter $ getConcatedFilterM [toFilterM dupInl, extractInl] [Str "abcd"]+ doc' `shouldBe` [Str "abcd", Str "abcd"]+ s' `shouldBe` T.pack "abcdabcd"++ it "converts [PartialFilter a] to b -> b, applied from left to right" $ do+ getConcatedFilter [dupInl, mergeInl] compPara `shouldBe` expectedDupMerge+ getConcatedFilter [mergeInl, dupInl] compPara `shouldBe` expectedMergeDup++ it "converts [PartialFilterM m a] to b -> m b, applied from left to right" $ do+ let (doc, s) = runWriter $ getConcatedFilterM [extractInl, toFilterM dupInl] compPara+ doc `shouldBe` expectedDup+ s `shouldBe` T.pack "abcd"++ let (doc', s') = runWriter $ getConcatedFilterM [toFilterM dupInl, extractInl] compPara+ doc' `shouldBe` expectedDup+ s' `shouldBe` T.pack "abcdabcd"+ readmeSpec :: Spec readmeSpec = parallel $ describe "readme example" $ do it "processes filter examples correctly on AST level" $ do applyFilters [beheadFilter, delinkFilter] readmeDoc `shouldBe` expectedDoc applyFilter myFilter readmeDoc `shouldBe` expectedDoc+ (delinkPandoc . beheadPandoc) readmeDoc `shouldBe` expectedDoc it "processes filter examples correctly on Text level" $ do fromRight "" (mdToHtml readmeText) `shouldBe` expectedHtml