RamazeでAmrita2が使えるようになりました
id:keita_yamaguchiさんが、RamazeのテンプレートエンジンをAmrita2 2.0.0 で動くように直してくれました。
これに便乗して、Ramazeのサンプルにあった132行のブログエンジンのAmrita2バージョンを作ってみました。
コントローラのソースを一部抜粋するとこんな感じです。
def index slug = nil title = nil if slug.nil? @posts = BlogPost.collect raise Ramaze::Error::NoAction, 'No blog posts found, create entries/YYYY.MM.DD.My.First.Blog.Post' unless @posts.any? else raise Ramaze::Error::NoAction, 'Invalid blog post' unless post = BlogPost[slug] post = BlogPost[slug] title = post.title @posts = [ post ] end title_hook = Amrita2::Core::Hook.new do if title render_child(:post_title, :href=>'/', :text=>title) else render_child(:index_title, :text=>TITLE) end end @data = binding %( <<h1 :title_hook | AcceptData[:hook] < <<a :post_title | Attr[:href] < <<:text>> <<span :index_title < <<:text>> <<div.hentry :posts < <<h2 { :url=> '/' + $_.slug } < <<abbr.updated title="$1" :| Eval["Time.parse($_.date).iso8601", :date] < $2 <<a.entry-title href="$1" rel="bookmark" :| NVar[:url, :title] < $2 <<div.entry-content :body | NoSanitize >> ) end
あえて、Amrita2のいろんな機能を詰め込んでみました。特に、Hookという機能は、けっこう面白いと思います。
Hook オブジェクトを作成すると、テンプレートエンジンがレンダリングしている途中で、ユーザコードに一時的に制御を戻すことができます。
上記の例だと、title_hookというタイトルを作成する所に介入しています。ここで、title というローカル変数がnilかどうかで、:index_titleか:post_titleの、どちらの要素を使うかを選択しています。また、その要素のレンダリングはAmrita2が行なうわけですが、そこに渡すデータもこの処理の中で作成しています。
テンプレートの中に条件判断を書かないで、Rubyのコードとして書けますので、これをうまく使うとプレゼンテーションとプレゼンテーションロジックがきれいに分離できるのではないかと思います。
また、これを使うとevalを使わないでテンプレートの処理を行なえるので、ruby1.9では少しは早くなるかもしれません。(その代わりに ブロックのネストが深くなるので、どうなるかはわかりません)
なお、Amrita2は今の所はruby1.9には未対応ですが、レビュアブルマインドの開発が落ち着いたら、1.9をターゲットにして最適化していこうと思っています。HTMLをRubyにコンパイルして動かしているので、YARVが喜ぶようなRubyコードを吐くように直していけば、いくらでも速くできるのではないかと考えています。