* Shibuya.js TT#1 RJS Template Jemplate **(株)はてな id:secondlife * アジェンダ - Template と名のつくモノの紹介 -- RJS Template -- Jemplate -- さわりの部分だけなので内容は深くない * 二つとも Template っぽい 実は名前は似てても全く異なるもの * RJS Template って? - Ruby on Rails 1.1 から搭載の JavaScript コード生成テンプレートヘルパー -- 旧 JavaScriptGenerator - 既存の HTML の DOM要素 に対する操作を簡単に行う * 何がうれしいの? 今までの Rails の Ajax 機能の場合 - Ajax で結果を取得してそれで HTML を replace したり insert したり - +αのことを行うとコールバック関数をでごりごり -- つまりめんどい * 何がうれしいの? RJS Template を使うと - DOM 要素に対する操作を Ruby で簡単に書ける - コールバック関数でごりごりせずに OK * 具体的にはどんな処理? - 出力した HTML から Ajax で RJS Template を呼び出す -- JavaScript をサーバサイドで生成して返す -- $("foo").show(); - 結果を eval する http://paprika/shibuyajs1/zu1.png * 前知識・利用方法 必要なライブラリの読み込み >|| <%= javascript_include_tag :defaults %> ||< >|| ||< * 前知識・利用方法 - view として .rjs ファイルを置く - アクションの render で >|| render :update do |page| # ここに実装 end ||< * 簡単なサンプル Ajax.Request で結果を取得して eval る >|| <%= link_to_remote( "RJS Action", :url =>{ :action => :rjs_action }) %> ||< >||
RJS Action
||< RJS Template >|| page.select('li').each do |el| el.set_style :color => 'red', :fontSize => ' 100px' end ||< >|| $$("li").each(function(value, index) { value.setStyle({"color": "red", "fontSize": "100px"}); }); ||< http://paprika:3000/test/ * アプリケーションっぽいサンプル RJS Template 無し(従来) >|| <%= form_remote_tag :url => { :action => :speak }, :complete => <<-EOF new Insertion.Top("spoke", request.responseText); $("word").value = ""; new Effect.Highlight($$("ul li").first()); EOF %> ||< >|| def speak # DB に保存とかサーバサイドロジックを書く render :text => "
#{ERB::Util.h params['word']}
" end ||< http://paprika:3000/chat/ * アプリケーションっぽいサンプル RJS Template >|| <%= form_remote_tag :url => { :action => :speak_rjs } %> ||< >|| def speak_rjs render :update do |page| page.insert_html :top, 'spoke', "
#{h params['word']}
" page['word'].value = '' page.select('ul li').first.visual_effect :highlight end end ||< DBから取得したインスタンスで page をあれこれ操作できるので楽 http://paprika:3000/chat/rjs * RJS Template の実装周り **実体 ActionView::Helpers::PrototypeHelper ::JavaScriptGenerator のインスタンス ** ドキュメントねーよ! ActionView::Helpers::PrototypeHelper ::JavaScriptGenerator::GeneratorMethods を extend してるのでその ドキュメントを見ると良い * 感覚つかみたいけどどうすればいい? ./script/console で helper 呼び出すとコマンドラインで対話的に使えるヨ >|| >> helper.update_page do |page| ?> page.select('ul li').first.visual_effect :highlight >> end => "$$(\"ul li\").first().visualEffect(\"highlight\");" ||< * 実装の話 インスタンス(page)のメソッドを実行したら、配列に結果を書き込んでいく つまり >|| page.alert(page['title']) ||< はできない。 * Ruby で JavaScript 生成ってめんどくさそう - RJS のメソッドは 19 個 -- 19個でできるの? -- そんなに使いません - あんまなんにも考えなくてうまい具合に変換してくれるよ どんな風にやってるの? * メソッド呼び出しのチェイン 定義されたメソッド以外は method_missing で JavaScript っぽいメソッドに変換 >|| def method_missing(method, *arguments) JavaScriptProxy.new(self, method.to_s.camelize) end ||< そのため ruby のメソッドチェインも JavaScript のチェイン になる >|| # 定義されていない↓ ↓ page.select('.foo').first.to_string # ↑ 定義されている ||< >|| $$(".foo").first().toString(); ||< * 引数に Ruby のオブジェクトを渡す ** 引数周りの処理はどんなん? ruby のオブジェクトを Object#to_json で JavaScript の syntax に変換してるため、引数に渡しても問題ない(ことが多い) >|| hash = {:color => 'red'} page['element'].set_style hash ||< >|| $("element").setStyle({"color": "red"}); ||< * Breakpoint によるリアルタイム実行 ** breakpointer dRuby + IRB でリモートデバッグ >|| render :update do |page| breakpoint end ||< breakpoint を利用して手動で DEMO http://paprika:3000/test/rjs >|| page.alert('hello') page.insert_html :after, 'title', '
hello RJS!
' page.visual_effect :fade, 'title', :duration => 5 ||< でもあまり実用性は… * RJS Template 紹介終わり * Jemplate って? - Syntax が Template-Toolkit ライクな テンプレートエンジン - 作者・Ingy dot Net -- http://static.flickr.com/46/121133822_8ffed78878_b.jpg * 何がうれしいの? - JavaScript でテンプレートエンジンが使えるだけでだいぶ違う -- JavaScript の文字列リテラルが貧弱 - データを全部 JSON でやりとりできる -- Ajax との連携、データの管理、使い回しが楽 * 使い方 - テンプレートを書く - jemplate コマンドでコンパイル - Jemplate.js と コンパイルした .js を読み込む - Jemplate.process('テンプレート名', json_data or URL, '#置換するid名 or element'); * 簡単なサンプル ** テンプレート char_list.tt というファイル名で適当なディレクトリに作成 >||
char list
[% FOR char = char_list %]
[% char | html %]
[% END %]
||< * 簡単なサンプル コンパイル >|| jemplate -c app/jemplate/jemplate/*.tt > public/javascripts/Jemplate/jemplate.js ||< ** 出力した .js の中身 Jemplate.templateMap['char_list.tt'] という名前空間に テンプレートが JavaScript に変換されて入る * 簡単なサンプル >|| new Ajax.Request("/jemplate/char_list", { onComplete: function(request) { var data = eval('(' + request.responseText + ')'); Jemplate.process('char_list.tt', data, '#result'); } }); // or Jemplate.process('char_list.tt', '/jemplate/char_list', '#result'); ||< サーバサイドで JSON を返す >|| render :text => { :char_list => ('a'..'z') }.to_json # {"char_list": ["a", "b", "c", "d", "e"…]} ||< http://paprika:3000/jemplate/ * 簡単なサンプル、RJS Template 遍 JSON は eval が面倒、でもサーバサイドで Jemplate.process まで生成しちゃうと… >|| new Ajax.Request('/jemplate/char_list_rjs', {evalScripts:true}); ||< >|| render :update do |page| page.Jemplate.process( 'char_list.tt', {:char_list => ('a'..'z') }, '#result' ) end ||< スマートに書けるお><ノ * コンパイルがめんどくさい フレームワークとの連携 - Catalyst::View::Jemplate -- 毎回 Jemplate テンプレートをコンパイル -- development 向け * 現在(0.18)サポートされている syntax - Plain text - [% [GET] variable %] - [% CALL variable %] - [% [SET] variable = value %] - [% DEFAULT variable = value ... %] - [% INCLUDE [arguments] %] - [% PROCESS [arguments] %] - [% BLOCK name %] - [% FILTER filter %] text... [% END %] - [% JAVASCRIPT %] code... [% END %] - [% WRAPPER template [variable = value ...] %] - [% IF condition %] - [% ELSIF condition %] - [% ELSE %] - [% SWITCH variable %] - [% CASE [{value|DEFAULT}] %] - [% FOR x = y %] - [% WHILE expression %] - [% RETURN %] - [% THROW type message %] - [% STOP %] - [% NEXT %] - [% LAST %] - [% CLEAR %] - [%# this is a comment %] * まとめ * RJS Template - JavaScript があまり解らない人 - Ruby で JavaScript のコードを生成したい人 - JavaScript の生成コードの共有 -- helper method の実装で可能 - JavaScript のコード生成に興味がある人 -- ソース嫁 - JavaScript がごりごり書ける人には正直… -- でも prototype アプリを作るのに感覚つかむのに手軽にできる * Jemplate - JavaScript で Template 書くのにめちゃ便利 - コンパイルや呼び出しが面倒 -- フレームワーク側で解決 - でも Template が必要になることはあまり無いかも? -- アプリケーションの設計次第 -- はてなマップとか * ご静聴ありがとうございました