= Amrita ツアー
== HTML要素の属性を変更する
href="..." のような属性の値を変更する方法を説明します。
コード:
:include: sample/tour/makeurl.rb
出力:
=== 説明
Amrita#a() というメソッドは Amrita::AttrArray という特別なオブジェクトを生成します。
a(:href=>"http://www.ruby-lang.org/") { "Ruby Home Page" },
このオブジェクトをモデルデータとして使用すると、HTML要素の属性が変更されます。
例えば、次のようなテンプレートにこのデータを与えたとすると
|
出力は次のようになります。
Ruby Home Page |
docs/XML_ja で説明している filelist.rb というサンプルもAttrArrayを使用しています。
なお、属性の展開は別の方法もあります。詳しくは docs/Tour2の expand_attr を参照してください。
---
== Procオブジェクト
モデルデータと+id+属性のマッチングというamrita独特の方法は、
シンプルで見通しのよいコードを可能にします。
しかし、そのような方法ではきれいに処理しきれないケースも稀には存在します。
+Proc+ オブジェクトをモデルデータとして与えると、
手続き的にテンプレートを変更することができます。
=== コードと出力
コード:
:include: sample/tour/proc.rb
出力:
- java
- I love Ruby!
- perl
...
=== 説明
モデルデータとして 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+ に対してそのメソッドの呼出しを行います。
その結果 という部分は、
t.yearの結果 "2002" と展開され、他の部分も同様に処理されて
次のように展開されます。
2002/7/17
amrita は 属性のない 要素は削除しますので、最終的な出力は
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>"
==== 属性値
属性値として危険な文字(<>&"')は自動的にエスケープされます。
==== URL用属性の扱い
要素のhref属性のように、URLを値として持つ属性値は、特別扱いされます。
どの属性値を特別扱いするかの詳細については tag.rb を参照してください。
これらの属性値は、次のようにさらに厳しくチェックされます。
* これらの属性値はURLとして許されない文字を持つことはできません
* これらの属性値は許されないスキーム(プロトコル指定)を持つことはできません
この条件に違反したら、属性値はnilで置きかえられて....
のように表示されます。
次のように+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 'sample_text
'
t.expand(STDOUT, { :a=>"" }) # => <xxx>
t.expand(result, { :a=>SanitizedString[""] }) # =>
この機能は、XSSについて理解した上で、充分注意して利用してください。
なお、もうひとつ同様の効果を得る方法として、escape {...} で
モデルデータを囲むという方法もあります。
---