hastache 0.3.3 → 0.4.1
raw patch · 4 files changed
+193/−16 lines, 4 filesPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
Files
- README.md +88/−0
- Text/Hastache.hs +47/−13
- hastache.cabal +2/−3
- tests/test.hs +56/−0
README.md view
@@ -11,6 +11,8 @@ Read [Mustache documentation](http://mustache.github.com/mustache.5.html) for template syntax. +See [Hastache hackage page](http://hackage.haskell.org/package/hastache).+ ### Examples #### Variables@@ -106,6 +108,92 @@ context = mkGenericContext $ Heroes ["Nameless","Long Sky","Flying Snow", "Broken Sword","Qin Shi Huang"]+```++List item by index++```haskell+main = mapM_ (\(template,context) ->+ hastacheStr defaultConfig (encodeStr template) context >>= LZ.putStrLn) + [(template1, mkStrContext context1),+ (template1, context2),+ (template2, context3)]++names = ["Nameless","Long Sky","Flying Snow","Broken Sword","Qin Shi Huang"]++template1 = concat [+ "{{heroes.1.name}}\n",+ "{{heroes.0.name}}\n"]++-- Context as function+context1 "heroes" = MuList $ map (mkStrContext . mkListContext) names+ where+ mkListContext name = \"name" -> MuVariable name+context1 _ = MuNothing++-- With Generics+data Hero = Hero { name :: String } deriving (Data, Typeable)+data Heroes = Heroes { heroes :: [Hero] } deriving (Data, Typeable)++context2 = mkGenericContext $ Heroes $ map Hero names++template2 = concat [+ "{{heroName.3}}\n",+ "{{heroName.2}}\n"]++data HeroesStr = HeroesStr { heroName :: [String] } deriving (Data, Typeable)++context3 = mkGenericContext $ HeroesStr names+```++```+Long Sky+Nameless++Long Sky+Nameless++Broken Sword+Flying Snow+```++#### Conditional evaluation++Boolean++```haskell+template = "{{#boolean}}true{{/boolean}}{{^boolean}}false{{/boolean}}"+context "boolean" = MuBool False+```+```+false+```++List++```haskell+template = "{{^messages}}No new messages{{/messages}}"+context "messages" = MuList []+```+```+No new messages+```++Number++```haskell+main = mapM_ (\ctx ->+ hastacheStr defaultConfig (encodeStr template) (mkStrContext ctx)+ >>= LZ.putStrLn) [context1,context2]++template = "{{#msg}}{{msg}}{{/msg}}{{^msg}}No{{/msg}} new messages."++context1 "msg" = MuVariable (100 :: Int)+context2 "msg" = MuVariable (0 :: Int)+```+```+100 new messages.+No new messages. ``` #### Functions
Text/Hastache.hs view
@@ -1,5 +1,5 @@-{-# LANGUAGE ExistentialQuantification, FlexibleInstances, - IncoherentInstances #-}+{-# LANGUAGE ExistentialQuantification, FlexibleInstances, IncoherentInstances,+ OverloadedStrings #-} -- Module: Text.Hastache -- Copyright: Sergey S Lymar (c) 2011 -- License: BSD3@@ -85,6 +85,7 @@ import Control.Monad.Trans (lift, liftIO, MonadIO) import Data.AEq ((~==)) import Data.ByteString hiding (map, foldl1)+import Data.ByteString.Char8 (readInt) import Data.Char (ord) import Data.Int import Data.IORef@@ -92,7 +93,7 @@ import Data.Monoid (mappend, mempty) import Data.Word import Prelude hiding (putStrLn, readFile, length, drop, tail, dropWhile, elem,- head, last, reverse, take, span)+ head, last, reverse, take, span, null) import System.Directory (doesFileExist) import System.FilePath (combine) @@ -243,9 +244,9 @@ muTemplateFileExt = Nothing } -defOTag = encodeStr "{{"-defCTag = encodeStr "}}"-unquoteCTag = encodeStr "}}}"+defOTag = "{{" :: ByteString+defCTag = "}}" :: ByteString+unquoteCTag = "}}}" :: ByteString findBlock :: ByteString @@ -269,14 +270,39 @@ toLBS :: ByteString -> LZ.ByteString toLBS v = LZ.fromChunks [v] ++readVar :: MonadIO m => [MuContext m] -> ByteString -> LZ.ByteString readVar [] _ = LZ.empty readVar (context:parentCtx) name = case context name of MuVariable a -> toLByteString a MuBool a -> show a ~> encodeStr ~> toLBS- MuNothing -> readVar parentCtx name+ MuNothing -> case tryFindArrayItem context name of+ Just (nctx,nn) -> readVar [nctx] nn+ _ -> readVar parentCtx name _ -> LZ.empty +tryFindArrayItem :: MonadIO m => + MuContext m+ -> ByteString + -> Maybe (MuContext m, ByteString)+tryFindArrayItem context name = do+ guard $ length idx > 1+ (idx,nxt) <- readInt $ tail idx+ guard $ idx >= 0+ guard $ (null nxt) || ((head nxt) == (ord8 '.'))+ case context nm of+ MuList l -> do+ guard $ idx < (List.length l)+ let ncxt = l !! idx+ if null nxt + then Just (ncxt, dotStr) -- {{some.0}}+ else Just (ncxt, tail nxt) -- {{some.0.field}}+ _ -> Nothing+ where+ (nm,idx) = breakSubstring dotStr name+ dotStr = "."+ findCloseSection :: ByteString -> ByteString @@ -287,11 +313,11 @@ guard (length after > 0) Just (before, drop (length close) after) where- close = foldl1 append [otag, encodeStr "/", name, ctag]+ close = foldl1 append [otag, "/", name, ctag] (before, after) = breakSubstring close str trimCharsTest :: Word8 -> Bool-trimCharsTest = (`elem` encodeStr " \t")+trimCharsTest = (`elem` " \t") trimAll :: ByteString -> ByteString trimAll str = span trimCharsTest str ~> snd ~> spanEnd trimCharsTest ~> fst@@ -312,7 +338,7 @@ processBlock :: MonadIO m => ByteString - -> [ByteString -> MuType m] + -> [MuContext m] -> ByteString -> ByteString -> MuConfig @@ -326,8 +352,8 @@ addResBS str return () -renderBlock:: MonadIO m =>- [ByteString -> MuType m] +renderBlock :: MonadIO m =>+ [MuContext m] -> Word8 -> ByteString -> ByteString @@ -358,8 +384,16 @@ then dropNL afterSection' else afterSection' tlInTag = tail inTag- readContext = map ($ tlInTag) contexts + readContext' = map ($ tlInTag) contexts ~> List.find (not . isMuNothing)+ readContextWithIdx = do+ Just (ctx,name) <- map (+ \c -> tryFindArrayItem c tlInTag) + contexts ~> List.find isJust+ Just $ ctx name+ readContext = case readContext' of+ Just a -> Just a+ Nothing -> readContextWithIdx processAndNext = do processBlock sectionContent contexts otag ctag conf next afterSection
hastache.cabal view
@@ -1,9 +1,9 @@ name: hastache-version: 0.3.3+version: 0.4.1 license: BSD3 license-file: LICENSE category: Text-copyright: Sergey S Lymar (c) 2011+copyright: Sergey S Lymar (c) 2011-2012 author: Sergey S Lymar <sergey.lymar@gmail.com> maintainer: Sergey S Lymar <sergey.lymar@gmail.com> stability: experimental@@ -45,4 +45,3 @@ source-repository head type: git location: http://github.com/lymar/hastache-
tests/test.hs view
@@ -303,6 +303,7 @@ \{{#someDataList}}\n\ \* {{.}} \n\ \{{/someDataList}}\n\+ \List item by index: {{someDataList.1}} \n\ \Obj list:\n\ \{{#someDataObjList}}\n\ \* {{intDataField1}} : {{intDataField2}} \n\@@ -335,6 +336,7 @@ \* 1 \n\ \* 2 \n\ \* 3 \n\+ \List item by index: 2 \n\ \Obj list:\n\ \* a : 1 \n\ \* b : 2 \n\@@ -411,6 +413,57 @@ \Nested variable : NESTED_TWO\n\ \" +-- Accessing array item by index+arrayItemsTest = do+ res <- hastacheStr defaultConfig (encodeStr template) + (mkStrContext context)+ assertEqualStr resCorrectness (decodeStrLBS res) testRes+ where+ template = "\+ \{{section.0.name}} {{section.1.name}} {{section.2.name}}\n\+ \{{#flags.0.val}}yes{{/flags.0.val}}\n\+ \{{^flags.1.val}}no{{/flags.0.val}}\n\+ \"+ context "section" = MuList $ map nameCtx ["Neo", "Morpheus", "Trinity"]+ context "flags" = MuList $ map flagCtx [True, False]+ context n = MuNothing+ nameCtx name = mkStrContext (\"name" -> MuVariable name)+ flagCtx val = mkStrContext (\"val" -> MuBool val)++ testRes = "\+ \Neo Morpheus Trinity\n\+ \yes\n\+ \no\n\+ \"++-- Accessing array item by index (generic version)+data ArrayItemTest_Item = ArrayItemTest_Item { + name :: String + } deriving (Data, Typeable) ++data ArrayItemTest_Container = ArrayItemTest_Container { + items :: [ArrayItemTest_Item],+ itemsStr :: [String]+ } deriving (Data, Typeable) ++arrayItemsTestGeneric = do+ res <- hastacheStr defaultConfig (encodeStr template) context+ assertEqualStr resCorrectness (decodeStrLBS res) testRes+ where+ template = "\+ \{{items.0.name}} {{items.2.name}}\n\+ \{{itemsStr.0}} {{itemsStr.1}}\n\+ \"+ context = mkGenericContext $ ArrayItemTest_Container {+ items = [ArrayItemTest_Item "Bob", ArrayItemTest_Item "Alice",+ ArrayItemTest_Item "Zoe"],+ itemsStr = ["Bob", "Alice", "Zoe"]+ }+ testRes = "\+ \Bob Zoe\n\+ \Bob Alice\n\+ \"+ tests = TestList [ TestLabel "Comments test" (TestCase commentsTest) ,TestLabel "Variables test" (TestCase variablesTest)@@ -424,6 +477,9 @@ ,TestLabel "Generic context test" (TestCase genericContextTest) ,TestLabel "Nested context test" (TestCase nestedContextTest) ,TestLabel "Nested generic context test" (TestCase nestedGenericContextTest)+ ,TestLabel "Accessing array item by index" (TestCase arrayItemsTest)+ ,TestLabel "Accessing array item by index (generic version)" + (TestCase arrayItemsTestGeneric) ] main = do