Amrita2 quick start guide

Step 1: hello world

This is the 'hello world' for Amrita2.

sources

--- ../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>

output

<html>
  <body>
    <h1>hello world</h1>
    <p>Amrita2 is a html template library for Ruby</p>
  </body>
</html>

description

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

Step 2: passive PO method

Passive PO methods returns a value for template expansion. This sample describes how TO expand values.

sources

--- ../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)

output

<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>

Array expansion

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>

Nested Struct

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>

Array of Struct

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>

Step 3: active PO method

sources

--- ../sample/hello/step3.rb ---
require "amrita2/template"
include Amrita2

class PO
  def passive
    "passive PO method"
  end

  def active(m)
    m.active("active PO method can replace attrs", :href=>"http://www.ruby-lang.org/")
  end

  def active_with_proc
    proc do |m|
      m.active_with_proc("output in a Proc")
    end
  end

  def active_nest(m)
    m.active_nest do |mm|
      mm.nested("active PO method can ")
      mm.nested("call dynamic element method ")
      mm.nested("many times")
    end
  end
end

tmpl = TemplateText.new <<-END
<html>
   <body>
      <h1>passive method</h1>
      <span id='passive'> </span>
      <h1>active method</h1>
      <a id='active'> </a>
      <div id='active_with_proc'> </div>
      <h1>active nested</h1>
      <p id='active_nest'>
      <span id='nested' />
      </p>
   </body>
</html>
END

tmpl.expand(STDOUT, PO.new)

output

<html>
  <body>
     <h1>passive method</h1>
     <span>passive PO method</span>
     <h1>active method</h1>
     <a href='http://www.ruby-lang.org/'>active PO method can replace attrs</a>
     <div>output in a Proc</div>
     <h1>active nested</h1>
     <p>
     <span>active PO method can </span><span>call dynamic element method </span><span>many times</span>
     </p>
  </body>
</html>

active PO method

If a PO method has a parameter, it will be regarded as an active PO method to which TO passes a Module compiled from the template. The active PO method calls a method of it to produce an output.

def active(m)
  m.active("active PO method can replace attrs", :href=>"http://www.ruby-lang.org/")
end

Using this mechanisim, you can use many feature of Amrita2. Most usable one is setting an attribute.

<h1>active method</h1>
<a href='http://www.ruby-lang.org/'>active PO method can replace attrs</a>

active PO method for nested dynamic elements

If the element has inner structures

<h1>active nested</h1>
<p id='active_nest'>
<span id='nested' />
</p>

The active PO method should call the method of the template module with a Block.

def active_nest(m)
  m.active_nest do |mm|
    mm.nested("active PO method")
  end
end

Then another Module for inner element will be passed. You can call the methods for inner elements.

<h1>active nested</h1>
<p>
<span>active PO method</span>
</p>

call the active PO method many times

You can call the method of template module any times

def active_nest(m)
  m.active_nest do |mm|
    mm.nested("active PO method can ")
    mm.nested("call dynamic element method ")
    mm.nested("many times")
  end
end

Then output is

<h1>active nested</h1>
<p>
  <span>active PO method can </span>
  <span>call dynamic element method </span>
  <span>many times</span>
</p>

If you don't call the method in an active PO method, then there will be no output.

next step

using Template Spec

Reverse Engineering

JavaScript Template

Parts template