Company Logo Simplest html/xhtml template library for Ruby
現在の位置:
Amrita ホームページ > ドキュメント > 機能チュートリアル
To English

Amrita ツアー

HTML要素の属性を変更する

href="..." のような属性の値を変更する方法を説明します。

コード:

出力:

<table border="1">                                                    
  <tr>                                                                
  <th>name</th>                                                       
  <th>author</th>                                                     
  <th>webpage</th>                                                    
  </tr>                                                               
  <tr>                                                                
  <td>Ruby</td>                                                       
  <td>matz</td>                                                       
  <td><a href="http://www.ruby-lang.org/">Ruby Home Page</a></td>     
  </tr>                                                               
  <tr>                                                                
  <td>perl</td>                                                       
  <td>Larry Wall</td>                                                 
  <td><a href="http://www.perl.com/">Perl.com</a></td>                
  </tr>                                                               
  <tr>                                                                
  <td>python</td>                                                     
  <td>Guido van Rossum</td>                                           
  <td><a href="http://www.python.org/">Python Language Website</a></td>
  </tr>                                                               
</table>                                                              

説明

Amrita#a() というメソッドは Amrita::AttrArray という特別なオブジェクトを生成します。

a(:href=>"http://www.ruby-lang.org/") { "Ruby Home Page" },

このオブジェクトをモデルデータとして使用すると、HTML要素の属性が変更されます。 例えば、次のようなテンプレートにこのデータを与えたとすると

<td><a id="webpage"></a></td>

出力は次のようになります。

<td><a href="http://www.ruby-lang.org/">Ruby Home Page</a></td>     

docs/XML_ja で説明している filelist.rb というサンプルもAttrArrayを使用しています。

なお、属性の展開は別の方法もあります。詳しくは docs/Tour2の expand_attr を参照してください。

---

Procオブジェクト

モデルデータと+id+属性のマッチングというamrita独特の方法は、 シンプルで見通しのよいコードを可能にします。

しかし、そのような方法ではきれいに処理しきれないケースも稀には存在します。

Proc+ オブジェクトをモデルデータとして与えると、

手続き的にテンプレートを変更することができます。

コードと出力

コード:

include: sample/tour/proc.rb

出力:

<ul> 
  <li><font color="black">java</font> </li>
  <li><em><font color="red" size="big">I love Ruby!</font></em> </li>
  <li><font color="blue">perl</font> </li>
  ...
</ul>

説明

モデルデータとして Proc オブジェクトが渡されると、amrita は、 テンプレート展開時に、そのProc を呼び出します。 その際、パラメータとして、対応する +id+ のついたHTML要素を Amrita::Element オブジェクトとして 渡します。 そして、その Proc の結果とテンプレートを置き換えます。

この Proc の中で、次のようなメソッドを利用して自由にテンプレートを編集することができます。

属性値の設定

elem[:color] = "red" 

要素にテキストを設定する

elem.set_text("I love Ruby!")

Amrita#e メソッドによって、新しいHTML要素を生成する

e(:em) { elem } 

---

既存のクラスをモデルデータとして使用する

HashやArrayだけでなく、 既存のクラス(Rubyの標準クラスやユーザ作成のクラス)のオブジェクトを そのまま、amrita のモデルデータとして使用する例です。

コードと出力

コード:

include: sample/tour/time.rb

出力:

2002/7/17

説明

もし、モデルデータが、Amrita::ExpandByMember というモジュールをincludeしていたら、 amritaは +id+ 属性の値をメソッド名と見なして、そのメソッドを呼び出します。

このサンプルでは、+:time+に対応するデータは、Rubyの標準のTimeオブジェクトですが、 ExpandByMember モジュールを +extend+ しています。 それで +id+属性の値である +year+ をメソッド名とみなし、amritaは

t+ に対してそのメソッドの呼出しを行います。

その結果 <tt><span id="year"></span></tt> という部分は、 <tt>t.year</tt>の結果 "2002" と展開され、他の部分も同様に処理されて 次のように展開されます。

<span><span>2002</span>/<span>7</span>/<span>17</span></span>

amrita は 属性のない <tt><span></tt> 要素は削除しますので、最終的な出力は

2002/7/17

となります。

---

プリコンパイル

amrita は HTML テンプレートを Ruby のコードにコンパイルすることができます。

コードと出力

コード(table.rbにコンパイラを利用するために追加した分) :

tmpl = TemplateText.new(TEMPLATE)
tmpl.use_compiler = true
tmpl.set_hint_by_sample_data(data) # これを追加するとそのデータに最適化します
tmpl.expand(STDOUT, data)  #
puts "----code generated by Amrita -----------"
puts tmpl.src
puts "----code generated by Amrita end -------"

出力はtable.rbと同じですが、 コンパイラの出力したコードとベンチマークが追加されています。

私のCrusoe TM5600マシン(NEC Lavie MX)での出力は次のようになります。

43.068354 seconds for 1000 times without compiling
5.078764 seconds for 1000 times with pre-compiled code

説明

基本的には、次の処理を追加するだけでコンパイラを使用できます。

tmpl.use_compiler = true

これ以降、+expand+ はコンパイルされたRubyコードで実行されます。 prettyprintの機能はサポートされませんが、それ以外は同じ結果になります。

サンプルデータを利用して、最適化を行なうには次の処理を追加します。

And optionally give a sample data to amrita.

tmpl.set_hint_by_sample_data(data)

amritaのコンパイラは、このデータを出力するRubyコードの最適化のために使用します。 従って、渡すモデルデータの構造が変化したら、再度、その新しいデータで

set_hint_by_sample_data+ を呼ぶ必要があります。

amritaのコンパイラは、部分的にインタプリターモードを含めることができます。 部分的に構造が変化するデータに対して、コンパイラを利用する場合は、 サンプルデータの対応する部分(変化するデータの部分)に、+nil+ を渡す必要があります。

コンパイラは、Element::expandを使用するようなコードを対応する個所に挿入します。

このようにして、スピードと柔軟性のトレードオフを自由に取ることができます。

---

サニタイジン -- XSS(クロスサイトスクリプティング)対策

amritaには、XSS対策として、Amrita::Sanitizer というモジュールが組込まれています。 Amrita::Formatter は自動的にこのモジュールを使用します。

I will provide interface to controle sanitizer through Amrita::Template in future release.

コードと出力

include: sample/tour/sanitizer.rb

説明

テキスト

xhtml/html 内のテキストとして危険な文字、(<>&) は自動的にエスケープされます。

"<abc>" => "&lt;abc&gt;"

属性値

属性値として危険な文字(<>&"')は自動的にエスケープされます。

URL用属性の扱い

<a>要素のhref属性のように、URLを値として持つ属性値は、特別扱いされます。

どの属性値を特別扱いするかの詳細については tag.rb を参照してください。

これらの属性値は、次のようにさらに厳しくチェックされます。

この条件に違反したら、属性値はnilで置きかえられて<tt><a href="">....</a></tt> のように表示されます。

次のように+setup_taginfo+ メソッドを再定義することで、 どの属性をこのように扱うか(扱わないか)をカスタマイズすることができます。

t = TemplateFile.new ...

def t.setup_taginfo
  ret = TagInfo.new
  ret[:aaa].set_url_attr(:bbb)
  ret
end

この場合は、 +aaa+要素の+bbb+属性は、URLとしてサニタイズされます。

サニタイズを無効にする

Amrita::SanitizedString オブジェクトをモデルデータに含めることで、 この機能を無効にすることができます。

t = TemplateText.new '<p id="a">sample_text</p>'
t.expand(STDOUT, { :a=>"<xxx>" })                  # => <p>&lt;xxx&gt;</p>
t.expand(result, { :a=>SanitizedString["<xxx>"] }) # => <p><xxx></p>

この機能は、XSSについて理解した上で、充分注意して利用してください。

なお、もうひとつ同様の効果を得る方法として、<tt>escape {...} </tt> で モデルデータを囲むという方法もあります。