Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Lots of cleanup. Fixed test cases. Refreshed the tutorial.

  • Loading branch information...
commit e0b3cc235ecba666f14b032f2f1f4e4c76de3739 1 parent ba587af
@mightybyte mightybyte authored
View
240 docs/templates.md
@@ -1,37 +1,38 @@
-# Snap Templates
+## Heist Templates
-Snap templates serve two primary design goals. First, they facilitate the
-separation of the view from the other aspects of your application. Second,
-they provide abstraction capabilities that allow you to avoid repeated template
-code. This allows you to follow the DRY principle (Don't Repeat Yourself) in
-the development of your application views.
+Heist templates serve two primary design goals. First, they facilitate
+the separation of the view from the other aspects of your application.
+Second, they provide abstraction capabilities that allow you to avoid
+repeated template code. This allows you to follow the DRY principle
+(Don't Repeat Yourself) in the development of your application views.
-Snap has two primary template abstraction constructs: bind and apply.
-They are implemented as specialized XML tags in the snap namespace.
+Heist has two primary template abstraction constructs: bind and apply.
+They are implemented as specialized XML tags.
-## `<snap:bind ...>`
+### The `<bind ...>` tag
-The `snap:bind` tag allows you to bind XML content to a single tag.
+The `bind` tag allows you to bind XML content to a single tag.
Whenever the bound tag is used, the template engine will substitute
-the content in its place. This allows you to essentially create your
-own higher-level markup language that snap transforms into whatever
-XML-based markup language is native to your application.
+the 'bind' tag's child nodes in its place. This allows you to
+essentially create your own higher-level markup language that Heist
+transforms into whatever XML-based markup language is native to your
+application.
-### Attributes
+#### Attributes
-The `snap:bind` tag has a single required attribute called `tag` specifying the
+The `bind` tag has a single required attribute called `tag` specifying the
name of the bound tag. If this attribute is not present, then the
-`snap:bind` tag has no effect.
+`bind` tag has no effect.
-### Example
+#### Example
Here's a simple example demonstrating the use of bind.
~~~~~~~~~~~~~~~ {.html}
- <snap:bind tag="longname">
+ <bind tag="longname">
Einstein, Feynman, Heisenberg, and Newton Reasearch Corporation
Ltd.<sup>TM</sup>
- </snap:bind>
+ </bind>
We at <longname/> have research expertise in many areas of physics.
Employment at <longname/> carries significant prestige. The rigorous
hiring process developed by <longname/> is leading the industry.
@@ -41,26 +42,47 @@ The full company name will be substituted at every occurrance of the
`<longname/>` tag. This eliminates repetition and makes it easier to
make changes.
-## `<snap:apply ...>`
+### The `<apply ...>` tag
-The `snap:apply` tag loads one of your application templates and inserts it
-into the current template's XML tree. If the target template does not have any
-special tags, then the contents of the `snap:apply` tag are ignored.
+The `apply` tag loads one of your application templates and inserts it
+into the current template's XML tree. If the target template does not
+have any special tags, then the contents of the `apply` tag are
+ignored.
-### Attributes
+#### Attributes
-The `snap:apply` tag has one required attribute called `template`. This attribute
-specifies the path to the template being applied. **`TODO`**: describe template
-path behavior.
+The `apply` tag has one required attribute called `template`. This
+attribute specifies the name of the template being applied. Heist
+template names work a little differently from traditional paths and
+filenames.
+If the template name contains a '/' character, then it will behave
+like traditional relative and absolute paths. The root directory will
+be the root of your template directory tree, and the current directory
+will be the directory containing whatever template is currently being
+processed. Absolute template path names start at the root directory.
+Relative template path names start at the current directory.
-### Example
+If the template name does not have any '/' characters, then Heist
+searches in the current directory for a template with that name. If
+it finds one, then Heist applies the template just like you would
+expect. The different behavior is that if the named template is
+not found in the current directory, Heist recursively searches up the
+directory hierarchy looking for the name. Heist uses the first
+template it finds on the way up that has that name. If no template is
+found, then you'll get an error.
-Let's look at a simple example to demonstrate the most basic use of the
-`snap:apply` tag. Say you have a navigation menu that is used on many
-different pages of your site. You want to avoid duplicating the HTML code in
-multiple different page templates, so you might put it in a template file by
-itself called `nav.tpl` that looks like this:
+This cascading behavior allows you to put site-wide templates in the
+top-level directory and selectively override them in subdirectories
+for certain parts of your site.
+
+#### Example
+
+Let's look at a simple example to demonstrate the most basic use of
+the `apply` tag. Say you have a navigation menu that is used on many
+different pages of your site. You want to avoid duplicating the HTML
+code in multiple different page templates, so you might put it in a
+template file by itself called `nav.tpl` that looks like this:
~~~~~~~~~~~~~~~ {.html}
<ul>
@@ -70,9 +92,9 @@ itself called `nav.tpl` that looks like this:
</ul>
~~~~~~~~~~~~~~~
-Then to include this nav template in your front page template, you would use
-the `snap:apply` tag. Here is what a simple home page template `home.tpl`
-might look like:
+Then to include this nav template in your front page template, you
+would use the `apply` tag. Here is what a simple home page template
+`home.tpl` might look like:
~~~~~~~~~~~~~~~ {.html}
<html>
@@ -81,16 +103,16 @@ might look like:
</head>
<body>
<h1>Home Page</h1>
- <snap:apply template="nav"/>
+ <apply template="nav"/>
<p>Welcome to our home page</p>
</body>
</html>
~~~~~~~~~~~~~~~
-When a user requests the `/home` URL, Snap would serve `home.tpl` (**`FIXME`**:
-depends on the snaplet in question), and the nav template would automatically
-be inserted into the page. Here is what the HTML will look like after the Snap
-processes the template:
+When a user requests the `/home` URL, Heist would serve `home.tpl`,
+and the nav template would automatically be inserted into the page.
+Here is what the HTML will look like after Heist processes the
+template:
~~~~~~~~~~~~~~~ {.html}
<html>
@@ -110,19 +132,21 @@ processes the template:
~~~~~~~~~~~~~~~
-## `<snap:get ...>`
+### The `<content>` tag
-Sometimes it is useful to pass information (usually in the form of XML data)
-into the template when it is applied so the template can insert it in useful
-places. This allows you to build page templates that are not just static
-blocks of code. If you are a programmer, you can think of a template as if it
-was a function that could have any number of parameters.
+Sometimes it is useful to pass information (usually in the form of XML
+data) into the template when it is applied so the template can insert
+it in useful places. This allows you to build page templates that are
+not just static blocks of code. If you are a programmer, you can
+think of a template as if it was a function that could have any number
+of parameters.
-In our previous example, we did not pass any parameters to the `nav` template
-when it was applied, so the `<snap:apply>` tag was empty. If we include data
-inside the body of the `<snap:apply>` tag, the template being called can access
-this data with the `<snap:get>` tag. The following simple example illustrates
-this concept. We create a site template called `default.tpl`:
+In our previous example, we did not pass any parameters to the `nav`
+template when it was applied, so the `<apply>` tag was empty. If we
+include data inside the body of the `<apply>` tag, the template being
+called can access this data with the `<content>` tag. The following
+simple example illustrates this concept. We create a site template
+called `default.tpl`:
~~~~~~~~~~~~~~~ {.html}
<html>
@@ -134,7 +158,7 @@ this concept. We create a site template called `default.tpl`:
<h1>XYZ Inc.</h1>
</div>
<div id="content">
- <snap:get />
+ <content />
</div>
<div id="footer">
<p>Copyright XYZ Inc</p>
@@ -144,19 +168,20 @@ this concept. We create a site template called `default.tpl`:
~~~~~~~~~~~~~~~
-The `<snap:get>` tag "pulls in" the page content from the calling template and
-inserts it into the content `<div>`.
+The `<content>` tag "pulls in" the page content from the calling
+template and inserts it into the content `<div>`.
Now we have a template for our home page called home.tpl:
~~~~~~~~~~~~~~~ {.html}
-<snap:apply template="default">
+<apply template="default">
<h1>Home Page</h1>
<p>Welcome to XYZ Inc</p>
-</snap:apply>
+</apply>
~~~~~~~~~~~~~~~
-And when Snap receives a request to `/home`, it will serve the following:
+And when Heist receives a request to `/home`, it will serve the
+following:
~~~~~~~~~~~~~~~ {.html}
<html>
@@ -178,28 +203,30 @@ And when Snap receives a request to `/home`, it will serve the following:
</html>
~~~~~~~~~~~~~~~
-The two lines from inside the `<snap:apply>` tag have been substituted into the
-content div in `default.tpl`. Notice the difference between these two
-examples. In the first example we pulled in a template (`nav.tpl`) that went
-inside the page being served (`home.tpl`). In the second example, `home.tpl`
-is still the intended target of requests, but the `default.tpl` template
-surrounds the content that home.tpl supplies as an argument. This seems like
-different behavior, but it is just a different use of the same `apply` tag. This
+The two lines from inside the `<apply>` tag have been substituted into
+the content div in `default.tpl`. Notice the difference between these
+two examples. In the first example we pulled in a template
+(`nav.tpl`) that went inside the page being served (`home.tpl`). In
+the second example, `home.tpl` is still the intended target of
+requests, but the `default.tpl` template surrounds the content that
+home.tpl supplies as an argument. This seems like different behavior,
+but it is just a different use of the same `apply` tag. This
illustrates the power of a simple concept like `apply`.
-## Using Bind and Apply
+### Using Bind and Apply
-What if, in the above example, we decided that the contents of the header div
-should be different for different pages? To do this, we need a way to pass
-multiple parameters into a template. Snap provides this capability with the
-`<snap:bind>` tag. Inside the body of a `<snap:apply>` tag, you can have
-multiple snap:bind tags surrounding data to be passed as separate parameters.
-Each `<snap:bind>` tag must have a name attribute that provides a name for its
-contents. Then, inside the template, each `<snap:get>` tag should have a name
-attribute indicating the name of the parameter to which it corresponds.
+What if, in the above example, we decided that the contents of the
+header div should be different for different pages? To do this, we
+need a way to pass multiple parameters into a template. Heist
+provides this capability with the `<bind>` tag. Inside the body of a
+`<apply>` tag, you can have multiple bind tags surrounding data to be
+passed as separate parameters. Each `<bind>` tag must have a `tag`
+attribute that provides a name for its contents just as described
+above. Then, inside the template, those tags will be substituted with
+the appropriate data.
-The previous example only needs a few modifications to default.tpl to allow
-multiple parameters. The `<snap:get>` tags now have name attributes:
+The previous example only needs a few modifications to `default.tpl`
+to allow multiple parameters.
~~~~~~~~~~~~~~~ {.html}
<html>
@@ -211,7 +238,7 @@ multiple parameters. The `<snap:get>` tags now have name attributes:
<header/>
</div>
<div id="content">
- <content/>
+ <main/>
</div>
<div id="footer">
<p>Copyright XYZ Inc</p>
@@ -221,28 +248,61 @@ multiple parameters. The `<snap:get>` tags now have name attributes:
~~~~~~~~~~~~~~~
-And `home.tpl` uses the `<snap:bind>` tag with a name attribute to define values
-for the parameters:
+And `home.tpl` uses the `<bind>` tag with a name attribute to define
+values for the `<header/>` and `<main/>` tags:
~~~~~~~~~~~~~~~ {.html}
-<snap:apply name="default">
- <snap:bind tag="header">
+<apply template="default">
+ <bind tag="header">
<h1>XYZ Inc.</h1>
- </snap:bind>
- <snap:bind tag="content">
+ </bind>
+ Some in-between text.
+ <bind tag="main">
<h1>Home Page</h1>
<p>Welcome to XYZ Inc</p>
- </snap:bind>
-</snap:apply>
+ </bind>
+</apply>
~~~~~~~~~~~~~~~
The result template for this example is the same as the previous
example.
-## `<snap:ignore ...>`
+NOTE: In this example the `<content/>` tag is still bound as described
+above. The `<content/>` tag is always bound to the complete contents
+of the calling `apply` tag. However, any `bind` tags inside the apply
+will disappear. If we changed `default.tpl` to the following:
+
+~~~~~~~~~~~~~~~ {.html}
+<foo>
+ <content/>
+</foo>
+~~~~~~~~~~~~~~~
+
+Then the above `home.tpl` template would render like this:
+
+~~~~~~~~~~~~~~~ {.html}
+<foo>
+ Some in-between text.
+</foo>
+~~~~~~~~~~~~~~~
+
+
+### The `<ignore>` tag
+
+In some cases you may want to include example data in a Heist template
+that should not be rendered when the site is active. Heist provides
+the `<ignore>` tag for this purpose. All `<ignore>` tags and their
+contents will be eliminated in a template's output.
+
+
+### The `<children>` tag
+
+XML requires that well-formed documents have a single root element.
+Sometimes you might want to make templates that don't have a single
+root element. In these situations the `<children>` tag is just what
+you want. When the children tag is rendered, it strips itself off and
+just returns its child nodes. This allows you to have a single root
+element where necessary, but have that tag disappear in the rendered
+output.
-In some cases you may want to include example data in a Snap template that
-should not be rendered when the site is active. Snap provides the
-`<snap:ignore>` tag for this purpose. All `<snap:ignore>` tags and their contents
-will be eliminated in a template's output.
View
262 src/Text/Templating/Heist.hs
@@ -77,20 +77,16 @@ module Text.Templating.Heist
, stopRecursion
, getParamNode
, runNodeList
+ , getContext
-- * Functions for running splices and templates
, runSplice
, runTemplate
, runBareTemplate
-
- -- * Temporary (FIXME)
, getDoc
, loadTemplates
, renderTemplate
, renderTemplate'
- , tShow
--- , test
--- , evalFile
, module Text.Templating.Heist.Constants
) where
@@ -104,16 +100,11 @@ import qualified Data.Foldable as F
import Data.List
import qualified Data.Map as Map
import Data.Map (Map)
-import Data.Maybe
-import Data.Monoid
import System.Directory.Tree hiding (name)
-import System.FilePath
+import Text.XML.Expat.Format
import qualified Text.XML.Expat.Tree as X
-import Text.XML.Expat.Format
-import Debug.Trace
-
import Text.Templating.Heist.Constants
------------------------------------------------------------------------------
-- Types
@@ -127,7 +118,7 @@ type Node = X.Node ByteString ByteString
-- | A 'Template' is a forest of XML nodes.
type Template = [Node]
--- |Reversed list of directories
+-- | Reversed list of directories
type TPath = [ByteString]
type TemplateMap = Map TPath Template
@@ -156,19 +147,19 @@ type TemplateMap = Map TPath Template
-- output verbatim.
data TemplateState m = TemplateState {
- -- | A mapping of splice names to splice actions
- _spliceMap :: SpliceMap m
- -- | A mapping of template names to templates
- , _templateMap :: TemplateMap
- -- | A flag to control splice recursion
- , _recurse :: Bool
- , _curContext :: TPath
+ -- | A mapping of splice names to splice actions
+ _spliceMap :: SpliceMap m
+ -- | A mapping of template names to templates
+ , _templateMap :: TemplateMap
+ -- | A flag to control splice recursion
+ , _recurse :: Bool
+ , _curContext :: TPath
}
instance Eq (TemplateState m) where
- a == b = (_recurse a == _recurse b) &&
- (_templateMap a == _templateMap b) &&
- (_curContext a == _curContext b)
+ a == b = (_recurse a == _recurse b) &&
+ (_templateMap a == _templateMap b) &&
+ (_curContext a == _curContext b)
-- | 'TemplateMonad' is a monad transformer that gives you access to the 'Node'
-- being processed (using the 'MonadReader' instance) as well as holding the
@@ -186,7 +177,7 @@ type SpliceMap m = Map ByteString (Splice m)
instance Monoid (TemplateState m) where
mempty = TemplateState Map.empty Map.empty True []
- (TemplateState s1 t1 r1 c1) `mappend` (TemplateState s2 t2 r2 c2) =
+ (TemplateState s1 t1 r1 _) `mappend` (TemplateState s2 t2 r2 c2) =
TemplateState s t r c2
where
s = s1 `mappend` s2
@@ -210,45 +201,61 @@ bindSplice :: Monad m =>
-> TemplateState m
bindSplice n v ts = ts {_spliceMap = Map.insert n v (_spliceMap ts)}
-
--- |convenience function for looking up a splice.
-lookupSplice :: Monad m => ByteString -> TemplateState m -> Maybe (Splice m)
+-- | Convenience function for looking up a splice.
+lookupSplice :: Monad m =>
+ ByteString
+ -> TemplateState m
+ -> Maybe (Splice m)
lookupSplice nm ts = Map.lookup nm $ _spliceMap ts
--- |Converts a path into an array of the elements in reverse order.
+-- | Converts a path into an array of the elements in reverse order.
splitPaths :: ByteString -> TPath
splitPaths = reverse . B.split '/'
-{-|
- Searches for a template by looking in the full path then backing up into each
- of the parent directories until the template is found.
--}
-traversePath :: TemplateMap -> TPath -> ByteString -> Maybe (Template, TPath)
+singleLookup :: TemplateMap
+ -> TPath
+ -> ByteString
+ -> Maybe (Template, TPath)
+singleLookup tm path name = fmap (,path) $ Map.lookup (name:path) tm
+
+-- | Searches for a template by looking in the full path then backing up into each
+-- of the parent directories until the template is found.
+traversePath :: TemplateMap
+ -> TPath
+ -> ByteString
+ -> Maybe (Template, TPath)
traversePath tm [] name = fmap (,[]) (Map.lookup [name] tm)
traversePath tm path name =
- --trace ("traversePath "++(B.unpack name)++" "++(show path)++" returned "++(show $ Map.lookup (name:path) tm))
- (fmap (,path) $ Map.lookup (name:path) tm) `mplus` traversePath tm (tail path) name
-
--- |Convenience function for looking up a template.
-lookupTemplate :: Monad m => ByteString -> TemplateState m -> Maybe (Template, TPath)
+ singleLookup tm path name `mplus`
+ traversePath tm (tail path) name
+
+-- | Convenience function for looking up a template.
+lookupTemplate :: Monad m =>
+ ByteString
+ -> TemplateState m
+ -> Maybe (Template, TPath)
lookupTemplate nameStr ts =
- --trace ("lookup "++(B.unpack nameStr)++" with "++(show $ _curContext ts)) $
- traversePath (_templateMap ts) (path++(_curContext ts)) name
- where (name:path) = splitPaths nameStr
-
--- |Adds a template to the template state.
+ f (_templateMap ts) path name
+ where (name:p) = splitPaths nameStr
+ path = p ++ (_curContext ts)
+ f = if '/' `B.elem` nameStr
+ then singleLookup
+ else traversePath
+
+-- | Adds a template to the template state.
addTemplate :: Monad m =>
ByteString
-> Template
-> TemplateState m
-> TemplateState m
-addTemplate n t st = st {_templateMap = Map.insert (splitPaths n) t (_templateMap st)}
+addTemplate n t st =
+ st {_templateMap = Map.insert (splitPaths n) t (_templateMap st)}
--- |Gets the node currently being processed.
+-- | Gets the node currently being processed.
getParamNode :: Monad m => TemplateMonad m Node
getParamNode = ask
--- |Stops the recursive processing of splices.
+-- | Stops the recursive processing of splices.
stopRecursion :: Monad m => TemplateMonad m ()
stopRecursion = modify (\st -> st { _recurse = False })
@@ -260,11 +267,11 @@ setContext c = modify (\st -> st { _curContext = c })
getContext :: Monad m => TemplateMonad m TPath
getContext = gets _curContext
--- |Performs splice processing on a list of nodes.
+-- | Performs splice processing on a list of nodes.
runNodeList :: Monad m => [Node] -> Splice m
runNodeList nodes = liftM concat $ sequence (map runNode nodes)
--- |Performs splice processing on a single node.
+-- | Performs splice processing on a single node.
runNode :: Monad m => Node -> Splice m
runNode n@(X.Text _) = return [n]
runNode n@(X.Element nm _ ch) = do
@@ -276,44 +283,46 @@ runNode n@(X.Element nm _ ch) = do
newKids <- runNodeList ch
return [X.modifyChildren (const newKids) n]
--- |Checks the recursion flag and recurses accordingly.
+-- | Checks the recursion flag and recurses accordingly.
recurseSplice :: Monad m => Node -> Splice m -> Splice m
recurseSplice node splice = do
- result <- local (const node) splice
- ts' <- get
- if _recurse ts'
- then runNodeList result
- else return result
-
-{-|
- Runs a splice in the underlying monad. Splices require two
- parameters, the template state, and an input node.
--}
+ result <- local (const node) splice
+ ts' <- get
+ if _recurse ts'
+ then runNodeList result
+ else return result
+
+-- | Runs a splice in the underlying monad. Splices require two
+-- parameters, the template state, and an input node.
runSplice :: Monad m =>
TemplateState m -- ^ The initial template state
-> Node -- ^ The splice's input node
-> Splice m -- ^ The splice
-> m [Node]
runSplice ts node (TemplateMonad splice) = do
- (result,_,_) <- runRWST splice node ts
- return result
+ (result,_,_) <- runRWST splice node ts
+ return result
-{-|
- Runs a template in the underlying monad. Similar to runSplice
- except that templates don't require a Node as a parameter.
--}
+-- | Runs a template in the underlying monad. Similar to runSplice
+-- except that templates don't require a Node as a parameter.
runTemplate :: Monad m => TemplateState m -> Template -> m [Node]
runTemplate ts template = runSplice ts (X.Text "") (runNodeList template)
-nameContext = tail . splitPaths
-
-runTemplateByName :: Monad m => TemplateState m -> ByteString -> m (Maybe [Node])
+-- | Looks up a template name in the supplied 'TemplateState' and runs
+-- it in the underlying monad.
+runTemplateByName :: Monad m =>
+ TemplateState m
+ -> ByteString
+ -> m (Maybe [Node])
runTemplateByName ts name = do
- let mt = lookupTemplate name ts
- maybe (return Nothing) (\(t,ctx) -> return . Just =<< runTemplate (ts {_curContext = ctx}) t) mt
--- maybe (return []) (\(t,ctx) -> runTemplate (ts {_curContext = ctx}) t) mt
-
--- |Runs a template with an empty TemplateState.
+ let mt = lookupTemplate name ts
+ maybe (return Nothing)
+ (\(t,ctx) ->
+ return . Just =<<
+ runTemplate (ts {_curContext = ctx}) t)
+ mt
+
+-- | Runs a template with an empty TemplateState.
runBareTemplate :: Monad m => Template -> m [Node]
runBareTemplate = runTemplate emptyTemplateState
@@ -323,11 +332,11 @@ runBareTemplate = runTemplate emptyTemplateState
-- The bind splice
--- |Default name for the bind splice.
+-- | Default name for the bind splice.
bindTag :: ByteString
bindTag = "bind"
--- |Default attribute name for the bind tag.
+-- | Default attribute name for the bind tag.
bindAttr :: ByteString
bindAttr = "tag"
@@ -356,32 +365,51 @@ applyAttr = "template"
-- | Implementation of the bind splice.
applyImpl :: Monad m => Splice m
applyImpl = do
- stopRecursion
- node <- getParamNode
- case X.getAttribute node applyAttr of
- Nothing -> return [] -- TODO: error handling
- Just attr -> do
- st <- get
- let template = lookupTemplate attr (st {_curContext = nextCtx attr st})
- put $ st { _spliceMap = defaultSpliceMap }
- processedChildren <- runNodeList $ X.getChildren node
- modify (bindSplice "content" $ return processedChildren)
- maybe (return []) -- TODO: error handling
- (\(t,ctx) -> do setContext ctx
- result <- runNodeList t
- put st
- return result)
- template
+ stopRecursion
+ node <- getParamNode
+ case X.getAttribute node applyAttr of
+ Nothing -> return [] -- TODO: error handling
+ Just attr -> do
+ st <- get
+ put $ st { _spliceMap = defaultSpliceMap }
+ processedChildren <- runNodeList $ X.getChildren node
+ modify (bindSplice "content" $ return processedChildren)
+ maybe (return []) -- TODO: error handling
+ (\(t,ctx) -> do setContext ctx
+ result <- runNodeList t
+ put st
+ return result)
+ (lookupTemplate attr (st {_curContext = nextCtx attr st}))
where nextCtx name st
- | B.isPrefixOf "/" name = []
- | otherwise = _curContext st
+ | B.isPrefixOf "/" name = []
+ | otherwise = _curContext st
+-- | Default name for the ignore splice.
+ignoreTag :: ByteString
+ignoreTag = "ignore"
+
+-- | The ignore tag and everything it surrounds disappears in the
+-- rendered output.
+ignoreImpl :: Monad m => Splice m
+ignoreImpl = return []
+
+-- | Default name for the ignore splice.
+childrenTag :: ByteString
+childrenTag = "children"
+
+-- | The ignore tag and everything it surrounds disappears in the
+-- rendered output.
+childrenImpl :: Monad m => Splice m
+childrenImpl = return . X.getChildren =<< getParamNode
+
-- | The default set of built-in splices.
defaultSpliceMap :: Monad m => SpliceMap m
defaultSpliceMap = Map.fromList
- [(applyTag, applyImpl)
- ,(bindTag, bindImpl)
- ]
+ [(applyTag, applyImpl)
+ ,(bindTag, bindImpl)
+ ,(ignoreTag, ignoreImpl)
+ ,(childrenTag, childrenImpl)
+ ]
expatOptions :: X.ParserOptions ByteString ByteString
expatOptions =
@@ -393,10 +421,12 @@ expatOptions =
{-
- Template loading
-}
+
+-- | Reads an XML document from disk.
getDoc :: String -> IO (Either String Node)
getDoc f = do
- bs <- catch (liftM Right $ B.readFile f) (\e -> return $ Left $ show e)
- return $ (mapLeft show . X.parse' expatOptions) =<< bs
+ bs <- catch (liftM Right $ B.readFile f) (\e -> return $ Left $ show e)
+ return $ (mapLeft show . X.parse' expatOptions) =<< bs
mapLeft :: (a -> b) -> Either a c -> Either b c
mapLeft g = either (Left . g) Right
@@ -405,41 +435,39 @@ mapLeft g = either (Left . g) Right
-- template is only loaded if it has a ".tpl" extension.
loadTemplate :: String -> String -> IO TemplateMap
loadTemplate path fname
- | ".tpl" `isSuffixOf` fname = do
- putStrLn $ "Reading "++fname++" as "++tName
- c <- getDoc fname
- print c
- return $ either (const Map.empty) (Map.singleton (splitPaths $ B.pack tName) . (:[])) c
- | otherwise = do
- putStrLn $ "Skipping "++fname
- return Map.empty
- where tName = drop ((length path)+1) $ take ((length fname) - 4) fname
+ | ".tpl" `isSuffixOf` fname = do
+ c <- getDoc fname
+ return $ either
+ (const Map.empty)
+ (Map.singleton (splitPaths $ B.pack tName) . (:[])) c
+ | otherwise = return Map.empty
+ where tName = drop ((length path)+1) $
+ take ((length fname) - 4) fname
-- | Traverses the specified directory structure and builds a
-- TemplateState by loading all the files with a ".tpl" extension.
loadTemplates :: Monad m => FilePath -> IO (TemplateState m)
loadTemplates dir = do
- d <- readDirectoryWith (loadTemplate dir) dir
- let tm = F.fold (free d)
- return $ TemplateState defaultSpliceMap tm True []
+ d <- readDirectoryWith (loadTemplate dir) dir
+ let tm = F.fold (free d)
+ return $ TemplateState defaultSpliceMap tm True []
-- | Renders a template from the specified TemplateState.
renderTemplate :: Monad m => TemplateState m -> ByteString -> m (Maybe ByteString)
renderTemplate ts name = do
- ns <- runTemplateByName ts name
- return $ (Just . formatList') =<< ns
+ ns <- runTemplateByName ts name
+ return $ (Just . formatList') =<< ns
-- | Reloads the templates from disk and renders the specified
-- template.
renderTemplate' :: FilePath -> ByteString -> IO (Maybe ByteString)
renderTemplate' baseDir name = do
- ts <- loadTemplates baseDir
- ns <- runTemplateByName ts name
- return $ (Just . formatList') =<< ns
+ ts <- loadTemplates baseDir
+ ns <- runTemplateByName ts name
+ return $ (Just . formatList') =<< ns
-tShow :: (X.GenericXMLString tag, X.GenericXMLString text)
- => [X.Node tag text] -> IO ()
-tShow = L.putStrLn . L.concat . map formatNode
+---------------------------------------------------------------------
+-- These are here until we can get them into hexpat.
formatList :: (X.GenericXMLString tag, X.GenericXMLString text) =>
[X.Node tag text]
View
4 test/suite/Text/Templating/Heist/Tests.hs
@@ -54,9 +54,7 @@ isLeft (Right _) = False
loadTest :: H.Assertion
loadTest = do
tm <- liftM _templateMap $ (loadTemplates "templates" :: IO (TemplateState IO))
- print $ Map.size tm
- print $ tm
- H.assertBool "loadTest size" $ Map.size tm == 12
+ H.assertBool "loadTest size" $ Map.size tm == 8
getDocTest :: H.Assertion
getDocTest = do
View
2  test/templates/user/admin/main.tpl
@@ -1,4 +1,4 @@
<html>
Admin Page
-<snap:apply template="menu"/>
+<apply template="menu"/>
</html>
View
2  test/templates/user/main.tpl
@@ -1,4 +1,4 @@
<html>
User Page
-<snap:apply template="menu"/>
+<apply template="menu"/>
</html>
Please sign in to comment.
Something went wrong with that request. Please try again.