packages feed

stache 0.1.8 → 0.2.0

raw patch · 10 files changed

+102/−44 lines, 10 filesdep ~directorydep ~stache

Dependency ranges changed: directory, stache

Files

CHANGELOG.md view
@@ -1,3 +1,12 @@+## Stache 0.2.0++* Breaking change: the `renderMustache` function will throw an exception+  when referenced key was not provided. This is a better behavior than+  silent interpolation of an empty string, because missing values are almost+  always a mistake and it's easy to provide empty strings explicitly anyway.++* Allowed `directory-1.3.0.0`.+ ## Stache 0.1.8  * Rename `specs` directory to `specification` as the previous name somehow
Text/Mustache/Compile.hs view
@@ -102,5 +102,5 @@ withException :: MonadThrow m   => Either (ParseError Char Dec) Template -- ^ Value to process   -> m Template        -- ^ The result-withException = either (throwM . MustacheException) return+withException = either (throwM . MustacheParserException) return {-# INLINE withException #-}
Text/Mustache/Render.hs view
@@ -18,13 +18,13 @@   ( renderMustache ) where +import Control.Exception (throw) import Control.Monad.Reader import Control.Monad.Writer.Lazy import Data.Aeson import Data.Foldable (asum) import Data.List (tails) import Data.List.NonEmpty (NonEmpty (..))-import Data.Maybe (fromMaybe) import Data.Text (Text) import Text.Megaparsec.Pos (Pos, unPos) import Text.Mustache.Type@@ -67,6 +67,11 @@  -- | Render a Mustache 'Template' using Aeson's 'Value' to get actual values -- for interpolation.+--+-- As of version 0.2.0, if referenced values are missing (which almost+-- always indicates some sort of mistake), 'MustacheRenderException' will be+-- thrown. The included 'Key' will indicate full path to missing value and+-- 'PName' will contain the name of active partial.  renderMustache :: Template -> Value -> TL.Text renderMustache t =@@ -182,10 +187,13 @@ lookupKey :: Key -> Render Value lookupKey (Key []) = NE.head <$> asks rcContext lookupKey k = do-  v <- asks rcContext-  p <- asks rcPrefix+  v     <- asks rcContext+  p     <- asks rcPrefix+  pname <- asks (templateActual . rcTemplate)   let f x = asum (simpleLookup False (x <> k) <$> v)-  (return . fromMaybe Null . asum) (fmap (f . Key) . reverse . tails $ unKey p)+  case asum (fmap (f . Key) . reverse . tails $ unKey p) of+    Nothing -> throw (MustacheRenderException pname (p <> k))+    Just  r -> return r  -- | Lookup a 'Value' by traversing another 'Value' using given 'Key' as -- “path”.
Text/Mustache/Type.hs view
@@ -15,11 +15,13 @@ {-# LANGUAGE DeriveDataTypeable         #-} {-# LANGUAGE DeriveGeneric              #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE OverloadedStrings          #-}  module Text.Mustache.Type   ( Template (..)   , Node (..)   , Key (..)+  , showKey   , PName (..)   , MustacheException (..) ) where@@ -41,7 +43,7 @@ -- all available templates (partials). -- -- 'Template' is a 'Semigroup'. This means that you can combine 'Template's--- (and their caches) using the ('<>') operator, the resulting 'Template'+-- (and their caches) using the @('<>')@ operator, the resulting 'Template' -- will have the same currently selected template as the left one. Union of -- caches is also left-biased. @@ -82,6 +84,15 @@  instance NFData Key +-- | Pretty-print a key, this is helpful, for example, if you want to+-- display an error message.+--+-- @since 0.2.0++showKey :: Key -> Text+showKey (Key []) = "<implicit>"+showKey (Key xs) = T.intercalate "." xs+ -- | Identifier for partials. Note that with the @OverloadedStrings@ -- extension you can use just string literals to create values of this type. @@ -93,14 +104,28 @@  instance NFData PName --- | Exception that is thrown when parsing of a template has failed.+-- | Exception that is thrown when parsing of a template has failed or+-- referenced values were not provided. -data MustacheException = MustacheException (ParseError Char Dec)+data MustacheException+  = MustacheParserException (ParseError Char Dec)+    -- ^ Template parser has failed. This contains the parse error.+    --+    -- /Before version 0.2.0 it was called 'MustacheException'./+  | MustacheRenderException PName Key+    -- ^ A referenced value was not provided. The exception provides info+    -- about partial in which the issue happened 'PName' and name of the+    -- missing key 'Key'.+    --+    -- @since 0.2.0   deriving (Eq, Show, Typeable, Generic)  #if MIN_VERSION_base(4,8,0) instance Exception MustacheException where-  displayException (MustacheException e) = parseErrorPretty e+  displayException (MustacheParserException e) = parseErrorPretty e+  displayException (MustacheRenderException pname key) =+    "Referenced value was not provided in partial \"" ++ T.unpack (unPName pname) +++    "\", key: " ++ T.unpack (showKey key) #else instance Exception MustacheException #endif
specification/interpolation.yml view
@@ -103,23 +103,23 @@    # Context Misses -  - name: Basic Context Miss Interpolation-    desc: Failed context lookups should default to empty strings.-    data: { }-    template: "I ({{cannot}}) be seen!"-    expected: "I () be seen!"+  # - name: Basic Context Miss Interpolation+  #   desc: Failed context lookups should default to empty strings.+  #   data: { }+  #   template: "I ({{cannot}}) be seen!"+  #   expected: "I () be seen!" -  - name: Triple Mustache Context Miss Interpolation-    desc: Failed context lookups should default to empty strings.-    data: { }-    template: "I ({{{cannot}}}) be seen!"-    expected: "I () be seen!"+  # - name: Triple Mustache Context Miss Interpolation+  #   desc: Failed context lookups should default to empty strings.+  #   data: { }+  #   template: "I ({{{cannot}}}) be seen!"+  #   expected: "I () be seen!" -  - name: Ampersand Context Miss Interpolation-    desc: Failed context lookups should default to empty strings.-    data: { }-    template: "I ({{&cannot}}) be seen!"-    expected: "I () be seen!"+  # - name: Ampersand Context Miss Interpolation+  #   desc: Failed context lookups should default to empty strings.+  #   data: { }+  #   template: "I ({{&cannot}}) be seen!"+  #   expected: "I () be seen!"    # Dotted Names 
specification/inverted.yml view
@@ -92,11 +92,11 @@     template: "| A {{^bool}}B {{^bool}}C{{/bool}} D{{/bool}} E |"     expected: "| A  E |" -  - name: Context Misses-    desc: Failed context lookups should be considered falsey.-    data: { }-    template: "[{{^missing}}Cannot find key 'missing'!{{/missing}}]"-    expected: "[Cannot find key 'missing'!]"+  # - name: Context Misses+  #   desc: Failed context lookups should be considered falsey.+  #   data: { }+  #   template: "[{{^missing}}Cannot find key 'missing'!{{/missing}}]"+  #   expected: "[Cannot find key 'missing'!]"    # Dotted Names 
specification/sections.yml view
@@ -132,11 +132,11 @@     template: "| A {{#bool}}B {{#bool}}C{{/bool}} D{{/bool}} E |"     expected: "| A  E |" -  - name: Context Misses-    desc: Failed context lookups should be considered falsey.-    data: { }-    template: "[{{#missing}}Found key 'missing'!{{/missing}}]"-    expected: "[]"+  # - name: Context Misses+  #   desc: Failed context lookups should be considered falsey.+  #   data: { }+  #   template: "[{{#missing}}Found key 'missing'!{{/missing}}]"+  #   expected: "[]"    # Implicit Iterators 
stache.cabal view
@@ -31,7 +31,7 @@ -- POSSIBILITY OF SUCH DAMAGE.  name:                 stache-version:              0.1.8+version:              0.2.0 cabal-version:        >= 1.10 license:              BSD3 license-file:         LICENSE.md@@ -64,7 +64,7 @@                     , bytestring       >= 0.10 && < 0.11                     , containers       >= 0.5  && < 0.6                     , deepseq          >= 1.4  && < 1.5-                    , directory        >= 1.2  && < 1.3+                    , directory        >= 1.2  && < 1.4                     , exceptions       >= 0.8  && < 0.9                     , filepath         >= 1.2  && < 1.5                     , megaparsec       >= 5.0  && < 6.0@@ -97,7 +97,7 @@                     , hspec            >= 2.0  && < 3.0                     , hspec-megaparsec >= 0.2  && < 0.4                     , megaparsec       >= 5.0  && < 6.0-                    , stache           >= 0.1.8+                    , stache           >= 0.2.0                     , text             >= 1.2  && < 1.3   other-modules:      Text.Mustache.Compile.THSpec                     , Text.Mustache.ParserSpec@@ -122,7 +122,7 @@                     , file-embed                     , hspec            >= 2.0  && < 3.0                     , megaparsec       >= 5.0  && < 6.0-                    , stache           >= 0.1.8+                    , stache           >= 0.2.0                     , text             >= 1.2  && < 1.3                     , yaml             >= 0.8  && < 0.9   if flag(dev)@@ -140,7 +140,7 @@                     , criterion        >= 0.6.2.1 && < 1.2                     , deepseq          >= 1.4  && < 1.5                     , megaparsec       >= 5.0  && < 6.0-                    , stache           >= 0.1.8+                    , stache           >= 0.2.0                     , text             >= 1.2  && < 1.3   if flag(dev)     ghc-options:      -O2 -Wall -Werror
tests/Text/Mustache/RenderSpec.hs view
@@ -6,6 +6,7 @@   , spec ) where +import Control.Exception (evaluate) import Data.Aeson (object, KeyValue (..), Value (..)) import Data.Text (Text) import Test.Hspec@@ -40,8 +41,13 @@   context "when rendering a section" $ do     let nodes = [Section (key "foo") [UnescapedVar (key "bar"), TextBlock "*"]]     context "when the key is not present" $-      it "renders nothing" $-        r nodes (object []) `shouldBe` ""+      it "throws the correct exception" $+        evaluate (r nodes (object [])) `shouldThrow`+          (== MustacheRenderException "test" (key "foo"))+    context "when the key is not present inside a section" $+      it "throws the correct exception" $+        evaluate (r nodes (object ["foo" .= ([1] :: [Int])])) `shouldThrow`+          (== MustacheRenderException "test" (Key ["foo","bar"]))     context "when the key is present" $ do       context "when the key is a “false” value" $ do         it "skips the Null value" $@@ -97,8 +103,9 @@   context "when rendering an inverted section" $ do     let nodes = [InvertedSection (key "foo") [TextBlock "Here!"]]     context "when the key is not present" $-      it "renders the inverse section" $-        r nodes (object []) `shouldBe` "Here!"+      it "throws the correct exception" $+        evaluate (r nodes (object [])) `shouldThrow`+          (== MustacheRenderException "test" (key "foo"))     context "when the key is present" $ do       context "when the key is a “false” value" $ do         it "renders with Null value" $
tests/Text/Mustache/TypeSpec.hs view
@@ -14,7 +14,7 @@ main = hspec spec  spec :: Spec-spec =+spec = do   describe "Template instances" $     context "the Semigroup instance" $ do       it "the resulting template inherits focus of the left one" $@@ -26,6 +26,15 @@             [ ("c", [TextBlock "foo"])             , ("d", [TextBlock "bar"])             , ("e", [TextBlock "baz"]) ]+  describe "showKey" $ do+    context "when the key has no elements in it" $+      it "is rendered correctly" $+        showKey (Key []) `shouldBe` "<implicit>"+    context "when the key has some elements" $+      it "is rendered correctly" $ do+        showKey (Key ["boo"]) `shouldBe` "boo"+        showKey (Key ["foo","bar"]) `shouldBe` "foo.bar"+        showKey (Key ["baz","baz","quux"]) `shouldBe` "baz.baz.quux"  templateA :: Template templateA = Template "a" $ M.fromList