This is the 'hello world' for Amrita2.
--- ../sample/hello/step1.rb --- |
require "amrita2/template" include Amrita2 class PO def title "hello world" end def body "Amrita2 is a html template libraly for Ruby" end end tmpl = TemplateFile.new("template.html") tmpl.expand(STDOUT, PO.new) |
--- ../sample/hello/template.html --- |
<html> <body> <h1 id='title'>title will be inserted here</h1> <p id='body'>body text will be inserted here</p> </body> </html> |
<html> <body> <h1>hello world</h1> <p>Amrita2 is a html template library for Ruby</p> </body> </html> |
There are two kind of objects in this example: Presentation Object(PO) and Template Object(TO).
Amrita2::TemplateFile is a TO which accepts HTML template from a file. This is how to create a Amrita2::TemplateFile object.
require "amrita2/template" include Amrita2 tmpl = TemplateFile.new("template.html") |
TO treats an element with id attribute as a dynamic element and will get the data for it from PO data using id attribute's value as method name.
Almost any Ruby object can be a Presentation Object only if PO has methods for dynamic elements.
class PO def title "hello world" end def body "Amrita2 is a html template libraly for Ruby" end end |
And a Hash can be used for PO.
data = { :title => "hello world", :body => "Amrita2 is a html template libraly for Ruby" } tmpl = TemplateFile.new("template.html") tmpl.expand(STDOUT, data) |
If this data was given to the TO, same result will be produced.
PO methods returns a value for template expansion. This sample describes how TO expand values.
--- ../sample/hello/step2.rb --- |
require "amrita2/template" include Amrita2 class PO def array_data [1, 2, 3] end def nested_struct Time.gm(2005,2,23, 4,5,6) end def nested_structs [Time.gm(2005,2,23, 4,5,6),Time.gm(2005,2,24, 4,5,6) ] end end tmpl = TemplateText.new <<-END <html> <body> <h1>array data</h1> <span id='array_data'> </span> <h1>nested struct</h1> <p id='nested_struct'> <span id='hour' />:<span id='min' />:<span id='sec' /> </p> <h1>array of nested struct</h1> <p id='nested_structs'> <span id='day' /> </p> </body> </html> END tmpl.expand(STDOUT, PO.new) |
<html> <body> <h1>array data</h1> <span>1</span><span>2</span><span>3</span> <h1>nested struct</h1> <p> <span>4</span>:<span>5</span>:<span>6</span> </p> <h1>array of nested struct</h1> <p> <span>23</span> </p><p> <span>24</span> </p> </body> </html> |
If a passive PO method returns Array ( or an Enumerable object)
def array_data [1, 2, 3] end |
then the matching element will be expanded many times.
From
<h1>array data</h1> <span id='array_data'> </span> |
To
<h1>array data</h1> <span>1</span><span>2</span><span>3</span> |
You can delete <span> tags using Template Spec if you like.
If the element has inner struct like this
<p id='nested_struct'> <span id='hour' />:<span id='min' />:<span id='sec' /> </p> |
then the PO method must return an object with the same methods with ID
def nested_struct Time.gm(2005,2,23, 4,5,6) end |
A Time Object has hour, min, sec as method. These methods will be called by TO and the result of the method will be inserted into the matching element.
<h1>nested struct</h1> <p> <span>4</span>:<span>5</span>:<span>6</span> </p> |
If a PO method returns an Array of Struct
def nested_structs [Time.gm(2005,2,23, 4,5,6),Time.gm(2005,2,24, 4,5,6) ] end |
then the element will be expanded two time each for an element of the Array.
From
<p id='nested_structs'> <span id='day' /> </p> |
To
<h1>array of nested struct</h1> <p> <span>23</span> </p><p> <span>24</span> </p> |
This is true for any levels of nest and any combination of struct and array.
Amrita2 has many ways to attribute handling.
--- ../sample/hello/step3.rb --- |
require "amrita2/template" include Amrita2 tmpl = TemplateText.new <<END <html> <body> <h1><a id='a1'>replacing attributes</a></h1> <a id='a2' amrita:type='link'>Amrita2</a> <p>See <a id='a3' amrita:type='use_original_element' href='http://www.ruby-lang.org/'>Ruby homepage</a> for detail </p> <a id='rubytalk' amrita:type='use_args' href="http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/$1"> [ruby-talk:$1] </a> <a id='raa' amrita:type='use_args' href="http://raa.ruby-lang.org/list.rhtml?name=$1"> [$2] </a> </body> </html> END data = { :a1 => a(:href=>'http://amrita2.rubyforge.org/') { 'replaced' }, :a2 => 'http://amrita2.rubyforge.org/', # use_original_element: REXML::Element object for the spec # will be passed. Edit it and return it or make a new # Element object and return it. :a3 => proc do |e| e.text += "(Japanese)" e.attributes['href'] += 'ja/' e end, # use_args: the value passed will be replaced $1, $2..... :rubytalk=>132204, :raa =>['amrita', 'amrita: HTML template library'] } tmpl.expand(STDOUT, data) |
<html> <body> <h1><a href='http://amrita2.rubyforge.org/'>replaced</a></h1> <a href='http://amrita2.rubyforge.org/'>Amrita2</a> <p>See <a href='http://www.ruby-lang.org/ja/'>Ruby homepage(Japanese)</a> for detail </p> <a href='http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/132204'> [ruby-talk:132204] </a> <a href='http://raa.ruby-lang.org/list.rhtml?name=amrita'> [amrita: HTML template library] </a> </body> </html> |
AttrArray is a Object for a PO require TO to replace attributes.
If PO passes a AttrArray Object ( a(..) { .. } is shortcut for it),
data = { :a1 => a(:href=>'http://amrita2.rubyforge.org/') { 'replaced' }, } |
The attribute and text is inserted to the matching template element.
So this template with data above
<h1><a id='a1'>replacing attributes</a></h1> |
makes the result:
<h1><a href='http://amrita2.rubyforge.org/'>replaced</a></h1> |
If the body part ( { ... } ) was ommited,
data = { :a1 => a(:href=>'http://amrita2.rubyforge.org/') } |
only attribute will be replaced
<a href='http://amrita2.rubyforge.org/'>replacing attributes</a> |
If you put a amrita:type attribute in the template,
<a id='a2' amrita:type='link'>Amrita2</a> |
Amrita2 will treat the element in a diffrent way. In this case, the type is 'link' which means the value will be inserted to the href part of the element instead of the contained text of the element.
So you can pass just the url alone for the element.
data = { :a2 => 'http://amrita2.rubyforge.org/', } |
The result is
<a href='http://amrita2.rubyforge.org/'>Amrita2</a> |
amrita:type='use_args' means '$1' in template will be replaced with the data given.
<a id='rubytalk' amrita:type='use_args' href="http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/$1"> [ruby-talk:$1] </a> |
If you give this data to this template above
data { :rubytalk=>132204, } |
the result will be
<a href='http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/132204'> [ruby-talk:132204] </a> |
If two or more args are needed
<a id='raa' amrita:type='use_args' href="http://raa.ruby-lang.org/list.rhtml?name=$1"> [$2] </a> |
Give an Array for it.
data { :raa =>['amrita', 'amrita: HTML template library'] } |
The result is
<a href='http://raa.ruby-lang.org/list.rhtml?name=amrita'> [amrita: HTML template library] </a> |
If you use an attribute or text in the template and make the result from it, use the amrita:type 'use_original_element'.
<p>See <a id='a3' amrita:type='use_original_element' href='http://www.ruby-lang.org/'>Ruby homepage</a> for detail </p> |
And pass a Proc to it,
data = { :a3 => proc do |e| # A REXML::Element will be passed to the proc e.text += "(Japanese)" e.attributes['href'] += 'ja/' # modify it or make new Element and return it e end, } |
The result is
<p>See <a href='http://www.ruby-lang.org/ja/'>Ruby homepage(Japanese)</a> for detail </p> |
There are many 'amrita:type's
And you can add new types to Amrita2 if you like to.
The interface of this plugin is very complicated and not fixed yet. So it is not documented well. Mail me if you want to use this feature. I may write a plugin or base of it for you.
--- ../sample/spec/inline.rb --- |
require "amrita2/template" include Amrita2 include Amrita2::Runtime # for amrita:type='erb' TEMPLATE_TEXT = <<END <html> <body> <table> <tr><th>name</th><th>author</th></tr> <tr id='lang' amrita:type='use_args'> <td><a href='$2'>$1</a></td><td>$3</td> </tr> </table> <hr /> powered by <a id='link' amrita:type='link'>Amrita2</a> <br /> <span id='erb_time' amrita:type='erb'><![CDATA[ <small>It is <%= Time.now %> now </small> ]]></span> <hr /> <input id='text1' amrita:type='input' name='text1' type='text' /> <input id='cb1' amrita:type='checkbox' name='cb1' type='checkbox' /> <select id='sel1' amrita:type='select'> <option value='a'>aaa</option> <option value='b'>bbb</option> <option value='c'>ccc</option> </select> </body> </html> END table = [ ["Ruby", "http://www.ruby-lang.org/", "Matz" ], ["Perl", "http://www.perl.com/", "Larry Wall" ], ["Python", "http://www.python.org/", "Guido van Rossum" ] ] data = { :lang=>table, :link=>'http://amrita2.rubyforge.org/', :erb_time =>binding, :text1 => 'Input a text here', :cb1 => rand(2)%2 == 0, :sel1 => ARGV.shift || :a } tmpl = TemplateText.new(TEMPLATE_TEXT) tmpl.expand(STDOUT, data)output <html> <body> <table> <tr><th>name</th><th>author</th></tr> <tr> <td><a href='http://www.ruby-lang.org/'>Ruby</a></td><td>Matz</td> </tr><tr> <td><a href='http://www.perl.com/'>Perl</a></td><td>Larry Wall</td> </tr><tr> <td><a href='http://www.python.org/'>Python</a></td><td>Guido van Rossum</td> </tr> </table> <hr></hr> powered by <a href='http://amrita2.rubyforge.org/'>Amrita2</a> <br></br> <small>It is Mon Apr 11 16:12:57 JST 2005 now </small> <hr></hr> <input name='text1' type='text' value='Input a text here'/> <input name='cb1' type='checkbox'/> <select> <option selected='selected' value='a'>aaa</option> <option value='b'>bbb</option> <option value='c'>ccc</option> </select> </body> </html> |
--- ../sample/spec/erb.rb --- |
require "amrita2/template" include Amrita2 include Amrita2::Runtime # for amrita:type='erb' TEMPLATE_TEXT = <<END <html> <head> <span id='header_title' amrita:type='erb'><![CDATA[ <title><%= TITLE %></title> ]]></span> </head> <body> <span id='title' amrita:type='erb'><![CDATA[ <h1><%= TITLE + $_ %></h1> ]]></span> <table> <tr><th>name</th><th>author</th></tr> <span id='item' amrita:type='erb'><![CDATA[ <tr> <td><%= make_link($_[1], $_[0]) %></td> <td><%= $_[2] %></td> </tr> ]]></span> </table> <hr /> <br /> </body> </html> END table = [ ["Ruby", "http://www.ruby-lang.org/", "Matz" ], ["Perl", "http://www.perl.com/", "Larry Wall" ], ["Python", "http://www.python.org/", "Guido van Rossum" ] ] def make_link(url, text) "<a href='#{url}'>#{text}</a>" end TITLE='Amrita2 with ERB ' # get binding at the place where you can see 'make_link' and 'TITLE ' b = binding # and pass the binding to erb item data = { :header_title => b, :title => [b, ' Sample'], # pass an addtional args :item=> table.collect { |i| [b, i] } } tmpl = TemplateText.new(TEMPLATE_TEXT) tmpl.expand(STDOUT, data)output <html> <head> <title>Amrita2 with ERB </title> </head> <body> <h1>Amrita2 with ERB Sample</h1> <table> <tr><th>name</th><th>author</th></tr> <tr> <td><a href='http://www.ruby-lang.org/'>Ruby</a></td> <td>Matz</td> </tr> <tr> <td><a href='http://www.perl.com/'>Perl</a></td> <td>Larry Wall</td> </tr> <tr> <td><a href='http://www.python.org/'>Python</a></td> <td>Guido van Rossum</td> </tr> </table> <hr></hr> <br></br> </body> </html> |
Use amrita:type='erb' and put the partial ERB source in ![CDATA[.....]]. Because <% %> is not allowed in XML.
<span id='header_title' amrita:type='erb'><![CDATA[ <title><%= TITLE %></title> ]]></span> |
And pass a Binding Object to it.
TITLE='Amrita2 with ERB ' b = binding data = { :header_title => b, } |
Get the Binding at the place where all variables used in the ERB template are visible.
In this case, a constant 'TITLE' is used by the ERB source, so binding should be called where TITLE is visible.
You can pass a value to ERB element.
data = { :title => [b, ' Sample'], # pass an addtional args } |
The string ' Sample' will be assigned to $_ and you can use it in ERB source.
<span id='title' amrita:type='erb'><![CDATA[ <h1><%= TITLE + $_ %></h1> ]]></span> |
If you want to construct an element with a method like this,
def make_link(url, text) "<a href='#{url}'>#{text}</a>" end |
get the binding where you can use the method, and pass the data for it
data { :item => [binding, ["Ruby", "http://www.ruby-lang.org/", "Matz" ] ] } |
This data and method can be used in the ERB source
<span id='item' amrita:type='erb'><![CDATA[ <tr> <td><%= make_link($_[1], $_[0]) %></td> <td><%= $_[2] %></td> </tr> ]]></span> |
The result is
<tr> <td><a href='http://www.ruby-lang.org/'>Ruby</a></td> <td>Matz</td> </tr> |
You can make a table if you pass a array of pair of binding and data.
table = [ ["Ruby", "http://www.ruby-lang.org/", "Matz" ], ["Perl", "http://www.perl.com/", "Larry Wall" ], ["Python", "http://www.python.org/", "Guido van Rossum" ] ] b = binding data = { :item=> table.collect { |i| [b, i] } } |