Warning: support for Amrita has been superseded by Cerise templates. Amrita will not be included in future versions of Cerise, however it can always be installed in cerise/lib and used if desired.
The holy grail of web application development is most likely the complete separation of HTML content from the code that drives the dynamic behavior of pages. Ideally it should be possible for each page to be created by someone with HTML design skills, using any HTML or text editor, and viewable in any browser, all before the code that will populate these pages with data and behavior is ready. If this ideal is met the code and content can be built in parallel without excessive dependencies, and one can be changed without affecting the other.
There are many technologies available for generating web pages dynamically, from CGI where a program is mixed with statements that output bits and pieces of HTML, to ASP where an HTML page contains bits of code, to JSP + tag libraries where the page looks like a standard HTML document but has custom tags that only the JSP engine understands. However none of these really achieves the goal of complete separation of code and content. You can't view the resulting pages until the whole bundle of code and data is ready to run in a special editor or runtime environment.
Amrita, written by Taku Nakajima, achieves complete separation of code and content using templates, standard HTML pages containing placeholders for the dynamic content and viewable in any browser. Amrita is extremely well done with support for very complex templates, and even byte or native code compilation. This document only describes the basic syntax and how it is integrated into Cerise, please visit Amrita's homepage at http://www.brain-tokyo.jp/research/amrita for complete details.
Amrita populates a template based on values contained in a data model. This model is a Ruby hash of key-value pairs where the key is a symbol and the value is a String, List, Hash, Object, Proc, or the value true. These different types are handled as follows.
| type | action |
|---|---|
| String | the string contents are placed in the body of the element |
| List | the element is output once for each list item with the item value processed according to this table |
| Hash | a model inside a model, the sub elements of the element are processed according to the hash contents |
| Object | the same as Hash except the object's method names take the place of the key and the method result is the value |
| Proc | the Proc is called with an Amrita::Element parameter that can be modified and will take the place of the template element |
| true | the element and its children are displayed as is, with no substitution |
An example data model might be
{ :name => "world", :numbers => [1, 2, 3] }
The HTML templates are ordinary HTML pages with certain attributes
containing hints for Amrita. The main attribute is id
which, according to the HTML specification, uniquely identifies an element.
Amrita takes advantage of this feature to manipulate the element based on
whether the id attribute's value is a key in the data model, and what type
of value it maps to. If the model doesn't contain a key matching the
element's id attribute, the element and its children are
completely removed from the document.
In addition to processing each element with an id attribute,
Amrita will remove the idattribute and value even if the
element is still displayed. If the id attribute is needed
for CSS or another purpose, it can be preserved, or another attribute can
be used. See the AmritaHandler configuration
parameters below for more details.
The following template corresponds to the data model above.
<div>
Hello <b id="name">name</b>!
<ul>
<li id="numbers">1</li>
</ul>
<i id="time">12:00</i>
</div>
When this is run with the above model, the following HTML results
<div>
Hello <b>world</b>!
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
</ul>
</div>
Notice how the sample content inside the template tags has been replaced
with data from the model. Sample data is not required, but makes the
template look more like the exact end result. Of course lists will only
have one element in the template. Also notice that the time element in
<i id="time">time<i> has been deleted completely from the
output since the data model contains no :time key.
This simple example doesn't highlight the full power of Amrita: nested models allow an entire hierarchy of HTML elements to be manipulated, using Proc values in the data model allows code to modify elements at runtime. See Amrita's tour 1 and tour 2 for more details.
Cerise implements support for Amrita templates with
Cerise::AmritaHandler. This
handler accepts requests for pages
matching *.ahtml by default and executes another handler with the same
name as the page to get the template data. The execution model is as
follows
The handler called by Amrita to retrieve a template's data model may return values other than a Hash containing a data model. If a String is returned, the user is redirected to the location specified in the string via Application.redirect. If nothing is returned then the Amrita handler simply returns without doing anything. This last behavior is useful when calling Application.forward.
AmritaHandler supports several configuration parameters in
app.cfg, the values below are the defaults
@parameters[AmritaHandler] = {
:use_module => Class, # module containing data model classes
:amrita_id => "id", # attribute identifying Amrita managed elements
:delete_id => true, # delete the 'amrita_id' attribute on output
:use_rexml => false, # parse templates with REXML, needed for XHTML
:compiler_mode => false, # compile the template
:min_templates => 1, # minimum number of each template in pool
:max_templates => 100, # maximum number of each template in pool
:reap_after => 60, # seconds before reaping inactive templates
}
Creating new Template objects is quite expensive, so
Cerise::AmritaHandler maintains a pool of Template instances
for each template. The above :min_templates,
:max_templates, and :reap_after parameters
control the template pool.
Amrita templates can be combined with the HTML form support for easy creation of input centric web content.