packages feed

heist 0.10.2.1 → 0.11.0

raw patch · 12 files changed

+274/−47 lines, 12 filesdep ~hashablePVP ok

version bump matches the API change (PVP)

Dependency ranges changed: hashable

API changes (from Hackage documentation)

- Heist.Compiled: compileNode :: Monad n => Node -> Splice n
- Heist.Compiled: runSplice :: Monad n => Node -> HeistState n -> Splice n -> IO [Chunk n]
+ Heist: compiledSpliceNames :: HeistState m -> [Text]
+ Heist.Compiled: applySnd :: a -> [(d, a -> b)] -> [(d, b)]
+ Heist.Compiled: callTemplate :: Monad n => ByteString -> HeistT n IO (DList (Chunk n))
+ Heist.Compiled: defer :: Monad n => (Promise a -> Splice n) -> RuntimeSplice n a -> Splice n
+ Heist.Compiled: deferMany :: Monad n => (Promise a -> Splice n) -> RuntimeSplice n [a] -> Splice n
+ Heist.Compiled: manyWithSplices :: Monad n => Splice n -> [(Text, Promise a -> Splice n)] -> n [a] -> Splice n
+ Heist.Compiled: mapInputPromise :: Monad m => (a -> b) -> (Promise b -> Splice m) -> Promise a -> Splice m
+ Heist.Compiled: mapSnd :: (b -> c) -> [(d, b)] -> [(d, c)]
+ Heist.Compiled: nodeSplice :: (a -> [Node]) -> a -> Builder
+ Heist.Compiled: nodeSplices :: [(Text, a -> [Node])] -> [(Text, a -> Builder)]
+ Heist.Compiled: pureSplice :: Monad m => (a -> Builder) -> Promise a -> Splice m
+ Heist.Compiled: pureSplices :: Monad m => [(d, a -> Builder)] -> [(d, Promise a -> Splice m)]
+ Heist.Compiled: runChildren :: Monad n => Splice n
+ Heist.Compiled: textSplice :: (a -> Text) -> a -> Builder
+ Heist.Compiled: textSplices :: [(Text, a -> Text)] -> [(Text, a -> Builder)]
+ Heist.Compiled: withLocalSplices :: [(Text, Splice n)] -> [(Text, AttrSplice n)] -> HeistT n IO a -> HeistT n IO a
+ Heist.Compiled: withPureSplices :: Monad n => Splice n -> [(Text, a -> Builder)] -> n a -> Splice n
+ Heist.Compiled: withSplices :: Monad n => Splice n -> [(Text, Promise a -> Splice n)] -> n a -> Splice n
+ Heist.Splices: ifCSplice :: Monad m => (t -> Bool) -> Promise t -> Splice m
+ Heist.Splices: ifISplice :: Monad m => Bool -> Splice m
- Heist: type AttrSplice m = Text -> m [(Text, Text)]
+ Heist: type AttrSplice m = Text -> RuntimeSplice m [(Text, Text)]
- Heist.Compiled: codeGen :: Monad m => [Chunk m] -> RuntimeSplice m Builder
+ Heist.Compiled: codeGen :: Monad m => DList (Chunk m) -> RuntimeSplice m Builder
- Heist.Compiled: mapPromises :: Monad n => (Promise a -> HeistT n IO (RuntimeSplice n Builder)) -> n [a] -> Splice n
+ Heist.Compiled: mapPromises :: Monad n => (Promise a -> HeistT n IO (RuntimeSplice n Builder)) -> RuntimeSplice n [a] -> Splice n
- Heist.Interpreted: textSplice :: Monad n => Text -> Splice n
+ Heist.Interpreted: textSplice :: Monad m => Text -> HeistT n m Template

Files

heist.cabal view
@@ -1,5 +1,5 @@ name:           heist-version:        0.10.2.1+version:        0.11.0 synopsis:       An Haskell template system supporting both HTML5 and XML. description:     Heist is a powerful template system that supports both HTML5 and XML.@@ -149,7 +149,7 @@     dlist                      >= 0.5     && < 0.6,     errors                     >= 1.3     && < 1.4,     filepath                   >= 1.3     && < 1.4,-    hashable                   >= 1.1     && < 1.2,+    hashable                   >= 1.1     && < 1.3,     mtl                        >= 2.0     && < 2.2,     process                    >= 1.1     && < 1.2,     random                     >= 1.0.1.0 && < 1.1,
src/Heist.hs view
@@ -37,6 +37,7 @@   , compiledTemplateNames   , hasTemplate   , spliceNames+  , compiledSpliceNames   , HeistT   , evalHeistT   , getParamNode
src/Heist/Common.hs view
@@ -280,3 +280,12 @@     enc X.UTF16LE = "utf-16"  +------------------------------------------------------------------------------+-- | Binds a set of new splice declarations within a 'HeistState'.+bindAttributeSplices :: [(T.Text, AttrSplice n)] -- ^ splices to bind+                     -> HeistState n             -- ^ start state+                     -> HeistState n+bindAttributeSplices ss hs =+    hs { _attrSpliceMap = Map.union (Map.fromList ss) (_attrSpliceMap hs) }++
src/Heist/Compiled.hs view
@@ -17,6 +17,26 @@   -- * High level compiled splice API     Splice   , renderTemplate+  , codeGen+  , runChildren++  -- * Functions for manipulating lists of compiled splices+  , mapSnd+  , applySnd+  , textSplices+  , nodeSplices+  , pureSplices+  , textSplice+  , nodeSplice+  , pureSplice+  , mapInputPromise+  , defer+  , deferMany+  , withSplices+  , manyWithSplices+  , withPureSplices++  -- * Old compiled splice API   , mapPromises   , promiseChildren   , promiseChildrenWith@@ -33,23 +53,20 @@   , yieldRuntimeText   , yieldLater   , addSplices+  , withLocalSplices    -- * Lower level promise functions   , Promise   , newEmptyPromise--  -- * RuntimeSplice functions   , getPromise   , putPromise   , adjustPromise-  , codeGen    -- * Running nodes and splices   , runNodeList   , runNode-  , compileNode   , runAttributes-  , runSplice+  , callTemplate    ) where 
src/Heist/Compiled/Internal.hs view
@@ -8,8 +8,11 @@  module Heist.Compiled.Internal where ++------------------------------------------------------------------------------ import           Blaze.ByteString.Builder import           Control.Arrow+import           Control.Monad import           Control.Monad.RWS.Strict import           Control.Monad.State.Strict import qualified Data.Attoparsec.Text            as AP@@ -25,10 +28,12 @@ import qualified Data.Vector                     as V import           Prelude                         hiding (catch) import qualified Text.XmlHtml                    as X-+------------------------------------------------------------------------------ import           Heist.Common import           Heist.Types+------------------------------------------------------------------------------ + ------------------------------------------------------------------------------ -- | A compiled Splice is a HeistT computation that returns a @DList -- (Chunk m)@.@@ -44,6 +49,16 @@   ------------------------------------------------------------------------------+-- | Runs the parameter node's children and returns the resulting compiled+-- chunks.  By itself this function is a simple passthrough splice that makes+-- the spliced node disappear.  In combination with locally bound splices,+-- this function makes it easier to pass the desired view into your splices.+runChildren :: Monad n => Splice n+runChildren = runNodeList . X.childNodes =<< getParamNode+{-# INLINE runChildren #-}+++------------------------------------------------------------------------------ -- | Takes a promise function and a runtime action returning a list of items -- that fit in the promise and returns a Splice that executes the promise -- function for each item and concatenates the results.@@ -55,14 +70,14 @@             => (Promise a -> HeistT n IO (RuntimeSplice n Builder))             -- ^ Use 'promiseChildrenWith' or a variant to create this             -- function.-            -> n [a]+            -> RuntimeSplice n [a]             -- ^ Runtime computation returning a list of items             -> Splice n mapPromises f getList = do     singlePromise <- newEmptyPromise     runSingle <- f singlePromise     return $ yieldRuntime $ do-        list <- lift getList+        list <- getList         htmls <- forM list $ \item ->             putPromise singlePromise item >> runSingle         return $ mconcat htmls@@ -71,9 +86,7 @@ ------------------------------------------------------------------------------ -- | Returns a runtime computation that simply renders the node's children. promiseChildren :: Monad m => HeistT m IO (RuntimeSplice m Builder)-promiseChildren = do-    res <- runNodeList . X.childNodes =<< getParamNode-    return $! codeGen $! consolidate res+promiseChildren = liftM codeGen runChildren {-# INLINE promiseChildren #-}  @@ -293,8 +306,9 @@ -- | Given a list of output chunks, consolidate turns consecutive runs of -- @Pure Html@ values into maximally-efficient pre-rendered strict -- 'ByteString' chunks.-codeGen :: Monad m => [Chunk m] -> RuntimeSplice m Builder-codeGen l = V.foldr mappend mempty $! V.map toAct $! V.fromList l+codeGen :: Monad m => DList (Chunk m) -> RuntimeSplice m Builder+codeGen l = V.foldr mappend mempty $!+            V.map toAct $! V.fromList $! consolidate l   where     toAct !(RuntimeHtml !m)   = m     toAct !(Pure !h)          = return $! fromByteString h@@ -310,8 +324,8 @@  ------------------------------------------------------------------------------ -- | Runs a single node.  If there is no splice referenced anywhere in the--- subtree, then it is rendered as a pure chunk, otherwise it is compiled to--- a runtime computation.+-- subtree, then it is rendered as a pure chunk, otherwise it calls+-- compileNode to generate the appropriate runtime computation. runNode :: Monad n => X.Node -> Splice n runNode node = localParamNode (const node) $ do     isStatic <- subtreeIsStatic node@@ -393,14 +407,14 @@         return $ attrToChunk k value      -- Handles attribute splices-    doAttrSplice splice = DL.singleton $ RuntimeHtml $ lift $ do+    doAttrSplice splice = DL.singleton $ RuntimeHtml $ do         res <- splice v         return $ mconcat $ map attrToBuilder res       ------------------------------------------------------------------------------ -- | Given a 'X.Node' in the DOM tree, produces a \"runtime splice\" that will--- generate html at runtime. Leaves the writer monad state untouched.+-- generate html at runtime. compileNode :: Monad n => X.Node -> Splice n compileNode (X.Element nm attrs ch) =     -- Is this node a splice, or does it merely contain splices?@@ -594,9 +608,21 @@ -- during load-time splice processing. addSplices :: Monad m => [(Text, Splice n)] -> HeistT n m () addSplices ss = modifyHS (bindSplices ss)+{-# DEPRECATED addSplices "addSplices will be removed in the next release!  Use withLocalSplices instead."#-}   ------------------------------------------------------------------------------+-- | Adds a list of compiled splices to the splice map.  This function is+-- useful because it allows compiled splices to bind other compiled splices+-- during load-time splice processing.+withLocalSplices :: [(Text, Splice n)]+                 -> [(Text, AttrSplice n)]+                 -> HeistT n IO a+                 -> HeistT n IO a+withLocalSplices ss as = localHS (bindSplices ss . bindAttributeSplices as)+++------------------------------------------------------------------------------ -- | Looks up a compiled template and returns a runtime monad computation that -- constructs a builder. renderTemplate :: Monad n@@ -604,9 +630,152 @@                -> ByteString                -> Maybe (n Builder, MIMEType) renderTemplate hs nm =-    fmap (first interpret . fst) $! lookupTemplate nm hs _compiledTemplateMap+    fmap (first (interpret . DL.fromList) . fst) $!+      lookupTemplate nm hs _compiledTemplateMap -interpret :: Monad m => [Chunk m] -> m Builder++------------------------------------------------------------------------------+-- | Looks up a compiled template and returns a compiled splice.+callTemplate :: Monad n+             => ByteString+             -> HeistT n IO (DList (Chunk n))+callTemplate nm = do+    hs <- getHS+    return $ maybe DL.empty (DL.fromList . fst . fst) $+      lookupTemplate nm hs _compiledTemplateMap+++interpret :: Monad m => DList (Chunk m) -> m Builder interpret = flip evalStateT HE.empty . unRT . codeGen+++------------------------------------------------------------------------------+-- Functions for manipulating lists of compiled splices+------------------------------------------------------------------------------+++mapSnd :: (b -> c) -> [(d, b)] -> [(d, c)]+mapSnd = map . second++applySnd :: a -> [(d, a -> b)] -> [(d, b)]+applySnd a = mapSnd ($a)++textSplices :: [(Text, a -> Text)] -> [(Text, a -> Builder)]+textSplices = mapSnd textSplice++textSplice :: (a -> Text) -> a -> Builder+textSplice f = fromByteString . T.encodeUtf8 . f++nodeSplices :: [(Text, a -> [X.Node])] -> [(Text, a -> Builder)]+nodeSplices = mapSnd nodeSplice++nodeSplice :: (a -> [X.Node]) -> a -> Builder+nodeSplice f = X.renderHtmlFragment X.UTF8 . f++pureSplices :: Monad m => [(d, a -> Builder)] -> [(d, Promise a -> Splice m)]+pureSplices = mapSnd pureSplice++pureSplice :: Monad m => (a -> Builder) -> Promise a -> Splice m+pureSplice f p = do+    return $ yieldRuntime $ do+        a <- getPromise p+        return $ f a++mapInputPromise :: Monad m+                => (a -> b)+                -> (Promise b -> Splice m)+                -> Promise a -> Splice m+mapInputPromise f g p1 = do+    p2 <- newEmptyPromise+    let action = yieldRuntimeEffect $ do+        a <- getPromise p1+        putPromise p2 (f a)+    res <- g p2+    return $ action `mappend` res+++------------------------------------------------------------------------------+-- | Allows you to use deferred Promises in a compiled splice.  It takes care+-- of the boilerplate of creating and storing data in a promise to be used at+-- load time when compiled splices are processed.  This function is similar to+-- mapPromises but runs on a single value instead of a list.+defer :: Monad n+      => (Promise a -> Splice n)+      -> RuntimeSplice n a+      -> Splice n+defer f getItem = do+    promise <- newEmptyPromise+    chunks <- f promise+    return $ yieldRuntime $ do+        item <- getItem+        putPromise promise item+        codeGen chunks+++------------------------------------------------------------------------------+-- | Takes a promise function and a runtime action returning a list of items+-- that fit in the promise and returns a Splice that executes the promise+-- function for each item and concatenates the results.+deferMany :: Monad n+          => (Promise a -> Splice n)+          -> RuntimeSplice n [a]+          -> Splice n+deferMany f getItems = do+    promise <- newEmptyPromise+    chunks <- f promise+    return $ yieldRuntime $ do+        items <- getItems+        res <- forM items $ \item -> do+            putPromise promise item+            codeGen chunks+        return $ mconcat res+++withSplices :: Monad n+            => Splice n+            -> [(Text, Promise a -> Splice n)]+            -> n a+            -> Splice n+withSplices splice splices runtimeAction = do+    p <- newEmptyPromise+    let splices' = mapSnd ($p) splices+    chunks <- withLocalSplices splices' [] splice+    let fillPromise = yieldRuntimeEffect $ putPromise p =<< lift runtimeAction+    return $ fillPromise `mappend` chunks+++------------------------------------------------------------------------------+-- | Gets a list of items at runtime, then for each item it runs the splice+-- with the list of splices bound.  There is no pure variant of this function+-- because the desired behavior can only be achieved as a function of a+-- Promise.+manyWithSplices :: Monad n+                => Splice n+                -- ^ Splice to run for each of the items in the runtime list.+                -- You'll frequently use 'runChildren' here.+                -> [(Text, Promise a -> Splice n)]+                -- ^ List of splices to bind+                -> n [a]+                -- ^ Runtime action returning a list of items to render.+                -> Splice n+manyWithSplices splice splices runtimeAction = do+    p <- newEmptyPromise+    let splices' = mapSnd ($p) splices+    chunks <- withLocalSplices splices' [] splice+    return $ yieldRuntime $ do+        items <- lift runtimeAction+        res <- forM items $ \item -> putPromise p item >> codeGen chunks+        return $ mconcat res+++withPureSplices :: Monad n+                => Splice n+                -> [(Text, a -> Builder)]+                -> n a+                -> Splice n+withPureSplices splice splices action = do+    let fieldSplice g = return $ yieldRuntime $ liftM g $ lift action+    let splices' = map (second fieldSplice) splices+    withLocalSplices splices' [] splice  
src/Heist/Interpreted.hs view
@@ -78,5 +78,5 @@   ) where  import Heist.Interpreted.Internal-import Heist.Common (mapSplices)+import Heist.Common (mapSplices, bindAttributeSplices) 
src/Heist/Interpreted/Internal.hs view
@@ -10,11 +10,12 @@ import           Blaze.ByteString.Builder import           Control.Arrow hiding (loop) import           Control.Monad-import           Control.Monad.Trans+import           Control.Monad.State.Strict import qualified Data.Attoparsec.Text as AP import           Data.ByteString (ByteString) import           Data.List import qualified Data.HashMap.Strict as Map+import qualified Data.HeterogeneousEnvironment   as HE import           Data.Maybe import           Data.Monoid import qualified Data.Text as T@@ -62,17 +63,8 @@   --------------------------------------------------------------------------------- | Binds a set of new splice declarations within a 'HeistState'.-bindAttributeSplices :: [(Text, AttrSplice n)] -- ^ splices to bind-                     -> HeistState n           -- ^ start state-                     -> HeistState n-bindAttributeSplices ss hs =-    hs { _attrSpliceMap = Map.union (Map.fromList ss) (_attrSpliceMap hs) }--------------------------------------------------------------------------------- -- | Converts 'Text' to a splice returning a single 'TextNode'.-textSplice :: Monad n => Text -> Splice n+textSplice :: Monad m => Text -> HeistT n m Template textSplice t = return [X.TextNode t]  @@ -211,7 +203,8 @@ runAttrSplice :: (Monad n) => (Text, Text) -> HeistT n n [(Text, Text)] runAttrSplice a@(k,v) = do     splice <- getsHS (Map.lookup k . _attrSpliceMap)-    maybe (liftM (:[]) $ attSubst a) (lift . ($v)) splice+    maybe (liftM (:[]) $ attSubst a)+          (lift . flip evalStateT HE.empty . unRT . ($v)) splice   ------------------------------------------------------------------------------
src/Heist/Splices.hs view
@@ -1,5 +1,7 @@ module Heist.Splices-  ( module Heist.Splices.Apply+  ( ifISplice+  , ifCSplice+  , module Heist.Splices.Apply   , module Heist.Splices.Bind   , module Heist.Splices.Cache   , module Heist.Splices.Html@@ -7,10 +9,40 @@   , module Heist.Splices.Markdown   ) where -import Heist.Splices.Apply-import Heist.Splices.Bind-import Heist.Splices.Cache-import Heist.Splices.Html-import Heist.Splices.Ignore-import Heist.Splices.Markdown+import           Data.Monoid+import qualified Heist.Compiled as C+import qualified Heist.Interpreted as I+import           Heist.Splices.Apply+import           Heist.Splices.Bind+import           Heist.Splices.Cache+import           Heist.Splices.Html+import           Heist.Splices.Ignore+import           Heist.Splices.Markdown++------------------------------------------------------------------------------+-- | Run the splice contents if given condition is True, make splice disappear+-- if not.+ifISplice :: Monad m => Bool -> I.Splice m+ifISplice cond =+    case cond of+      False -> return []+      True -> I.runChildren+++------------------------------------------------------------------------------+-- | Function for constructing if splices that use a runtime predicate+-- function to determine whether the node's children should be rendered.+ifCSplice :: Monad m+          => (t -> Bool)+          -> C.Promise t+          -> C.Splice m+ifCSplice predicate prom = do+    chunks <- C.runChildren+    return $ C.yieldRuntime $ do+        a <- C.getPromise prom+        if predicate a+          then+            C.codeGen chunks+          else+            return mempty 
src/Heist/Splices/Cache.hs view
@@ -136,7 +136,7 @@     ref <- liftIO $ newIORef Nothing     liftIO $ addCompiledRef ref cts     let reload curTime = do-            builder <- C.codeGen $! C.consolidate compiled+            builder <- C.codeGen compiled             let out = fromByteString $! toByteString $! builder             liftIO $ writeIORef ref (Just (curTime, out))             return $! out
src/Heist/Types.hs view
@@ -124,7 +124,7 @@ -- | Type alias for attribute splices.  The function parameter is the value of -- the bound attribute splice.  The return value is a list of attribute -- key/value pairs that get substituted in the place of the bound attribute.-type AttrSplice m = Text -> m [(Text, Text)]+type AttrSplice m = Text -> RuntimeSplice m [(Text, Text)]   ------------------------------------------------------------------------------@@ -212,9 +212,15 @@   --------------------------------------------------------------------------------- | Gets the names of all the splices defined in a HeistState.+-- | Gets the names of all the interpreted splices defined in a HeistState. spliceNames :: HeistState m -> [Text] spliceNames ts = H.keys $ _spliceMap ts+++------------------------------------------------------------------------------+-- | Gets the names of all the compiled splices defined in a HeistState.+compiledSpliceNames :: HeistState m -> [Text]+compiledSpliceNames ts = H.keys $ _compiledSpliceMap ts   ------------------------------------------------------------------------------
test/suite/Heist/Tests.hs view
@@ -58,7 +58,7 @@  attrSpliceTest :: IO () attrSpliceTest = do-    ehs <- loadT "templates" [] [] [] [("autocheck", autocheckedSplice)]+    ehs <- loadT "templates" [] [] [] [("autocheck", lift . autocheckedSplice)]     let hs = either (error . show) id ehs         runtime = fromJust $ C.renderTemplate hs "attr_splice" 
test/suite/Heist/Tutorial/CompiledSplices.lhs view
@@ -149,12 +149,12 @@ >     ] >  > peopleSplice :: (Monad n)->              => n [Person]+>              => RuntimeSplice n [Person] >              -> C.Splice n > peopleSplice getPeople = C.mapPromises personSplice getPeople >  > allPeopleSplice :: C.Splice (StateT [Person] IO)-> allPeopleSplice = peopleSplice get+> allPeopleSplice = peopleSplice (lift get) >  > personListTest :: FilePath >                -> IO ByteString