doctemplates 0.7.2 → 0.8
raw patch · 10 files changed
+160/−154 lines, 10 filesPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
- Text.DocTemplates.Internal: [varFilters] :: Variable -> [Filter]
- Text.DocTemplates.Internal: data Filter
- Text.DocTemplates.Internal: instance Data.Data.Data Text.DocTemplates.Internal.Filter
- Text.DocTemplates.Internal: instance GHC.Classes.Eq Text.DocTemplates.Internal.Filter
- Text.DocTemplates.Internal: instance GHC.Classes.Ord Text.DocTemplates.Internal.Filter
- Text.DocTemplates.Internal: instance GHC.Generics.Generic Text.DocTemplates.Internal.Filter
- Text.DocTemplates.Internal: instance GHC.Read.Read Text.DocTemplates.Internal.Filter
- Text.DocTemplates.Internal: instance GHC.Show.Show Text.DocTemplates.Internal.Filter
+ Text.DocTemplates.Internal: [varPipes] :: Variable -> [Pipe]
+ Text.DocTemplates.Internal: data Pipe
+ Text.DocTemplates.Internal: instance Data.Data.Data Text.DocTemplates.Internal.Pipe
+ Text.DocTemplates.Internal: instance GHC.Classes.Eq Text.DocTemplates.Internal.Pipe
+ Text.DocTemplates.Internal: instance GHC.Classes.Ord Text.DocTemplates.Internal.Pipe
+ Text.DocTemplates.Internal: instance GHC.Generics.Generic Text.DocTemplates.Internal.Pipe
+ Text.DocTemplates.Internal: instance GHC.Read.Read Text.DocTemplates.Internal.Pipe
+ Text.DocTemplates.Internal: instance GHC.Show.Show Text.DocTemplates.Internal.Pipe
- Text.DocTemplates.Internal: Block :: Alignment -> Int -> Border -> Filter
+ Text.DocTemplates.Internal: Block :: Alignment -> Int -> Border -> Pipe
- Text.DocTemplates.Internal: Chomp :: Filter
+ Text.DocTemplates.Internal: Chomp :: Pipe
- Text.DocTemplates.Internal: NoWrap :: Filter
+ Text.DocTemplates.Internal: NoWrap :: Pipe
- Text.DocTemplates.Internal: Partial :: [Filter] -> Template a -> Template a
+ Text.DocTemplates.Internal: Partial :: [Pipe] -> Template a -> Template a
- Text.DocTemplates.Internal: Reverse :: Filter
+ Text.DocTemplates.Internal: Reverse :: Pipe
- Text.DocTemplates.Internal: ToAlpha :: Filter
+ Text.DocTemplates.Internal: ToAlpha :: Pipe
- Text.DocTemplates.Internal: ToLength :: Filter
+ Text.DocTemplates.Internal: ToLength :: Pipe
- Text.DocTemplates.Internal: ToLowercase :: Filter
+ Text.DocTemplates.Internal: ToLowercase :: Pipe
- Text.DocTemplates.Internal: ToPairs :: Filter
+ Text.DocTemplates.Internal: ToPairs :: Pipe
- Text.DocTemplates.Internal: ToRoman :: Filter
+ Text.DocTemplates.Internal: ToRoman :: Pipe
- Text.DocTemplates.Internal: ToUppercase :: Filter
+ Text.DocTemplates.Internal: ToUppercase :: Pipe
- Text.DocTemplates.Internal: Variable :: [Text] -> [Filter] -> Variable
+ Text.DocTemplates.Internal: Variable :: [Text] -> [Pipe] -> Variable
Files
- README.md +8/−8
- changelog.md +6/−0
- doctemplates.cabal +2/−2
- src/Text/DocTemplates/Internal.hs +20/−20
- src/Text/DocTemplates/Parser.hs +10/−10
- test/filter-and-partial.test +0/−16
- test/filters.test +0/−91
- test/pipe-and-partial.test +16/−0
- test/pipes.test +91/−0
- test/test.hs +7/−7
README.md view
@@ -11,9 +11,9 @@ Control structures are provided to test whether a variable has a non-blank value and to iterate over the items of a list. Partials---that is,-subtemplates defined in different files---are supported. Filters+subtemplates defined in different files---are supported. Pipes can be used to transform the values of variables or partials.-The provided filters make it possible to do list enumeration and+The provided pipes make it possible to do list enumeration and tabular layout in templates. Templates are rendered to a doclayout `Doc` (which is polymorphic@@ -354,11 +354,11 @@ The `~` keyword has no effect when rendering to `Text` or `String`. -## Filters+## Pipes -A filter transforms the value of a variable or partial. Filters+A pipe transforms the value of a variable or partial. Pipes are specified using a slash (`/`) between the variable name (or-partial) and the filter name. Example:+partial) and the pipe name. Example: ``` $for(name)$@@ -372,7 +372,7 @@ $employee:name()/uppercase$ ``` -Filters may be chained:+Pipes may be chained: ``` $for(employees/pairs)$@@ -380,7 +380,7 @@ $endfor$ ``` -Some filters take parameters:+Some pipes take parameters: ``` |----------------------|------------|@@ -390,7 +390,7 @@ |----------------------|------------| ``` -Currently the following filters are predefined:+Currently the following pipes are predefined: - `pairs`: Converts a map or array to an array of maps, each with `key` and `value` fields. If the original
changelog.md view
@@ -1,5 +1,11 @@ # doctemplates +## 0.8++ * Change `Filter` data type to `Pipe`. Use the nomenclature of+ "pipe" instead of "filter" to avoid confusion in pandoc between+ two notions of filter. Otherwise everything works the same.+ ## 0.7.2 * Add `nowrap` filter.
doctemplates.cabal view
@@ -1,9 +1,9 @@ name: doctemplates-version: 0.7.2+version: 0.8 synopsis: Pandoc-style document templates description: This is the text templating system used by pandoc. It supports variable interpolation, iteration,- tests for non-blank values, filters, and partials.+ tests for non-blank values, pipes, and partials. Templates are rendered to doclayout Docs, and variable values may come from a variety of different sources, including aeson Values.
src/Text/DocTemplates/Internal.hs view
@@ -33,7 +33,7 @@ , TemplateTarget , Template(..) , Variable(..)- , Filter(..)+ , Pipe(..) , Alignment(..) , Border(..) ) where@@ -70,7 +70,7 @@ | Conditional Variable (Template a) (Template a) | Iterate Variable (Template a) (Template a) | Nested (Template a)- | Partial [Filter] (Template a)+ | Partial [Pipe] (Template a) | Literal (Doc a) | Concat (Template a) (Template a) | Empty@@ -86,7 +86,7 @@ mappend = (<>) mempty = Empty -data Filter =+data Pipe = ToPairs | ToUppercase | ToLowercase@@ -115,7 +115,7 @@ data Variable = Variable { varParts :: [Text]- , varFilters :: [Filter]+ , varPipes :: [Pipe] } deriving (Show, Read, Data, Typeable, Generic, Eq, Ord) @@ -294,17 +294,17 @@ mapText f val = runIdentity (traverse (return . fromText . f . toText) val) -applyFilter :: TemplateTarget a => Filter -> Val a -> Val a-applyFilter ToLength val = SimpleVal $ fromString . show $ len+applyPipe :: TemplateTarget a => Pipe -> Val a -> Val a+applyPipe ToLength val = SimpleVal $ fromString . show $ len where len = case val of SimpleVal d -> T.length . toText $ DL.render Nothing d MapVal (Context m) -> M.size m ListVal xs -> length xs NullVal -> 0-applyFilter ToUppercase val = mapText T.toUpper val-applyFilter ToLowercase val = mapText T.toLower val-applyFilter ToPairs val =+applyPipe ToUppercase val = mapText T.toUpper val+applyPipe ToLowercase val = mapText T.toLower val+applyPipe ToPairs val = case val of MapVal (Context m) -> ListVal $ map toPair $ M.toList m@@ -315,24 +315,24 @@ toPair (k, v) = MapVal $ Context $ M.fromList [ ("key", SimpleVal $ fromString . T.unpack $ k) , ("value", v) ]-applyFilter Reverse val =+applyPipe Reverse val = case val of ListVal xs -> ListVal (reverse xs) SimpleVal{} -> mapText T.reverse val _ -> val-applyFilter Chomp val = mapDoc DL.chomp val-applyFilter ToAlpha val = mapText toAlpha val+applyPipe Chomp val = mapDoc DL.chomp val+applyPipe ToAlpha val = mapText toAlpha val where toAlpha t = case T.decimal t of Right (y,"") -> fromString [chr (ord 'a' + (y `mod` 26) - 1)] _ -> t-applyFilter ToRoman val = mapText toRoman' val+applyPipe ToRoman val = mapText toRoman' val where toRoman' t = case T.decimal t of Right (y,"") -> maybe t id (toRoman y) _ -> t-applyFilter NoWrap val = mapDoc DL.nowrap val-applyFilter (Block align n border) val =+applyPipe NoWrap val = mapDoc DL.nowrap val+applyPipe (Block align n border) val = let constructor = case align of LeftAligned -> DL.lblock Centered -> DL.cblock@@ -371,8 +371,8 @@ | x == 0 = return "" | otherwise = Nothing -applyFilters :: TemplateTarget a => [Filter] -> Val a -> Val a-applyFilters fs x = foldr applyFilter x $ reverse fs+applyPipes :: TemplateTarget a => [Pipe] -> Val a -> Val a+applyPipes fs x = foldr applyPipe x $ reverse fs multiLookup :: TemplateTarget a => [Text] -> Val a -> Val a multiLookup [] x = x@@ -387,7 +387,7 @@ resolveVariable' :: TemplateTarget a => Variable -> Val a -> [Doc a] resolveVariable' v val =- case applyFilters (varFilters v) $ multiLookup (varParts v) val of+ case applyPipes (varPipes v) $ multiLookup (varParts v) val of ListVal xs -> concatMap (resolveVariable' mempty) xs SimpleVal d | DL.isEmpty d -> []@@ -405,7 +405,7 @@ => Variable -> Context a -> (Context a -> m (Doc a)) -> m [Doc a] withVariable v ctx f =- case applyFilters (varFilters v) $ multiLookup (varParts v) (MapVal ctx) of+ case applyPipes (varPipes v) $ multiLookup (varParts v) (MapVal ctx) of NullVal -> return mempty ListVal xs -> mapM (\iterval -> f $ Context $ M.insert "it" iterval $ unContext ctx) xs@@ -444,7 +444,7 @@ DL.nest n <$> renderTemp t ctx renderTemp (Partial fs t) ctx = do val' <- renderTemp t ctx- return $ case applyFilters fs (SimpleVal val') of+ return $ case applyPipes fs (SimpleVal val') of SimpleVal x -> x _ -> mempty renderTemp (Concat t1 t2) ctx =
src/Text/DocTemplates/Parser.hs view
@@ -349,7 +349,7 @@ P.setPosition oldPos return res' P.putState oldst- fs <- many pFilter+ fs <- many pPipe case mbvar of Just var -> return $ Iterate var (Partial fs t) separ Nothing -> return $ Partial fs t@@ -399,15 +399,15 @@ pVar = do first <- pIdentPart <|> pIt rest <- P.many (P.char '.' *> pIdentPart)- filters <- P.many pFilter- return $ Variable (first:rest) filters+ pipes <- P.many pPipe+ return $ Variable (first:rest) pipes -pFilter :: Monad m => Parser m Filter-pFilter = do+pPipe :: Monad m => Parser m Pipe+pPipe = do P.char '/'- filterName <- P.many1 P.letter+ pipeName <- P.many1 P.letter P.notFollowedBy P.letter- case filterName of+ case pipeName of "uppercase" -> return ToUppercase "lowercase" -> return ToLowercase "pairs" -> return ToPairs@@ -420,7 +420,7 @@ "left" -> Block LeftAligned <$> pBlockWidth <*> pBlockBorders "right" -> Block RightAligned <$> pBlockWidth <*> pBlockBorders "center" -> Block Centered <$> pBlockWidth <*> pBlockBorders- _ -> fail $ "Unknown filter " ++ filterName+ _ -> fail $ "Unknown pipe " ++ pipeName pBlockWidth :: Monad m => Parser m Int pBlockWidth = P.try (do@@ -428,8 +428,8 @@ ds <- P.many1 P.digit case T.decimal (T.pack ds) of Right (n,"") -> return n- _ -> fail "Expected integer parameter for filter") P.<?>- "integer parameter for filter"+ _ -> fail "Expected integer parameter for pipe") P.<?>+ "integer parameter for pipe" pBlockBorders :: Monad m => Parser m Border pBlockBorders = do
− test/filter-and-partial.test
@@ -1,16 +0,0 @@-{ "employee":- [ { "name": { "first": "John", "last": "Doe" } }- , { "name": { "first": "Omar", "last": "Smith" }- , "salary": "30000" }- , { "name": { "first": "Sara", "last": "Chen" }- , "salary": "60000" }- ]-}-.-$for(employee)$-$it:name()/uppercase$-$endfor$-.-(JOHN) DOE-(OMAR) SMITH-(SARA) CHEN
− test/filters.test
@@ -1,91 +0,0 @@-{ "foo": 1,- "bar": null,- "baz": ["a", "b"],- "bim": { "Zub": "Sim" },- "sup": [ { "biz": "qux" },- { "sax": 2 } ],- "items": [ "one with\na line break",- "two",- "three with\na line break" ],- "hasblanks": "hello\n\n",- "hasblanksmap": { "a": "hello\n\n",- "b": "there\n\n" },- "digits": [1, 5, 20]-}-.-$bar/length$-$baz/length$-$bim.Zub/length$-$bim/length$-$sup/length$--$baz/uppercase[, ]$--$for(baz)$-$it$-$it/uppercase$-$baz$-$baz/uppercase$-$endfor$--$for(bim/pairs)$-$it.key$: $it.value$-$bim.key$: $bim.value/lowercase$-$endfor$--$for(baz/pairs)$-$it.key/roman/uppercase/right 4$. $it.value$-$endfor$--$items/pairs/reverse:enum()$--($hasblanks/chomp$)--$for(hasblanksmap/chomp/pairs/uppercase)$-$it.key$ ($it.value$)-$endfor$--$digits/roman[ ]$--$for(bim/uppercase)$-$it.Zub$-$endfor$-.-0-2-3-1-2--A, B--a-A-a-A-b-B-b-B--Zub: Sim-Zub: sim-- I. a- II. b--C. three with- a line break-B. two-A. one with- a line break---(hello)--A (HELLO)-B (THERE)--i v xx--SIM
+ test/pipe-and-partial.test view
@@ -0,0 +1,16 @@+{ "employee":+ [ { "name": { "first": "John", "last": "Doe" } }+ , { "name": { "first": "Omar", "last": "Smith" }+ , "salary": "30000" }+ , { "name": { "first": "Sara", "last": "Chen" }+ , "salary": "60000" }+ ]+}+.+$for(employee)$+$it:name()/uppercase$+$endfor$+.+(JOHN) DOE+(OMAR) SMITH+(SARA) CHEN
+ test/pipes.test view
@@ -0,0 +1,91 @@+{ "foo": 1,+ "bar": null,+ "baz": ["a", "b"],+ "bim": { "Zub": "Sim" },+ "sup": [ { "biz": "qux" },+ { "sax": 2 } ],+ "items": [ "one with\na line break",+ "two",+ "three with\na line break" ],+ "hasblanks": "hello\n\n",+ "hasblanksmap": { "a": "hello\n\n",+ "b": "there\n\n" },+ "digits": [1, 5, 20]+}+.+$bar/length$+$baz/length$+$bim.Zub/length$+$bim/length$+$sup/length$++$baz/uppercase[, ]$++$for(baz)$+$it$+$it/uppercase$+$baz$+$baz/uppercase$+$endfor$++$for(bim/pairs)$+$it.key$: $it.value$+$bim.key$: $bim.value/lowercase$+$endfor$++$for(baz/pairs)$+$it.key/roman/uppercase/right 4$. $it.value$+$endfor$++$items/pairs/reverse:enum()$++($hasblanks/chomp$)++$for(hasblanksmap/chomp/pairs/uppercase)$+$it.key$ ($it.value$)+$endfor$++$digits/roman[ ]$++$for(bim/uppercase)$+$it.Zub$+$endfor$+.+0+2+3+1+2++A, B++a+A+a+A+b+B+b+B++Zub: Sim+Zub: sim++ I. a+ II. b++C. three with+ a line break+B. two+A. one with+ a line break+++(hello)++A (HELLO)+B (THERE)++i v xx++SIM
test/test.hs view
@@ -38,18 +38,18 @@ (res :: Either String (Template T.Text)) <- compileTemplate "foobar.txt" "$sep$" res @?= Left "\"foobar.txt\" (line 1, column 5):\nunexpected \"$\"\nexpecting letter or digit or \"()\""- , testCase "compile failure (unknown filter)" $ do+ , testCase "compile failure (unknown pipe)" $ do (res :: Either String (Template T.Text)) <- compileTemplate "foobar.txt" "$foo/nope$"- res @?= Left "\"foobar.txt\" (line 1, column 10):\nunexpected \"$\"\nexpecting letter, letter or digit or \"()\"\nUnknown filter nope"- , testCase "compile failure (missing parameter for filter)" $ do+ res @?= Left "\"foobar.txt\" (line 1, column 10):\nunexpected \"$\"\nexpecting letter, letter or digit or \"()\"\nUnknown pipe nope"+ , testCase "compile failure (missing parameter for pipe)" $ do (res :: Either String (Template T.Text)) <- compileTemplate "foobar.txt" "$foo/left$"- res @?= Left "\"foobar.txt\" (line 1, column 10):\nunexpected \"$\"\nexpecting letter, integer parameter for filter, letter or digit or \"()\""- , testCase "compile failure (unexpected parameter for filter)" $ do+ res @?= Left "\"foobar.txt\" (line 1, column 10):\nunexpected \"$\"\nexpecting letter, integer parameter for pipe, letter or digit or \"()\""+ , testCase "compile failure (unexpected parameter for pipe)" $ do (res :: Either String (Template T.Text)) <- compileTemplate "foobar.txt" "$foo/left a$"- res @?= Left "\"foobar.txt\" (line 1, column 11):\nunexpected \"a\"\nexpecting integer parameter for filter"+ res @?= Left "\"foobar.txt\" (line 1, column 11):\nunexpected \"a\"\nexpecting integer parameter for pipe" , testCase "compile failure (error in partial)" $ do (res :: Either String (Template T.Text)) <- compileTemplate "test/foobar.txt" "$bad()$"@@ -67,7 +67,7 @@ (renderTemplate t (object ["foo" .= ("42" :: T.Text)])) Left e -> T.pack e res @?= "not breakable and\nthis is\nbreakable\nok? 42"- , testCase "nowrap filter" $ do+ , testCase "nowrap pipe" $ do (templ :: Either String (Template T.Text)) <- compileTemplate "foo" "$foo/nowrap$\n$foo$" let res :: T.Text