= Tempura - リファレンスマニュアル

== テンプレートの書式

Tempuraのテンプレートは、REXMLでパース可能なXML形式のテキストとして表
現します。テンプレートは、(({REXML::Document.new}))に第一引数としてそ
のまま渡されます。いくつかのXML属性とその値がTempuraの処理に利用されま
す。


=== XML属性

* _nil_       : XML要素を削除
* _child_     : XML要素の内容を属性値の評価結果で置換
* _self_      : XML要素自体を属性値の評価結果で置換
* _child_xml_ : XML要素の内容を属性値の評価結果をREXMLパースしたもので置換
* _self_xml_  : XML要素自体を属性値の評価結果をREXMLパースしたもので置換
* _attr_*     : (接頭辞) XML属性とその値を置換
* _block_     : XML要素をブロックが呼ばれた回数分複製
* _event_     : aおよびform要素を「ユーザによるイベント」として変更
* _action_    : aおよびform要素において、_event_の送信先を変更
* _if_        : 属性値の評価結果が偽ならXML要素自体を削除 (暫定的に実装)
* _unless_    : 属性値の評価結果が真ならXML要素自体を削除 (暫定的に実装)

以上のXML属性がTempuraによる展開の結果に影響を与えます。これらのXML属
性自身は、Tempuraによる展開の出力結果からは削除されます。

以降、各XML属性の仕様を説明します。

:_nil_

  この属性を持つXML要素をまるごと削除します。XMLの仕様上、属性値を省略
  することはできませんが、値は無視されます。  XHTMLをプレビューするとき
  などに、ダミーのXML要素を置くのに使うことができます。

  例 (展開前):

      <ul>
        <li>天丼</li>
        <li>天ざる</li>
        <li _nil_="">(すきやき)</li>
      </ul>

  例 (展開後):

      <ul>
        <li>天丼</li>
        <li>天ざる</li>
      </ul>

:_child_

  この属性を持つXML要素の内容を、属性値を評価した結果で置き換えます。
  属性値は、Rubyスクリプトとして実行時に指定された環境(binding)で評価
  されます。ただし例外として、((<_block_>))属性の影響下にあるときには、
  ブロックの環境で評価されます。

  ((<_self_>))がXML要素自体をまるごと置き換えるのに対して、_child_では、
  XML要素の内容を置き換えます。

  評価の結果が:

    * nilだった場合、このXML要素自体を削除します。
    * falseだった場合、何もしません。
    * REXML::Childのインスタンスだった場合、そのまま置き換えます。
    * その他のオブジェクトの場合、to_sで文字列にしてテキスト要素として置
      き換えます。

  例 (展開前):

      <p _child_="Time.now">current time</p>

  例 (展開後):

      <p>Wed Sep 17 17:47:35 JST 2003</p>

:_self_

  この属性を持つXML要素自体を、属性値を評価した結果で置き換えます。属
  性値は、実行時に指定された環境(binding)でRubyスクリプトとして評価さ
  れます。ただし例外として、((<_block_>))属性の影響下にあるときには、
  ブロックの環境で評価されます。

  ((<_child_>))がXML要素自体ではなく内容を変更するのに対して、_self_で
  は、XML要素自体を置き換えます。

  評価の結果が:

    * nilだった場合、このXML要素自体を削除します。
    * falseだった場合、何もしません。
    * REXML::Childのインスタンスだった場合、そのまま置き換えます。
    * その他のオブジェクトの場合、to_sで文字列にしてテキスト要素として置
      き換えます。

  例 (展開前):

      <p _self_="Time.now">current time</p>

  例 (展開後):

      Wed Sep 17 17:47:35 JST 2003

:_child_xml_, _self_xml_

  それぞれ_child_、_self_と基本的には同じです。しかし、評価の結果が、
  nil・false・REXML::Childのインスタンスのいずれでもないとき(その他の
  オブジェクトの場合)の振舞いが異なります。

    * nilだった場合、このXML要素自体を削除します。
    * falseだった場合、何もしません。
    * REXML::Childのインスタンスだった場合、そのまま置き換えられます。

  ここまでは、それぞれ_child_、_self_と同じですが

    * その他のオブジェクトの場合、to_sで文字列にした評価結果をREXMLでパー
      スした結果で置き換えます。

  となります。

  _child_と_self_では、文字列に変換した評価結果がXML形式であろうがなか
  ろうが、まるごとテキスト要素として扱われます。

  それに対して、_ child_xml_と_self_xml_では、文字列に変換した評価結果
  をREXMLで一度パースします。したがってXML形式の文字列はREXML::Childの
  インスタンスとして扱われることになります。

  この_xml_という接尾辞がつくXML属性は、評価結果がXML形式の文字列を返
  すことが想定される場合、それを文字列でなくXML部品として扱いたいとき
  に使います。具体的には、XMLで書かれたTempura::Divテンプレートの中に、
  Div標準のErbで書かれたDiv::Divテンプレートを埋め込むときなどに使います。

  以下に、(({ @erbdiv.to_div(context)}))を評価した結果が
  (({"<div>hello</div>" }))という文字列を返す場合の、_xml_接尾辞の有無
  による結果の違いを例示します。

  * 例 - _xml_有 (展開前):

      <body _child_xml_="@erbdiv.to_div(context)">hoge</body>
      <body _self_xml_="@erbdiv.to_div(context)">hoge</body>

  * 例 - _xml_有 (展開後):

      <body><div>hello</div></body>
      <div>hello</div>

  * 例 - _xml_無 (展開前):

      <body _child_="@erbdiv.to_div(context)">hoge</body>
      <body _self_="@erbdiv.to_div(context)">hoge</body>

  * 例 - _xml_無 (展開後):

      <body>&lt;div&gt;hello&lt;/div&gt;</body>
      &lt;div&gt;hello&lt;/div&gt;

  この結果から、ErbによるDiv::Divを埋め込む場合には、
  _child_xml_や_self_xml_の方が役に立つだろうことが推測できるでしょうか。

:_attr_* (名前が_attr_で始まるXML属性)

  この属性を持つXML要素の指定された属性を、属性値を評価した結果を文字
  列化したもので、置き換えます。_attr_*属性名の_attr_ を取り除いたもの
  が変更される属性(ターゲット属性)の名前になります。

  属性値は、実行時に指定された環境(binding)でRubyスクリプトとして評価
  されます。ただし例外として、((<_block_>))属性の影響下にあるときには、
  ブロックの環境で評価されます。評価の結果により、以下のようにターゲッ
  ト属性を変更します。

    * nilだった場合、ターゲット属性自体を削除
    * falseだった場合、何もしません
    * それ以外の場合、ターゲット属性の値を評価結果を文字列にしたもので置換

  例 (展開前):

      <p _attr_time="Time.now">hello world</p>

      <option _attr_selected="nil" selected="true"/>
      <option _attr_selected="false" selected="true"/>
      <option _attr_selected="%(false)" selected=="true"/>
      <option _attr_selected="true"/>
      <option _attr_selected="%(true)"/>

  例 (展開後):

      <p time="Wed Sep 17 17:47:35 JST 2003">hello world</p>

      <option/>
      <option selected="true"/>
      <option selected=="false"/>
      <option selected="true"/>
      <option selected="true"/>


:_block_

  この属性を持つXML要素を、特定書式の属性値の内容にしたがって、複製し
  ます。属性値はつぎの書式で記述します。

    _block_属性値 := Rubyスクリプト片 '//' ブロックメソッド名 '//' ブロック引数リスト

  Rubyスクリプト片の評価結果に対して、ブロックメソッドが呼ばれます。ブ
  ロックが呼ばれた回数だけXML要素が複製されます。複製されたXML要素は、
  ブロックの環境(binding)でTempura展開されます。

  例1 (展開前):

      <li _block_="1..3//each//i" _child_="i">(will be replaced)</li>

  例1 (展開後):

      <li>1</li><li>2</li><li>3</li>

  例2 (展開前):

      <tr _block_="{:aaa=>111,:bbb=>222,:ccc=>333}//each//key,val">
        <td class="key" _child_="key">(key)</td>
        <td class="val" _child_="val">(val)</td>
      </tr>

  例1 (展開後):

      <tr>
        <td class="key">aaa</td>
        <td class="val">111</td>
      </tr><tr>
        <td class="key">bbb</td>
        <td class="val">222</td>
      </tr><tr>
        <td class="key">ccc</td>
        <td class="val">333</td>
      </tr>

:_event_

  この属性を持つXML要素の名前が"a"または"form"の場合に、その要素をユー
  ザのWEBアプリケーションに対する操作として扱い、特定書式の属性値の内
  容にしたがって変更します。その他の要素の場合には何もしません。属性値
  はつぎの書式で指定します。

    _event_属性値 := イベント名 [ パラメータ ]*
    パラメータ    := '//' キー '==>' 値

  例1 - form要素 (展開前):

      <form method="POST" _event_="add">
        name: <input type="text" name="name"/>
        age : <input type="text" name="age"/>
        <input type="submit" value="add"/>
      </form>

  例1 -form要素 (展開後):

      <form method="POST" action="myapp.cgi"><input type="hidden" name="event" value="hello"/>
        item : <input type="text" name="item"/>
        price: <input type="text" name="price"/>
        <input type="submit" value="add"/>
      </form>

  例2 - a要素 (展開前):

      <a href="dummy" _event_="add//item==>%(tenzaru)//price==>9//time==>Time.now.to_i">add tenzaru</a>

  例2 -a要素 (展開後):

      <a href="myapp.cgi?event=add;item=tenzaru;price=9;time=1064208436">add tenzaru</a>

  例3 - Div (展開前):

      <form method="POST" _event_="add">
        name: <input type="text" name="name"/>
        age : <input type="text" name="age"/>
        <input type="submit" value="add"/>
      </form>

  例3 -Div (展開後):

      <form method="POST" action="/div">
          <input name='div_id' type='hidden' value='123456789'/>
          <input name='div_cmd' type='hidden' value='add'/>
        item : <input type="text" name="item"/>
        price: <input type="text" name="price"/>
        <input type="submit" value="add"/>
      </form>

:_action_

  この属性は、((<_event_>))属性と組み合わせて使うためのもので、aおよび
  form要素のイベントの送信先を変更します。

  この属性を持つXML要素が、"a"または"form"という名前で、かつ
  ((<_event_>))属性を持っている場合に、((<_event_>))によって展開される
  action名が、この属性の値に置き換えられます。テンプレート展開後のform 
  要素のaction属性、もしくはa要素のhref属性の値に影響します。この属性
  による置き換えは、最優先されます。

  例1 - form要素 (展開前):

      <form method="POST" _event_="hello" action="dummy.cgi" _action_="alt.cgi">
      </form>

  例1 -form要素 (展開後):

      <form method="POST" action="alt.cgi"><input type="hidden" name="event" value="hello"/>
      </form>

  例2 - a要素 (展開前):

      <a href="dummy.cgi" _action_="alt.cgi" _event_="hello">hello</a>

  例2 -a要素 (展開後):

      <a href="alt.cgi?event=hello">hello</a>


== 文字コード変換器

Tempuraテンプレートにはそれぞれ文字コード変換器を指定することができま
す。Tempura内部では、文字コードをUTF-8で扱います。UTF-8以外の文字コー
ドで記述されたテンプレートを使うためには、その文字コードとUTF-8を相互
に変換するための文字コード変換器を指定する必要があります。

文字コード変換器は、つぎの２つのインスタンスメソッドを備えた任意のオブ
ジェクトです。

--- 文字コード変換器#to_u8(str)

    文字列をUTF-8文字列に変換して返す。

--- 文字コード変換器#from_u8(str)

    UTF-8文字列を8文字列に変換して返す。

あらかじめ以下の文字コード変換器が定義されています。

: Tempura::CharConvDefault
  何もしない変換器。デフォルト。

: Tempura::CharConvEUC
  EUC-JPのための変換器。

: Tempura::CharConvSJIS
  ShiftJISのための変換器。


== クラス

=== Tempura::Templateクラス

複数のTempuraテンプレートと１つのTempura展開器を包むオブジェクトを定義
するクラスです。選択されたテンプレートを引数として与えられたデータで展
開する機能を持っています。Tempuraを典型的なテンプレートライブラリとし
て使う場合、通常はこのクラスのインスタンスを生成して使います。

このクラスのインスタンスは、デフォルトテンプレートを含む複数のテンプレー
トを持つことができます。各テンプレートは特定のキーオブジェクトと関連づ
けられます。展開時に、与えられたキーに関連づけられたテンプレートが見つ
からない場合は、デフォルトテンプレートが使用されます。

各テンプレートはそれぞれ関連する文字コード変換器を持つことができます。

==== ロード:

(({ require 'tempura/template' }))

==== クラスメソッド:

--- Tempura::Template.new([path, charconv, safe_level])

    Tempura::Templateオブジェクトを生成します。((|path|))には、デフォ
    ルトテンプレートを記述したファイルへのパスを指定します。
    ((|charconv|))には((<文字コード変換器>))を指定します。
    ((|safe_level|))はテンプレートを展開するときの$SAFEの値を指定しま
    す。

--- Tempura::Template.new_with_string(str[, charconv, safe_level])

    Tempura::Templateオブジェクトを生成します。((|str|))には、デフォル
    トテンプレートを記述した文字列を指定します。((|charconv|))には
    ((<文字コード変換器>))を指定します。((|safe_level|))はテンプレート
    を展開するときの$SAFEの値を指定します。

==== メソッド:

--- Tempura::Template#default_action

    _event_属性を展開するときにaction属性の値とする文字列を返します。
    デフォルトは空文字列""です。この値は、テンプレート展開後のform要素
    のaction属性、もしくはa要素のhref属性の値に、影響します。

--- Tempura::Template#default_action=(str)

    _event_属性を展開するときに、action属性の値とする文字列を設定しま
    す。この値は、テンプレート展開後のform要素のaction属性、もしくはa 
    要素のhref属性の値に、影響します。

    (({ default_action = "myapp.cgi" })) のとき

      <form  method="POST" _event_="hello">
      ...
      </form>
      <a href="dummy" _event_="hello">hello</a>

    の展開結果は

      <form method="POST" action="myapp.cgi"><input type="hidden" name="event" value="hello"/>
      ...
      </form>
      <a href="myapp.cgi?event=hello">hello</a>

    となります。

--- Tempura::Template#default_event_key

    _event_属性を展開するときに、eventを表すキー文字列として展開する文
    字列を返します。デフォルトは"event"です。

--- Tempura::Template#default_event_key=(val)

    _event_属性を展開するときに、eventを表すキー文字列として展開する文
    字列を設定します。

    (({ default_event_key = "mycmd" })) のとき

      <form  method="POST" _event_="hello">
      ...
      </form>
      <a href="dummy" _event_="hello">hello</a>

    の展開結果は

      <form method="POST" action=""><input type="hidden" name="mycmd" value="hello"/>
      ...
      </form>
      <a href="?mycmd=hello">hello</a>

    となります。


--- Tempura::Template#set(path[, key, charconv])

    ((|path|))で指定されたファイルの内容を、((|key|))と関連づけられた
    テンプレートとして設定します。((|key|))が省略された場合はデフォル
    トテンプレートとなります。((|charconv|))には((<文字コード変換器>))
    を指定します。

--- Tempura::Template#set_with_string(str[, key, charconv])

    ((|str|))で指定された文字列を、((|key|))と関連づけられたテンプレー
    トとして設定します。((|key|))が省略された場合はデフォルトテンプレー
    トとなります。((|charconv|))には((<文字コード変換器>))を指定します。

--- Tempura::Template#expand(model[, key])

    ((|model|))と関連付けられた環境(binding)で、((|key|))と関連付けら
    れたテンプレートを展開し、結果を文字列として返します。((|key|))が
    省略された場合はデフォルトテンプレートを展開します。

    ((|model|))が

    :Bindingインスタンスの場合
      テンプレートはその環境(binding)で評価されます

    :その他のインスタンスの場合
      テンプレートはインスタンスの環境(binding)で評価されます

--- Tempura::Template#expand_to_document(model[, key])

    ((|model|))と関連付けられた環境(binding)で、((|key|))と関連付けら
    れたテンプレートを展開し、結果をREXML::Documentインスタンスとして
    返します。((|key|))が省略された場合はデフォルトテンプレートを展開
    します。


=== Tempura::Divクラス

テンプレートにTempuraテンプレートを使うDiv::Divの派生クラスです。Divに
ついては
((<Divのウェブサイト|URL:http://raa.ruby-lang.org/list.rhtml?name=div>))
などを参照してください。

==== スーパークラス:

Div::Div

==== ロード:

(({ require 'tempura/div' }))

==== クラスメソッド:

--- Tempura::Div.new(session)

    Tempura::Divオブジェクトを生成します。

--- Tempura::Div.set_template(path[, key, charconv])

    ((|path|))で指定されたファイルの内容を、((|key|))と関連づけられた
    テンプレートとして設定します。((|key|))が省略された場合はデフォル
    トテンプレートとなります。((|charconv|))には((<文字コード変換器>))
    を指定します。

--- Tempura::Div.set_safe_level(safe_level)

    テンプレートを展開するときの$SAFEの値を指定します。

--- Tempura::Div.reload_template

    テンプレートをファイルから再読み込みします。

==== メソッド:

--- Tempura::Div#select_template(key)

    与えられたキーと関連付けられたテンプレートをデフォルトテンプレート
    にします。

--- Tempura::Div#to_html_document([context, key])

    レシーバインスタンスの環境(binding)で、((|key|))と関連付けられたテ
    ンプレートを展開し、結果をREXML::Documentインスタンスとして返しま
    す。((|key|))が省略された場合はデフォルトテンプレートを展開します。
    Erbで書かれたDivテンプレートの中から呼ぶ場合は、このメソッドでなく、
    文字列を返すバージョンの((<Tempura::Div#to_html>))を呼ぶべきです。

--- Tempura::Div#to_html([context, key])

    レシーバインスタンスの環境(binding)で、((|key|))と関連付けられたテ
    ンプレートを展開し、結果を文字列として返します。((|key|))が省略さ
    れた場合はデフォルトテンプレートを展開します。Tempuraテンプレート
    で書かれたDivテンプレートの中から呼ぶ場合は、このメソッドでなく、
    REXML::Documentインスタンスを返すバージョンの
    ((<Tempura::Div#to_html_document>)) を呼ぶ方が効率的です。

--- Tempura::Div#to_div_document([context, key])
--- Tempura::Div#to_div([context, key])

=== Tempura::Expanderクラス

Tempuraテンプレート展開器を定義するクラスです。このクラスが、Tempuraの
核心部といえます。とくにカスタマイズなどをする必要がなければ、通常はこ
のクラスを直接扱う必要はありません。

==== ロード:

(({ require 'tempura/expander' }))

==== クラスメソッド:

--- Tempura::Expander.pre_expand(rexml_element[, bang_p])
--- Tempura::Expander.new([safe_level])

==== メソッド:

--- Tempura::Expander#safe_level
--- Tempura::Expander#pre_expand(rexml_element[, bang_p])
--- Tempura::Expander#expand(context, rexml_element, charconv[, bang_p])
--- Tempura::Expander#expand_to_string(context, rexml_element, charconv[, bang_p])
--- Tempura::Expander#default_action
--- Tempura::Expander#default_action=(action)
--- Tempura::Expander#default_event_key
--- Tempura::Expander#default_event_key=(event_key)
--- Tempura::Expander#param_filter(&proc)
--- Tempura::Expander#action_filter(&proc)


=== Tempura::SourceContainerクラス

Tempuraテンプレートソース(Tempura::Sourceインスタンス)のコンテナを定義
するクラスです。各テンプレートはキーオブジェクトと関連付けられて管理さ
れます。通常はこのクラスを直接扱う必要はありません。

==== ロード:

(({ require 'tempura/source_container' }))

==== クラスメソッド:


--- Tempura::SourceContainer.new

==== メソッド:

--- Tempura::SourceContainer#[](key)
--- Tempura::SourceContainer#[]=(key,val)
--- Tempura::SourceContainer#default
--- Tempura::SourceContainer#default=(val)
--- Tempura::SourceContainer#set(key, path[, charconv])
--- Tempura::SourceContainer#set_as_string(key, string[, charconv])
--- Tempura::SourceContainer#reload


=== Tempura::Sourceクラス

REXML::Documentインスタンスと関連する文字コード変換器を包むオブジェク
トを表現するクラスです。通常はこのクラスを直接扱う必要はありません。

==== ロード:

(({ require 'tempura/source' }))

==== クラスメソッド:

--- Tempura::Source.new_with_string(str[, charconv])
--- Tempura::Source.new(path[, charconv])

==== メソッド:

--- Tempura::Source#path
--- Tempura::Source#charconv
--- Tempura::Source#name
--- Tempura::Source#name=(val)
--- Tempura::Source#reload
--- Tempura::Source#fetch_document
