= Amrita ツアー == HTML要素の属性を変更する href="..." のような属性の値を変更する方法を説明します。 コード: :include: sample/tour/makeurl.rb 出力:
name author webpage
Ruby matz Ruby Home Page
perl Larry Wall Perl.com
python Guido van Rossum Python Language Website
=== 説明 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 出力: === 説明 モデルデータとして 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 {...} で モデルデータを囲むという方法もあります。 ---