amrita2 README for 1.0 users 和訳+α

amrita2のREADME_FOR_1.0_USERSを少しだけアップデートしたので、ついでに日本語に訳してみました。(なんだかバタくさくて、テレビショッピングのような日本語だ)

ブツは前と同じくこちら

概略

amrita2 は二種類のAPIをサポートします。

  • アクティブレンプレートAPI(これは基本的にはamrita 1.0.x互換)
  • パッシブテンプレートAPI(柔軟性に富んだ新しいAPI)

アクティブレンプレートAPI

テンプレート

 <html>
<body>
<h1 id='title'>title will be inserted here</h1>
<p id='body'>body text will be inserted here</p>
</body>
</html>

コード

 require "amrita2/template"
include Amrita2
tmpl = TemplateFile.new("template.html")
data = {
:title => "hello world",
:body => "Amrita is a html template libraly for Ruby"
}
tmpl.expand(STDOUT, data)

結果

 <html>
<body>
<h1>hello world</h1>
<p>Amrita is a html template libraly for Ruby</p>
</body>
</html>

パッシブテンプレートAPI(柔軟性に富んだ新しいAPI)

 require "amrita2/template"
include Amrita2
tmpl = TemplateFile.new("template.html")
tmpl.expand(STDOUT) do |m|
# amrita2 はテンプレートをRubyのModuleにコンパイルして
# それを渡します。このModuleには、動的なエレメントに
# 対応したメソッドが含まれています
m.title("hello world")
m.body("Amrita is a html template libraly for Ruby")
end

結果は上記のサンプルと同じです。

ハイライト

これらのコードはユニットテストからの抜粋です。ですから、現在、実際に動いているものです。概要としては複雑すぎるものもありますがご了承ください。

テンプレートスペック

パッシブAPIでは、テンプレートスペックなるものを使用できます。これによって、(内部で行なわれている)HTMLからRubyへのコンパイルを制御できます。

     # template spec
spec = Amrita2::define_tempalte_spec do
dynamic_element(:aaa)
end
# XML document
doc = REXML::Document.new "<x id='aaa'>111</x>"
# create template object from spec and document
t = spec.create_template(doc)
# use template
out = ""
t.expand_template(out) do |m|
m.aaa('hello amrita2')
end
assert_equal("<x id='aaa'>hello amrita2</x>", out)
属性

:replace_attrというフラグをONにすると、任意のエレメントの属性値を変更できるようになります。

     spec = Amrita2::define_tempalte_spec do 
# With :replace_attr option on, you can control attributes of
# element with id 'aaa'
dynamic_element(:aaa, :replace_attr=>true)
end
doc = REXML::Document.new "<a id='aaa' class='abc'><b id='bbb'>xxx</b></a>"
t = spec.create_template(doc)
out = ""
t.expand_template(out) do |m|
# set attribute value
m.aaa(:class=>'xyz') do |m2|
m2.bbb('yyy')
end
end
assert_equal("<a class='xyz' id='aaa'><b id='bbb'>yyy</b></a>", out)
テンプレート上の値に文字列を追加する

:use_original_elementによって、テンプレート内に含まれるURLや文字列をコードから使用することができます。テンプレート内のアドレスにパラメータを加えて完全なアドレスとすること等が簡単にできます。

     spec = Amrita2::define_tempalte_spec do 
dynamic_element(:link, :use_original_element=>true)
end
doc = REXML::Document.new "<p>See <a id='link' href='http://www.ruby-lang.org/'>Ruby for detail</p>"
t = spec.create_template(doc)
t.expand_template(out="") do |m|
m.link('Ruby homepage')
end
assert_equal("<p>See <a href='http://www.ruby-lang.org/' id='link'>Ruby homepage</a> for detail</p>", out)
t.expand_template(out="") do |m|
m.link do |e|
# e は REXML::Element オブジェクトです。
# REXMLのAPIによって操作できます。
e.attributes["href"] += 'ja/'
e.attributes.delete("id")
e.text += '(Japanese)'
e
end
end
assert_equal("<p>See <a href='http://www.ruby-lang.org/ja/'>Ruby(Japanese) for detail</p>", out)
テーブルの処理

amrita2はテーブルの処理に関して、amrita 1.0.Xよりうまく処理できます。

amrita2では、テーブルの奇数行と偶数行に交互に違うテンプレートを使うことが、自動的に行なえます。

 tmpl = REXML::Document.new <<END
<table border='1'>
<tr><th></th><th></th></tr>
<tr class='detail1'><td></td><td></td></tr>
<tr class='detail2'><td></td><td></td></tr>
</table>
END

スペック上の:match_manyというオプションが鍵です。

 include HtmlTag
spec = Amrita2::define_tempalte_spec(:direct_define=>true) {
table(:matcher=>TABLE) {
header(:matcher=>TR) {
item1(:matcher=>TH)
item2(:matcher=>TH)
}
# the element 'detail' is suposed to match two 'TR' element
# of template with :match_many option
detail(:matcher=>TR, :match_many=>true) {
name(:matcher=>TD)
author(:matcher=>TD)
}
}
}

ロジック

 data = [
[ "Ruby", "matz" ],
[ "perl", "Larry Wall" ],
[ "python", "Guido van Rossum" ]
]
spec.create_template(tmpl).expand_template(STDOUT) do |m|
m.table do |mt|
mt.header do |mh|
mh.item1('name')
mh.item2('author')
end
data.each_with_index do |data, i|
# (i%2)番目の TR エレメントを出力します。
mt.detail(i) do |md|
md.name(data[0])
md.author(data[1])
end
# もし、テンプレートに三つのTRエレメントが存在していたら、
# このコードが一切の変更なしで、(i%3)番目の行を出力します
end
end
end

結果はこうなります。

 <table border='1'>
<tr><th>name</th><th>author</th></tr>
<tr class='detail1'><td>Ruby</td><td>matz</td></tr>
<tr class='detail2'><td>perl</td><td>Larry Wall</td></tr>
<tr class='detail1'><td>python</td><td>Guido van Rossum</td></tr>
</table>
ロジックをテンプレートなしでテストし、プレゼンテーションをロジックなしで作成する

テンプレートスペックがあれば、HTMLテンプレートが正しく作成されているか、検証することができます。ですから、スペックを書いてそれをデザイナーに渡してしまえば、デザイナーは自由に美しい画面をデザインすることができます。彼がするべきことは、テンプレートスペックでそれを検証することだけです。

そして、もしあなたにプログラミングを手伝ってくれる人がいたら、その人にロジックの作成を依頼できます。プログラマーは、スペックだけでテンプレートなしでもユニットテストを実行することができます。

     require 'amrita2/test'
spec = Amrita2::define_tempalte_spec do
dynamic_element(:aaa)
end
# create dummy template object from spec without template.
t = spec.create_dummy_template
# the behavior of dummy template is same as real one.
t.expand_template(nil) do |m|
m.aaa('123')
end
# dummy template remembers values assigned to it.
# You can test it
assert_equal('123', t[:aaa])

これによって、プログラマーとデザイナーは並行して作業できます。あなたは「俺の書いたテンプレートスペックでチェックしておけよ」とだけ言っておけばいいのです。それだけで、ロジックとプレゼンテーションはうまく協調して動くでしょう。