packages feed

hastache 0.4.2 → 0.5.0

raw patch · 5 files changed

+146/−96 lines, 5 filesdep +HUnitdep +hastachedep +transformersdep ~basedep ~mtlPVP ok

version bump matches the API change (PVP)

Dependencies added: HUnit, hastache, transformers

Dependency ranges changed: base, mtl

API changes (from Hackage documentation)

+ Text.Hastache: muTemplateRead :: MuConfig m -> FilePath -> m (Maybe ByteString)
+ Text.Hastache.Context: mkStrContextM :: Monad m => (String -> m (MuType m)) -> MuContext m
- Text.Hastache: MuConfig :: (ByteString -> ByteString) -> Maybe FilePath -> Maybe String -> MuConfig
+ Text.Hastache: MuConfig :: (ByteString -> ByteString) -> Maybe FilePath -> Maybe String -> (FilePath -> m (Maybe ByteString)) -> MuConfig m
- Text.Hastache: data MuConfig
+ Text.Hastache: data MuConfig m
- Text.Hastache: defaultConfig :: MuConfig
+ Text.Hastache: defaultConfig :: MonadIO m => MuConfig m
- Text.Hastache: hastacheFile :: MonadIO m => MuConfig -> FilePath -> MuContext m -> m ByteString
+ Text.Hastache: hastacheFile :: MonadIO m => MuConfig m -> FilePath -> MuContext m -> m ByteString
- Text.Hastache: hastacheFileBuilder :: MonadIO m => MuConfig -> FilePath -> MuContext m -> m Builder
+ Text.Hastache: hastacheFileBuilder :: MonadIO m => MuConfig m -> FilePath -> MuContext m -> m Builder
- Text.Hastache: hastacheStr :: MonadIO m => MuConfig -> ByteString -> MuContext m -> m ByteString
+ Text.Hastache: hastacheStr :: MonadIO m => MuConfig m -> ByteString -> MuContext m -> m ByteString
- Text.Hastache: hastacheStrBuilder :: MonadIO m => MuConfig -> ByteString -> MuContext m -> m Builder
+ Text.Hastache: hastacheStrBuilder :: MonadIO m => MuConfig m -> ByteString -> MuContext m -> m Builder
- Text.Hastache: muEscapeFunc :: MuConfig -> ByteString -> ByteString
+ Text.Hastache: muEscapeFunc :: MuConfig m -> ByteString -> ByteString
- Text.Hastache: muTemplateFileDir :: MuConfig -> Maybe FilePath
+ Text.Hastache: muTemplateFileDir :: MuConfig m -> Maybe FilePath
- Text.Hastache: muTemplateFileExt :: MuConfig -> Maybe String
+ Text.Hastache: muTemplateFileExt :: MuConfig m -> Maybe String
- Text.Hastache: type MuContext m = ByteString -> MuType m
+ Text.Hastache: type MuContext m = ByteString -> m (MuType m)

Files

README.md view
@@ -20,7 +20,7 @@ ```haskell import Text.Hastache  import Text.Hastache.Context -import qualified Data.ByteString.Lazy as LZ +import qualified Data.ByteString.Lazy.Char8 as LZ   main = hastacheStr defaultConfig (encodeStr template) (mkStrContext context)     >>= LZ.putStrLn@@ -215,7 +215,7 @@ {-# LANGUAGE FlexibleContexts #-} import Text.Hastache  import Text.Hastache.Context -import qualified Data.ByteString.Lazy as LZ +import qualified Data.ByteString.Lazy.Char8 as LZ  import Control.Monad.State   main = run >>= LZ.putStrLn
Text/Hastache.hs view
@@ -1,7 +1,7 @@ {-# LANGUAGE ExistentialQuantification, FlexibleInstances, IncoherentInstances,              OverloadedStrings #-} -- Module:      Text.Hastache--- Copyright:   Sergey S Lymar (c) 2011 +-- Copyright:   Sergey S Lymar (c) 2011-2013  -- License:     BSD3 -- Maintainer:  Sergey S Lymar <sergey.lymar@gmail.com> -- Stability:   experimental@@ -18,13 +18,13 @@ @ import Text.Hastache  import Text.Hastache.Context -import qualified Data.ByteString.Lazy as LZ +import qualified Data.ByteString.Lazy.Char8 as LZ   main = do      res <- hastacheStr defaultConfig (encodeStr template)           (mkStrContext context)      LZ.putStrLn res -    where +  where      template = \"Hello, {{name}}!\\n\\nYou have {{unread}} unread messages.\"      context \"name\" = MuVariable \"Haskell\"     context \"unread\" = MuVariable (100 :: Int)@@ -43,7 +43,7 @@ @ import Text.Hastache  import Text.Hastache.Context -import qualified Data.ByteString.Lazy as LZ +import qualified Data.ByteString.Lazy.Char8 as LZ  import Data.Data  import Data.Generics   @@ -56,7 +56,7 @@     res <- hastacheStr defaultConfig (encodeStr template)          (mkGenericContext inf)      LZ.putStrLn res -    where +  where      template = \"Hello, {{name}}!\\n\\nYou have {{unread}} unread messages.\"     inf = Info \"Haskell\" 100 @@@ -80,13 +80,15 @@     , decodeStrLBS     ) where  -import Control.Monad (guard, when)+import Control.Monad (guard, when, mplus, mzero, liftM ) import Control.Monad.Reader (ask, runReaderT, MonadReader, ReaderT) import Control.Monad.Trans (lift, liftIO, MonadIO)+import Control.Monad.Trans.Maybe (MaybeT(MaybeT), runMaybeT) import Data.AEq (AEq,(~==)) import Data.ByteString hiding (map, foldl1) import Data.ByteString.Char8 (readInt) import Data.Char (ord)+import Data.Functor ((<$>)) import Data.Int import Data.IORef import Data.Maybe (isJust)@@ -100,6 +102,7 @@ import qualified Blaze.ByteString.Builder as BSB import qualified Codec.Binary.UTF8.String as SU import qualified Data.ByteString.Lazy as LZ+import qualified Data.Foldable as F import qualified Data.List as List import qualified Data.Text as Text import qualified Data.Text.Encoding as TextEncoding@@ -112,9 +115,9 @@ infixl 9 ~>  -- | Data for Hastache variable-type MuContext m = -    ByteString  -- ^ Variable name-    -> MuType m -- ^ Value+type MuContext m =+    ByteString      -- ^ Variable name+    -> m (MuType m) -- ^ Value  class Show a => MuVar a where     -- | Convert to Lazy ByteString@@ -189,13 +192,16 @@     show (MuLambdaM _) = "MuLambdaM <..>"     show MuNothing = "MuNothing" -data MuConfig = MuConfig {+data MuConfig m = MuConfig {     muEscapeFunc        :: LZ.ByteString -> LZ.ByteString,          -- ^ Escape function ('htmlEscape', 'emptyEscape' etc.)     muTemplateFileDir   :: Maybe FilePath,         -- ^ Directory for search partial templates ({{> templateName}})-    muTemplateFileExt   :: Maybe String+    muTemplateFileExt   :: Maybe String,         -- ^ Partial template files extension+    muTemplateRead      :: FilePath -> m (Maybe ByteString)+        -- ^ Template retrieval function. 'Nothing' indicates that the+        --   template could not be found.     }  -- | Convert String to UTF-8 Bytestring@@ -242,13 +248,21 @@  {- | Default config: HTML escape function, current directory as       template directory, template file extension not specified -}-defaultConfig :: MuConfig -defaultConfig = MuConfig { +defaultConfig :: MonadIO m => MuConfig m+defaultConfig = MuConfig {     muEscapeFunc = htmlEscape,     muTemplateFileDir = Nothing,-    muTemplateFileExt = Nothing-    } +    muTemplateFileExt = Nothing,+    muTemplateRead = liftIO . defaultTemplateRead+    } +defaultTemplateRead :: FilePath -> IO (Maybe ByteString)+defaultTemplateRead fullFileName = do+    fe <- doesFileExist fullFileName+    if fe+        then Just <$> readFile fullFileName+        else return Nothing+ defOTag = "{{" :: ByteString defCTag = "}}" :: ByteString unquoteCTag = "}}}" :: ByteString@@ -275,35 +289,38 @@ 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 -> case tryFindArrayItem context name of+readVar :: MonadIO m => [MuContext m] -> ByteString -> m LZ.ByteString+readVar [] _ = return LZ.empty+readVar (context:parentCtx) name = do+    muType <- context name+    case muType of+        MuVariable a -> return $ toLByteString a+        MuBool a -> return $ show a ~> encodeStr ~> toLBS+        MuNothing -> do+          mb <- runMaybeT $ tryFindArrayItem context name+          case mb of             Just (nctx,nn) -> readVar [nctx] nn             _ -> readVar parentCtx name-        _ -> LZ.empty+        _ -> return LZ.empty  tryFindArrayItem :: MonadIO m =>         MuContext m-    -> ByteString -    -> Maybe (MuContext m, ByteString)+    -> ByteString+    -> MaybeT m (MuContext m, ByteString) tryFindArrayItem context name = do     guard $ length idx > 1-    (idx,nxt) <- readInt $ tail idx+    (idx,nxt) <- MaybeT $ return $ readInt $ tail idx     guard $ idx >= 0     guard $ (null nxt) || ((head nxt) == (ord8 '.'))-    case context nm of+    muType <- lift $ context nm+    case muType 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+            if null nxt+                then return (ncxt, dotStr) -- {{some.0}}+                else return (ncxt, tail nxt) -- {{some.0.field}}+        _ -> mzero     where     (nm,idx) = breakSubstring dotStr name     dotStr = "."@@ -346,7 +363,7 @@     -> [MuContext m]      -> ByteString      -> ByteString -    -> MuConfig +    -> MuConfig m     -> ReaderT (IORef BSB.Builder) m () processBlock str contexts otag ctag conf =      case findBlock str otag ctag of@@ -364,14 +381,14 @@     -> ByteString      -> ByteString     -> ByteString -    -> MuConfig +    -> MuConfig m     -> ReaderT (IORef BSB.Builder) m () renderBlock contexts symb inTag afterClose otag ctag conf     -- comment     | symb == ord8 '!' = next afterClose     -- unescape variable     | symb == ord8 '&' || (symb == ord8 '{' && otag == defOTag) = do-        readVar contexts (tail inTag ~> trimAll) ~> addResLZ+        addResLZ =<< lift (readVar contexts (tail inTag ~> trimAll))         next afterClose     -- section, inverted section     | symb == ord8 '#' || symb == ord8 '^' = @@ -389,22 +406,21 @@                             then dropNL afterSection'                             else afterSection'                     tlInTag = tail inTag-                    readContext' = map ($ tlInTag) contexts -                        ~> List.find (not . isMuNothing)+                    readContext' = MaybeT $ liftM (List.find (not . isMuNothing)) $+                                     mapM ($ tlInTag) contexts                     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 +                      (ctx,name) <- Prelude.foldr mplus mzero $+                                    map (\c -> tryFindArrayItem c tlInTag) contexts+                      lift $ ctx name+                    readContext = readContext' `mplus` readContextWithIdx+                    processAndNext = do                         processBlock sectionContent contexts otag ctag conf                         next afterSection-                in +                in do+                mbCtx <- lift $ runMaybeT readContext                 if symb == ord8 '#'-                    then case readContext of -- section+                    then+                      case mbCtx of -- section                         Just (MuList []) -> next afterSection                         Just (MuList b) -> do                             mapM_ (\c -> processBlock sectionContent@@ -422,7 +438,7 @@                             toLByteString res ~> addResLZ                             next afterSection                         _ -> next afterSection-                    else case readContext of -- inverted section+                    else case mbCtx of -- inverted section                         Just (MuList []) -> processAndNext                         Just (MuBool False) -> processAndNext                         Just (MuVariable a) -> if isEmpty a @@ -457,14 +473,12 @@                 Nothing -> fileName                 Just path -> combine path fileName         in do-            fe <- liftIO $ doesFileExist fullFileName-            when fe $ do-                cnt <- liftIO $ readFile fullFileName-                next cnt+            F.mapM_ next =<< lift (muTemplateRead conf fullFileName)             next (trim' afterClose)     -- variable     | otherwise = do-        readVar contexts (trimAll inTag) ~> muEscapeFunc conf ~> addResLZ+        addResLZ . muEscapeFunc conf =<<+          lift (readVar contexts $ trimAll inTag)         next afterClose     where     next t = processBlock t contexts otag ctag conf@@ -476,7 +490,7 @@  -- | Render Hastache template from ByteString hastacheStr :: (MonadIO m) => -       MuConfig         -- ^ Configuration+       MuConfig m       -- ^ Configuration     -> ByteString       -- ^ Template     -> MuContext m      -- ^ Context     -> m LZ.ByteString@@ -485,7 +499,7 @@  -- | Render Hastache template from file hastacheFile :: (MonadIO m) => -       MuConfig         -- ^ Configuration+       MuConfig m       -- ^ Configuration     -> FilePath         -- ^ Template file name     -> MuContext m      -- ^ Context     -> m LZ.ByteString@@ -494,7 +508,7 @@  -- | Render Hastache template from ByteString hastacheStrBuilder :: (MonadIO m) => -       MuConfig         -- ^ Configuration+       MuConfig m       -- ^ Configuration     -> ByteString       -- ^ Template     -> MuContext m      -- ^ Context     -> m BSB.Builder@@ -505,7 +519,7 @@  -- | Render Hastache template from file hastacheFileBuilder :: (MonadIO m) => -       MuConfig         -- ^ Configuration+       MuConfig m       -- ^ Configuration     -> FilePath         -- ^ Template file name     -> MuContext m      -- ^ Context     -> m BSB.Builder
Text/Hastache/Context.hs view
@@ -1,6 +1,6 @@ {-# LANGUAGE ScopedTypeVariables #-} -- Module:      Text.Hastache.Context--- Copyright:   Sergey S Lymar (c) 2011 +-- Copyright:   Sergey S Lymar (c) 2011-2013  -- License:     BSD3 -- Maintainer:  Sergey S Lymar <sergey.lymar@gmail.com> -- Stability:   experimental@@ -11,6 +11,7 @@ -} module Text.Hastache.Context (       mkStrContext+    , mkStrContextM     , mkGenericContext     ) where  @@ -32,8 +33,12 @@  -- | Make Hastache context from String -> MuType function mkStrContext :: Monad m => (String -> MuType m) -> MuContext m-mkStrContext f a = decodeStr a ~> f+mkStrContext f a = decodeStr a ~> f ~> return +-- | Make Hastache context from monadic String -> MuType function+mkStrContextM :: Monad m => (String -> m (MuType m)) -> MuContext m+mkStrContextM f a = decodeStr a ~> f+ {- |  Make Hastache context from Data.Data deriving type @@ -242,7 +247,7 @@     muLambdaMBSLBS :: (BS.ByteString -> m LBS.ByteString) -> TD m     muLambdaMBSLBS f = MuLambdaM f ~> TSimple -convertGenTempToContext :: TD t -> MuContext t+convertGenTempToContext :: Monad m => TD m -> MuContext m convertGenTempToContext v = mkMap "" Map.empty v ~> mkMapContext     where     mkMap name m (TSimple t) = Map.insert (encodeStr name) t m@@ -257,9 +262,9 @@         then concat [name, ".", newName]         else newName     foldTObj name m (fn, fv) = mkMap (mkName name fn) m fv-    -    mkMapContext m a = case Map.lookup a m of-        Nothing -> ++    mkMapContext m a = return $ case Map.lookup a m of+        Nothing ->             case a == dotBS of                 True ->                      case Map.lookup BS.empty m of
hastache.cabal view
@@ -1,9 +1,9 @@ name:            hastache-version:         0.4.2+version:         0.5.0 license:         BSD3 license-file:    LICENSE category:        Text-copyright:       Sergey S Lymar (c) 2011-2012+copyright:       Sergey S Lymar (c) 2011-2013 author:          Sergey S Lymar <sergey.lymar@gmail.com> maintainer:      Sergey S Lymar <sergey.lymar@gmail.com> stability:       experimental@@ -35,6 +35,7 @@     base == 4.*     ,bytestring     ,mtl+    ,transformers     ,directory     ,filepath     ,utf8-string@@ -47,3 +48,17 @@ source-repository head   type:     git   location: http://github.com/lymar/hastache++test-suite test-hastache+  type:           exitcode-stdio-1.0+  main-is:        test.hs+  hs-source-dirs: tests++  build-depends:+    hastache+   ,base == 4.*+   ,mtl+   ,HUnit+   ,text+   ,bytestring+   ,syb
tests/test.hs view
@@ -1,7 +1,8 @@ {-# LANGUAGE DeriveDataTypeable #-}-module Tests where+module Main where  import Control.Monad+import Control.Monad.Error import Control.Monad.Writer import Data.Char import Data.Data@@ -33,7 +34,7 @@  -- Variables variablesTest = do-    res <- hastacheStr defaultConfig (encodeStr template) +    res <- hastacheStr defaultConfig (encodeStr template)         (mkStrContext context)     assertEqualStr resCorrectness (decodeStrLBS res) testRes     where@@ -70,7 +71,7 @@  -- Show/hide sections showHideSectionsTest = do-    res <- hastacheStr defaultConfig (encodeStr template) +    res <- hastacheStr defaultConfig (encodeStr template)         (mkStrContext context)     assertEqualStr resCorrectness (decodeStrLBS res) testRes     where@@ -124,7 +125,7 @@  -- Render list listSectionTest = do-    res <- hastacheStr defaultConfig (encodeStr template) +    res <- hastacheStr defaultConfig (encodeStr template)         (mkStrContext context)     assertEqualStr resCorrectness (decodeStrLBS res) testRes     where@@ -138,7 +139,7 @@         \"     context "section" = MuList $ map nameCtx ["Neo", "Morpheus", "Trinity"]     nameCtx name = mkStrContext (\"name" -> MuVariable name)-    +     testRes = "\         \text 1\n\         \ * Neo \n\@@ -150,7 +151,7 @@  -- Show/hide block according to boolean variable boolSectionTest = do-    res <- hastacheStr defaultConfig (encodeStr template) +    res <- hastacheStr defaultConfig (encodeStr template)         (mkStrContext context)     assertEqualStr resCorrectness (decodeStrLBS res) testRes     where@@ -183,7 +184,7 @@  -- Transorm section lambdaSectionTest = do-    res <- hastacheStr defaultConfig (encodeStr template) +    res <- hastacheStr defaultConfig (encodeStr template)         (mkStrContext context)     assertEqualStr resCorrectness (decodeStrLBS res) testRes     where@@ -207,10 +208,8 @@     assertEqualStr "monad state correctness" (decodeStr writerState)         testMonad     where-    monadicFunction = do-        res <- hastacheStr defaultConfig (encodeStr template) +    monadicFunction = hastacheStr defaultConfig (encodeStr template)             (mkStrContext context)-        return res     template = "\         \[{{#mf}}abc{{/mf}}]\n\         \[{{#mf}}def{{/mf}}]\n\@@ -224,9 +223,24 @@         \"     testMonad = "abcdef" +-- Monadic context function+monadicContextTest = do+    r <- runErrorT $ hastacheStr defaultConfig (encodeStr template)+        (mkStrContextM context)+    let { res = case r of+        Left err  -> "error: " ++ err+        Right res -> decodeStrLBS res }+    assertEqualStr resCorrectness res testRes+    where+    template = "Hello, {{name}}! You have {{unread}} unread messages. {{some}}"+    context "name"   = return $ MuVariable "Haskell"+    context "unread" = return $ MuVariable (100 :: Int)+    context var      = throwError $ "{{" ++ var  ++ "}} not found!"+    testRes = "error: {{some}} not found!"+ -- Change delimiters setDelimiterTest = do-    res <- hastacheStr defaultConfig (encodeStr template) +    res <- hastacheStr defaultConfig (encodeStr template)         (mkStrContext context)     assertEqualStr resCorrectness (decodeStrLBS res) testRes     where@@ -251,7 +265,7 @@  -- Render external (partial) template file partialsTest = do-    res <- hastacheStr defaultConfig (encodeStr template) +    res <- hastacheStr defaultConfig (encodeStr template)         (mkStrContext context)     assertEqualStr resCorrectness (decodeStrLBS res) testRes     where@@ -350,7 +364,7 @@  -- Up-level context from nested block nestedContextTest = do-    res <- hastacheStr defaultConfig (encodeStr template) +    res <- hastacheStr defaultConfig (encodeStr template)         (mkStrContext context)     assertEqualStr resCorrectness (decodeStrLBS res) testRes     where@@ -362,7 +376,7 @@         \"     context "section" = MuList $ map elemCtx ["elem 1", "elem 2"]     context "top" = MuVariable "top"-    elemCtx vl = mkStrContext (\v -> case v of +    elemCtx vl = mkStrContext (\v -> case v of         "val" -> MuVariable vl         _ -> MuNothing         )@@ -415,7 +429,7 @@  -- Accessing array item by index arrayItemsTest = do-    res <- hastacheStr defaultConfig (encodeStr template) +    res <- hastacheStr defaultConfig (encodeStr template)         (mkStrContext context)     assertEqualStr resCorrectness (decodeStrLBS res) testRes     where@@ -465,20 +479,22 @@         \"  tests = TestList [-     TestLabel "Comments test" (TestCase commentsTest)-    ,TestLabel "Variables test" (TestCase variablesTest)-    ,TestLabel "Show/hide sections test" (TestCase showHideSectionsTest)-    ,TestLabel "List test" (TestCase listSectionTest)-    ,TestLabel "Bool test" (TestCase boolSectionTest)-    ,TestLabel "Lambda test" (TestCase lambdaSectionTest)-    ,TestLabel "LambdaM test" (TestCase lambdaMSectionTest)-    ,TestLabel "Set delimiter test" (TestCase setDelimiterTest)-    ,TestLabel "Partials test" (TestCase partialsTest)-    ,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)" +      TestLabel "Comments test" (TestCase commentsTest)+    , TestLabel "Variables test" (TestCase variablesTest)+    , TestLabel "Show/hide sections test" (TestCase showHideSectionsTest)+    , TestLabel "List test" (TestCase listSectionTest)+    , TestLabel "Bool test" (TestCase boolSectionTest)+    , TestLabel "Lambda test" (TestCase lambdaSectionTest)+    , TestLabel "LambdaM test" (TestCase lambdaMSectionTest)+    , TestLabel "Monadic context test" (TestCase monadicContextTest)+    , TestLabel "Set delimiter test" (TestCase setDelimiterTest)+    , TestLabel "Partials test" (TestCase partialsTest)+    , 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)     ]