Path: | htree/template.rb |
Last Update: | Sat Apr 28 17:00:54 +0000 2012 |
The htree template engine converts HTML and some data to HTML or XML.
Note that the following method, HTree(), is not a template method.
A template directive is described as a special HTML attribute which name begins with underscore.
The template directives are listed as follows.
_attr_name is used for a dynamic attribute.
<elem _attr_xxx="..."/> -> <elem xxx="..."/>
It is expanded to name="content". The content is generated by evaluating expr. Usually you don‘t need to care escaping: &, <, > and " are automatically escaped. If you need to output character references, the value of expr should be an object which have a rcdata method such as an HTree::Text. If the value has a rcdata method, it is called and the result is used as the content with escaping <, > and ".
_attr_name can be used multiple times in single element.
_text substitutes the content of the element by the string evaluated from expr. expr is described in the attribute value or the content of the element.
If a result of expr have &, < and/or >, they are automatically escaped. If you need to output character references, the value of expr should be an object which have a rcdata method such as an HTree::Text. If the value has a rcdata method, it is called and the result is used as the content with escaping < and >.
If the element is span or div, and there is no other attributes, no tags are produced.
<elem _text="...">dummy-content</elem> -> <elem>...</elem>
_tree substitutes the content of the element by the htree object evaluated from expr. expr is described in the attribute value or the content of the element.
If the element is span or div, and there is no other attributes, no tags are produced.
<elem _tree="...">dummy-content</elem> -> <elem>...</elem>
_if is used for conditional.
If expr is evaluated to true, it expands as follows regardless of existence of _else.
<elem _if="<i>expr</i>">then-content</elem> -> <elem>then-content</elem>
If expr is evaluated to false, it expands using _else. If _else is not given, it expands to empty. If _else is given, it expands as follows.
<elem _if="<i>expr</i>" _else="<i>name(args)</i>">then-content</elem> -> <elem _call="<i>name(args)</i>">then-content</elem> -> see _call for further expansion.
It is expanded to <elem>then-content</elem> if expr is evaluated to a true value. Otherwise, it is replaced by other template specified by _else attribute. If _else attribute is not given, it just replaced by empty.
_iter and _iter_content is used for iteration. _iter iterates the element itself but _iter_content iterates the content.
<outer _iter="..."><inner/></outer> -> <outer><inner/></outer><outer><inner/></outer>... <outer _iter_content="..."><inner/></outer> -> <outer><inner/><inner/>...</outer>
expr.meth(args) specifies iterator method call. It is actually called with a block. The block have block parameters vars. vars must be variables separated by comma.
_call is used to expand a template function. The template function is defined by _template.
<d _template="m">...</d> <c _call="m">...</c> -> <d>...</d>
A local template can be called as follows:
HTree.expand_template{<<'End'} <a _template=ruby_talk(num) _attr_href='"http://ruby-talk.org/#{num}"' >[ruby-talk:<span _text=num>nnn</span>]</a> Ruby 1.8.0 is released at <span _call=ruby_talk(77946) />. Ruby 1.8.1 is released at <span _call=ruby_talk(88814) />. End
mod should be the result of HTree.compile_template.
M = HTree.compile_template(<<'End') <a _template=ruby_talk(num) _attr_href='"http://ruby-talk.org/#{num}"' >[ruby-talk:<span _text=num>nnn</span>]</a> End HTree.expand_template{<<'End'} <html> Ruby 1.8.0 is released at <span _call=M.ruby_talk(77946) />. Ruby 1.8.1 is released at <span _call=M.ruby_talk(88814) />. </html> End
The module can included. In such case, the template function can be called without mod. prefix.
include HTree.compile_template(<<'End') <a _template=ruby_talk(num) _attr_href='"http://ruby-talk.org/#{num}"' >[ruby-talk:<span _text=num>nnn</span>]</a> End HTree.expand_template{<<'End'} <html> Ruby 1.8.0 is released at <span _call=ruby_talk(77946) />. Ruby 1.8.1 is released at <span _call=ruby_talk(88814) />. </html> End
_template defines a template function which is usable by _call.
When a template is compiled to a module by HTree.compile_template, the module have a module function for each template function defined by outermost _template attribute.
The htree template engine strips whitespace text nodes in a template except under HTML pre element.
For example the white space text node between two spans in following template is stripped.
<span _text="'a'"/> <span _text="'b'"/> -> "ab"
Character entity references are not stripped.
<span _text="'a'"/> <span _text="'b'"/> -> "a b"
Text nodes generated by _text is not stripped.
<span _text="'a'"/><span _text="' '"> </span><span _text="'b'"/> -> "a b"
The htree template engine outputs HTML or XML.
If a template has no XML declaration and the top element is HTML, the result is HTML. Otherwise the result is XML.
They differs as follows.
HTree template engine doesn‘t force you to separate design and logic. Any logic (Ruby code) can be embedded in design (HTML).
However the template engine cares the separation by logic refactorings. The logic is easy to move between a template and an application. For example, following tangled template
tmpl.html: <html> <head> <title _text="very-complex-ruby-code">dummy</title> </head> ... </html> app.rb: HTree.expand_template('tmpl.html', obj)
can be refactored as follows.
tmpl.html: <html> <head> <title _text="title">dummy</title> </head> ... </html> app.rb: def obj.title very-complex-ruby-code end HTree.expand_template('tmpl.html', obj)
In general, any expression in a template can be refactored to an application by extracting it as a method. In JSP, this is difficult especially for a code fragment of an iteration.
Also HTree encourages to separate business logic (Ruby code in an application) and presentation logic (Ruby code in a template). For example, presentation logic to color table rows stripe can be embedded in a template. It doesn‘t need to tangle an application.
HTree(html_string) parses html_string. HTree{template_string} parses template_string and expand it as a template. Ruby expressions in template_string is evaluated in the scope of the caller.
HTree() and HTree{} returns a tree as an instance of HTree::Doc.