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 +9/−0
- Text/Mustache/Compile.hs +1/−1
- Text/Mustache/Render.hs +12/−4
- Text/Mustache/Type.hs +29/−4
- specification/interpolation.yml +15/−15
- specification/inverted.yml +5/−5
- specification/sections.yml +5/−5
- stache.cabal +5/−5
- tests/Text/Mustache/RenderSpec.hs +11/−4
- tests/Text/Mustache/TypeSpec.hs +10/−1
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