packages feed

doctemplates 0.11.0.1 → 0.11.1

raw patch · 6 files changed

+106/−28 lines, 6 filesdep ~containersdep ~doclayoutPVP: major bump suggested

API removals or changes: PVP suggests a major version bump

Dependency ranges changed: containers, doclayout

API changes (from Hackage documentation)

+ Text.DocTemplates: getVariables :: Template a -> [Text]
+ Text.DocTemplates.Internal: getVariables :: Template a -> [Text]
- Text.DocTemplates: class Monad m => TemplateMonad m
+ Text.DocTemplates: class Monad m => TemplateMonad (m :: Type -> Type)
- Text.DocTemplates: data () => Doc a
+ Text.DocTemplates: data Doc a
- Text.DocTemplates.Internal: class Monad m => TemplateMonad m
+ Text.DocTemplates.Internal: class Monad m => TemplateMonad (m :: Type -> Type)

Files

README.md view
@@ -108,7 +108,7 @@   the assumption is that the calling program will escape   the strings appropriately for the output format.) - If the value of the variable is a boolean value, it-  will be rendered as `true` if true, or as empty if false.+  will be rendered as `true` if true, or as `false` if false. - If the value is a list, the values will be concatenated. - If the value is a map, the string `true` will be rendered. - Every other value will be rendered as the empty string.
changelog.md view
@@ -1,12 +1,25 @@ # doctemplates -# 0.11.0.1+## 0.11.1 +  * Add `getVariables`, returning free variables of a template [API change].+    Returns variable names in order of first occurrence, without+    duplicates, excluding variables bound inside for loops (the loop+    variable, fields underneath it, and the anaphoric variable `it`).++  * Fix off-by-one error in `alpha` pipe.++  * Fix `roman` pipe for numbers >= 4000.++  * Fix `reverse`, `alpha`, `roman` pipes on multi-chunk Docs.++## 0.11.0.1+   * Bump version bounds for doclayout.    * Fix typos. -# 0.11+## 0.11    * Remove HsYAML depenedency. 
doctemplates.cabal view
@@ -1,5 +1,5 @@ name:                doctemplates-version:             0.11.0.1+version:             0.11.1 synopsis:            Pandoc-style document templates description:         This is the text templating system used by pandoc.                      It supports variable interpolation, iteration,@@ -15,13 +15,12 @@ copyright:           2016-19 John MacFarlane category:            Text build-type:          Simple--- extra-source-files:-data-files:          README.md+extra-doc-files:     README.md                      changelog.md extra-source-files:  test/*.test                      test/*.txt                      test/*.tex-cabal-version:       >=1.10+cabal-version:       2.0  library   hs-source-dirs:      src@@ -33,8 +32,8 @@                        text-conversions,                        aeson,                        text,-                       doclayout >= 0.4 && < 0.6,-                       containers,+                       doclayout >= 0.4 && < 0.7,+                       containers >= 0.6.0.1,                        vector,                        filepath,                        parsec,@@ -51,7 +50,7 @@   main-is:             test.hs   build-depends:       base,                        doctemplates,-                       doclayout >= 0.4 && < 0.6,+                       doclayout >= 0.4 && < 0.7,                        containers,                        aeson,                        Glob,@@ -70,7 +69,7 @@   Main-Is:         bench.hs   Hs-Source-Dirs:  bench   Build-Depends:   doctemplates,-                   doclayout >= 0.4 && < 0.6,+                   doclayout >= 0.4 && < 0.7,                    base >= 4.8 && < 5,                    criterion >= 1.0,                    filepath,
src/Text/DocTemplates.hs view
@@ -105,7 +105,7 @@     calling program will escape the strings appropriately for the output     format.) -   If the value of the variable is a boolean value, it will be rendered-    as @true@ if true, or as empty if false.+    as @true@ if true, or as @false@ if false. -   If the value is a list, the values will be concatenated. -   If the value is a map, the string @true@ will be rendered. -   Every other value will be rendered as the empty string.@@ -405,6 +405,7 @@ -}  module Text.DocTemplates ( renderTemplate+                         , getVariables                          , compileTemplate                          , compileTemplateFile                          , applyTemplate@@ -424,7 +425,7 @@ import Text.DocTemplates.Parser (compileTemplate) import Text.DocTemplates.Internal ( TemplateMonad(..), Context(..),             Val(..), ToContext(..), FromContext(..), TemplateTarget,-            Template, renderTemplate )+            Template, renderTemplate, getVariables )  -- | Compile a template from a file.  IO errors will be -- raised as exceptions; template parsing errors result in
src/Text/DocTemplates/Internal.hs view
@@ -22,6 +22,7 @@  module Text.DocTemplates.Internal       ( renderTemplate+      , getVariables       , TemplateMonad(..)       , Context(..)       , Val(..)@@ -40,7 +41,6 @@ import Control.Monad.Identity import qualified Control.Monad.State.Strict as S import Data.Char (chr, ord)-import Data.Maybe (fromMaybe) import qualified Data.Text.Read as T import qualified Data.Text as T import qualified Data.Text.IO as TIO@@ -52,9 +52,10 @@ import GHC.Generics (Generic) import Data.Text (Text) import qualified Data.Map as M+import Data.Containers.ListUtils (nubOrd) import qualified Data.Vector as V import Data.Scientific (floatingOrInteger)-import Data.List (intersperse)+import Data.List (intersperse, isPrefixOf) #if MIN_VERSION_base(4,11,0) #else import Data.Semigroup@@ -252,6 +253,11 @@     BoolVal b          -> BoolVal b     NullVal            -> NullVal +-- | The full rendered text of a 'Doc', regardless of how it is+-- divided into chunks.+renderedText :: TemplateTarget a => Doc a -> Text+renderedText = toText . DL.render Nothing+ mapText :: TemplateTarget a => (Text -> Text) -> Val a -> Val a mapText f val =   runIdentity (traverse (return . fromText . f . toText) val)@@ -297,19 +303,22 @@ applyPipe Reverse val =   case val of     ListVal xs  -> ListVal (reverse xs)-    SimpleVal{} -> mapText T.reverse val+    SimpleVal d -> SimpleVal $ DL.literal . fromText . T.reverse $+                     renderedText d     _           -> 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-applyPipe ToRoman val = mapText toRoman' val-  where toRoman' t =-         case T.decimal t of-           Right (y,"") -> fromMaybe t (toRoman y)-           _            -> t+applyPipe ToAlpha val = mapDoc toAlpha val+  where toAlpha d =+          case T.decimal (renderedText d) of+            Right (y,"")+              | y > (0 :: Int) -> fromString+                                    [chr (ord 'a' + ((y - 1) `mod` 26))]+            _            -> d+applyPipe ToRoman val = mapDoc toRoman' val+  where toRoman' d =+         case T.decimal (renderedText d) of+           Right (y,"") -> maybe d (DL.literal . fromText) (toRoman y)+           _            -> d applyPipe NoWrap val = mapDoc DL.nowrap val applyPipe (Block align n border) val =   let constructor = case align of@@ -333,8 +342,8 @@ -- | Convert number 0 < x < 4000 to lowercase roman numeral. toRoman :: Int -> Maybe Text toRoman x-  | x >= 1000-  , x < 4000  = ("m" <>) <$> toRoman (x - 1000)+  | x >= 4000 = Nothing+  | x >= 1000 = ("m" <>) <$> toRoman (x - 1000)   | x >= 900  = ("cm" <>) <$> toRoman (x - 900)   | x >= 500  = ("d" <>) <$> toRoman (x - 500)   | x >= 400  = ("cd" <>) <$> toRoman (x - 400)@@ -424,6 +433,28 @@ renderTemplate :: (TemplateTarget a, ToContext a b)                => Template a -> b -> Doc a renderTemplate t x = S.evalState (renderTemp t (toContext x)) 0++-- | Retrieve the names of all free variables used in a template,+-- in the order in which they first occur, without duplicates.+-- The parts of a multipart variable (@foo.bar@) are separated+-- by periods.  Variables bound inside a @for@ loop (the loop+-- variable, fields underneath it, and the anaphoric variable+-- @it@) are not included.+getVariables :: Template a -> [Text]+getVariables = nubOrd . map (T.intercalate ".") . go+ where+  go (Interpolate v)       = [varParts v]+  go (Conditional v t1 t2) = varParts v : go t1 <> go t2+  go (Iterate v t1 t2)     = varParts v :+                             filter (not . boundBy v) (go t1) <> go t2+  go (Nested t)            = go t+  go (Partial _ t)         = go t+  go (Literal _)           = []+  go (Concat t1 t2)        = go t1 <> go t2+  go Empty                 = []+  -- inside the body of @for(v)@, variables under v are rebound+  -- to the current list item, and "it" refers to the item itself+  boundBy v parts = varParts v `isPrefixOf` parts || take 1 parts == ["it"]  updateColumn :: TemplateTarget a => Doc a -> RenderState (Doc a) updateColumn x = do
test/test.hs view
@@ -80,6 +80,40 @@                        :: Val T.Text) mempty))                   Left e  -> T.pack e       res @?= "hello this is a test of the wrapping\nhello this\nis a test\nof the\nwrapping"+  , testCase "alpha pipe" $ do+      (templ :: Either String (Template T.Text)) <-+        compileTemplate "foo" "$one/alpha$ $twentysix/alpha$ $twentyseven/alpha$ $zero/alpha$"+      let res :: T.Text+          res = case templ of+                  Right t -> render Nothing+                   (renderTemplate t (object [ "one" .= (1 :: Int)+                                             , "twentysix" .= (26 :: Int)+                                             , "twentyseven" .= (27 :: Int)+                                             , "zero" .= (0 :: Int) ]))+                  Left e  -> T.pack e+      res @?= "a z a 0"+  , testCase "getVariables" $ do+      (res :: Either String (Template T.Text)) <-+        compileTemplate "" "$b$$a$$if(foo.bar)$$b$$else$$baz$$endif$"+      fmap getVariables res @?= Right ["b", "a", "foo.bar", "baz"]+  , testCase "getVariables excludes loop-bound variables" $ do+      (res :: Either String (Template T.Text)) <-+        compileTemplate ""+          "$for(employee)$$employee.name$: $it.salary$ $company$$sep$$separator$$endfor$"+      fmap getVariables res @?= Right ["employee", "company", "separator"]+  , testCase "getVariables excludes it in bracketed loop" $ do+      (res :: Either String (Template T.Text)) <-+        compileTemplate "" "$items[, ]$"+      fmap getVariables res @?= Right ["items"]+  , testCase "getVariables with nested loops" $ do+      (res :: Either String (Template T.Text)) <-+        compileTemplate ""+          "$for(a)$$for(a.b)$$it$$a.c$$x$$endfor$$endfor$"+      fmap getVariables res @?= Right ["a", "x"]+  , testCase "getVariables includes it outside of loops" $ do+      (res :: Either String (Template T.Text)) <-+        compileTemplate "" "$it$"+      fmap getVariables res @?= Right ["it"]   ]  {- The test "golden" files are structured as follows: