• 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31

ActionController::Base#respond_to

ActionController の respond_to

  • MIMEタイプに応じて出力を切り替える素晴らしい手段を提供しつつも
  • 使う気をなくさせる表記法(実装)を採用する

というセンスがあるのかないのかわからない機能になっている。

   1    def show
   2      @person = Person.find(params[:id])
   3  
   4      respond_to do |format|
   5        format.html
   6        format.xml { render :xml => @person.to_xml }
   7      end
   8    end

誰がこんな面倒な記述を各アクションに書いていきたいと思うだろうか。

問題

具体的には以下の問題点が挙げられる。

  • やりたい事に対して無駄にコード量が多い
  • アクションが肥大化し可読性が低い
  • case文と同じで再利用性が低い

提案

上記の問題点を解消するために、 以下のような新しい表記法(実装)を提案する。

   1    def show
   2      @person = Person.find(params[:id])
   3    end
   4  
   5    def show.xml
   6      render :xml => @person.to_xml
   7    end

可読性は一目瞭然であり、 さきほどのサンプルと比べて以下のメリットを有する。

  1. アクションロジックと描画ロジックの峻別
  2. MIME単位での定義による可読性と再利用性
  3. 特異メソッド定義と拡張子の直感的親和性

特に3番目の、 "show.xml" のレスポンスを直感的に定義(記述)できる点は Rubyならではの機能と言える。

実装方針

   1  class ApplicationController < ActionController::Base
   2    class << self
   3      def method_missing(action, *arguments)
   4        if action_methods.include?(action.to_s)
   5          mime_respond_proxy_for(action)
   6        else
   7          super
   8        end
   9      end
  10  
  11      def mime_respond_proxy_for(action)
  12        @mime_responds[action] ||= MimeRespondProxy.new
  13      end
  14    end

  1. コントローラクラスの method_missing で、"def show.xml" の "show" 部分の未定義変数への参照をトラップ
  2. 定義済みのアクションであれば、Proxyオブジェクトを返す
  3. 以下、"def show.xml" 等の定義は Proxy オブジェクトへの(特異)メソッド追加となる
  4. default_render で、現在のアクションに応じた Proxy オブジェクトを取得し、指定されたmimeタイプの描画処理を行う
  5. コンテキストを合わせるために、aProxy.xml のメソッド定義の内容を実行中のコントローラに定義する
  6. singleton method bound for a different object (imkk)

反省会

  • singleton 以前に、他のメソッド定義を違うクラスに再定義できない

今後の選択肢

  • ブロック定義にすれば引き回せるよ (→ "def show.xml" と書ける心地よさが重要)
  • UnboundMethodを任意のクラス(Object)にbindさせてYO!
  • Method#to_sourceが欲しい
  • Method#modulizeでもいい
  • JavaScriptProxyみたいにする(helperとmethodとcontextをパピコ)
posted by Png maiha on Mon 28 Jul 2008 at 06:48 with 3 comments

Comments:

Png 瀧内元気 over 16 years ago.

一応、Proc#sourceを取り出すのであれば、 この辺なんかが使えそうな気がしますね。

Png maiha over 16 years ago.

Procだとそれが便利だねぇ。 でもMethodには使えないみたいだ。(to_procするとnilになる)

Png 瀧内元気 over 16 years ago.

なるほど、確かにMethodだとだめですね。うーむ。

or Preview
Social Bookmarks
  • Delicious
  • B_entry689
  • Clip_16_12_w
Services from s21g
twpro(ツイプロ)
Twitterプロフィールを快適検索
地価2009
土地の値段を調べてみよう
MyRestaurant
自分だけのレストラン手帳
Formula
ブログに数式を埋め込める数式コミュニティ