active PO method

the internal structure of Amrita2

compiled module

Amrita2 compiles HTML template to Ruby module.

This is the compiled Ruby code from sample/hello.rb and will be evaluated in a Module.

extend Amrita2::Runtime
def self.expand_template(out,&block)
  new_context(out) do
    block.call(MainContext) if block_given? 
    get_mainstream << "<html>\n   <body>\n      "
    output_substream(:title)
    get_mainstream << "\n      "
    output_substream(:body)
    get_mainstream << "\n   </body>\n</html>\n\n"
  end
end

module MainContext
  extend Amrita2::Runtime
  def title(val=nil,attrs={},&amp;block)
    attrs = val if val.kind_of?(Hash)
    new_context(get_substream(:title)) do
      if val == true
        get_mainstream << "<h1 id='title'>title will be inserted here</h1>"
      else
        if attrs.size == 0
          get_mainstream << "<h1>"
          get_mainstream << val.amrita_sanitize
          get_mainstream << "</h1>"
        else
          a = { }
          attrs.each do |k,v|
            a[k] = v
          end
          e = new_element("h1", a)
          e.delete_attribute("id")
          get_mainstream << start_tag(e)
          get_mainstream << val.amrita_sanitize
          get_mainstream << end_tag(e)
        end
      end
    end
  end
  module_function :title

  def body(val=nil,attrs={},&amp;block)
    attrs = val if val.kind_of?(Hash)
    new_context(get_substream(:body)) do
      # same as the 'title' method above
    end
  end
  module_function :body
end

Expander object

When a PO was given, an Expander object will be generated from Template Spec. And the Expander object will generate HTML output using the TO module.

There are many Expander object classes. The selection of Expander class and compiled result of Ruby TO module will be controled by Template Spec.

active PO method

You can controle the Ruby code with Specs and Expander, but there is always an overhead of Expander because the Expander does not know the type of the PO data so it must check the type of it and select the usage of the module

If you want to pass the overhead of Expander, you can use the TO module direct.

This is good when the speed or detailed controle of usage of the TO module was needed.

We call it 'active PO method'.

sources

--- ../sample/hello/step4.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.