Modifierもどきを実装

DHHのアドバイスに従い、Smarty修正子(Modifier)もどきを実装してみた。ついでに、動的要素を示す属性の既定値をidからamrita:srcに変更。

t = TemplateText.new %[<x amrita:src='time|DateFormat["%Y-%m-%d %H:%M"]' />]
t.expand(out="", :time=>Time.local(2006,6,19,22,30))
assert_equal("<x>2006-06-19 22:30</x>", out)

DateFormat["%Y-%m-%d %H:%M"]というのがModifierの例。システムで単純なものをいくつか用意するが、実装は次のように単純なので、簡単に追加できる。

    class DateFormat < Amrita2::Modifier::Base
      def initialize(format)
        @format = format
      end

      def do_filter_data(data)
        data.strftime(@format)
      end
    end

複数の修飾子を並べて、順に適用させることもできる。(UNIXのパイプのイメージ?)

t = TemplateText.new %[<x amrita:src='time | Default[Time.local(2006,6,19)] | DateFormat["%m-%d"]' />]
time1 = Time.local(2006,6,17)
time2 = Time.local(2006,6,18)
t.expand(out="", :time=>[time1, time2 ,nil])
assert_equal("<x>06-17</x><x>06-18</x><x>06-19</x>", out)

Defaultは、値がnilの時に、ここで指定した値と入れかえるModifier。

この記述方式に、amrita:type という、出力形式を変更するオプションの指定も統合する予定。

tmpl = TemplateText.new "<a amrita:src='a2|Link'>Amrita2</a>"
data = {
  :a2 => 'http://amrita2.rubyforge.org/',
}
tmpl.expand(out="", data)
assert_equal("<a href='http://amrita2.rubyforge.org/'>Amrita2</a>", out)

これは、前の書き方で言うと

"<a amrita:src='a2' amrita:type='link'>Amrita2</a>"

に相当する。今の時点では、amrita:typeというオプションは廃止して、この方式で統一しようと思っている。これの実装は次のようになっていて、

    class Link < Base
      def set_option(opt)
        super
        opt[:link_attr] = [:href, [/javascript:.*/]]
      end
    end

自作するにはopt[:link_attr]の意味等を理解する必要はあるが、これも一応拡張(外付け)可能になった。option[:link_attr]の指定で動き出す機能も(現在の実装の迷路の中をさまよう覚悟さえあれば)一応拡張可能。ただし、このレベルのプラグインAPIはちょっとやそっとではドキュメント化できません。

ちなみに、[/javascript:.*/]は、禁止URLの指定で、ここに渡した正規表現にマッチする属性値は削除される。つまり、http://...ftp://のような普通のURLは許されるけど、javascript:で始まるURLが渡されると、この属性は空白になる。

この変更で、API(というかプログラマ向けのインターフェース)は、少しは整理されたように思う。後は、DHHが言うように、View内でプレゼンテーションオブジェクト(View用データ作成の処理=特定アクション専用のHelperメソッド)が書けるようにして、なるべく早く次期バージョンをリリースしたい。