Personal tools
You are here: Home ブログ 井上 Ruby勉強会資料の訂正
« November 2008 »
Su Mo Tu We Th Fr Sa
            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            
Recent comments
AirOne v5.0.1出てしまいました inoue 2008-10-29
Re:Reversible debugging in GDB morita 2008-10-09
Re:Google Chromeの発表には驚きました inoue 2008-09-15
Re:Google Chromeの発表には驚きました Anonymous User 2008-09-10
Re:Windowsのタスクマネージャの闇 horii 2008-09-09
Re:Google Chromeの発表には驚きました inoue 2008-09-04
Re:Google Chromeの発表には驚きました inoue 2008-09-04
Re:Google Chromeの発表には驚きました inoue 2008-09-04
Re:Google Chromeの発表には驚きました Anonymous User 2008-09-03
Re:Software Design 2008年2月号「Emacsマスターへの道」の原稿を公開 elim 2008-07-25
Re:Rails(ActiveRecord)のJOINのイディオム inoue 2008-06-20
Re:「ピアレビュー」を読みました Anonymous User 2008-05-12
Categories
カテゴリなし
 
Document Actions

Ruby勉強会資料の訂正

にウソがあったので訂正します。

- RoRのコード例から引用

 class MyController < ApplicationController
   def index
     if params[:name] == 'unknown'
       render :action => 'x'
     else
       render :action => 'y'
     end
   end 
 end

- params[]というメソッドに引数 :name を渡している

と書いていましたが、MyControllerにparams[] というメソッドはありません。あるのはparamsというメソッドです(と、params=)。このふたつはインスタンス変数(@_params)のアクセサメソッドです。このインスタンス変数がハッシュテーブルのオブジェクトなので、上の [:name] はハッシュテーブルの [] メソッドの呼び出しです。

この params[:name] は params['name'] とも書けるのですが、この実装がどうなっているのか気になって調べたのが、気づいた発端でした。

以下、Ruby on Railsのソースのトップディレクトリを$RAILSと表記します。

$RAILS/actionpack/lib/action_controller/base.rb で次のようにあります(抜粋)。ActionController::Base は ApplicationController の親クラスです。

module ActionController #:nodoc:
  ...
  class Base
    ...
    attr_internal :params

attr_internal は次のようなメソッドです(一部略)。

class Module
  def attr_internal_reader(*attrs)
    attrs.each do |attr|
      module_eval "def #{attr}() #{attr_internal_ivar_name(attr)} end"
    end
  end

  def attr_internal_writer(*attrs)
    attrs.each do |attr|
      module_eval "def #{attr}=(v) #{attr_internal_ivar_name(attr)} = v end"
    end
  end

  # Declare attributes backed by 'internal' instance variables names.
  def attr_internal_accessor(*attrs)
    attr_internal_reader(*attrs)
    attr_internal_writer(*attrs)
  end

  alias_method :attr_internal, :attr_internal_accessor

  private
    mattr_accessor :attr_internal_naming_format
    self.attr_internal_naming_format = '@_%s'

    def attr_internal_ivar_name(attr)
      attr_internal_naming_format % attr
    end
end

気分は完全にマクロですが、要は attr_internal :params の呼び出しで、params と params= のふたつのメソッドを生成しています。ちなみに '@_%s' % :foo で '@_foo' の文字列を返します。

静的型の言語であれば、@_params (インスタンス変数)の定義を見れば、最初の疑問は一発で分かりそうですが、そうならないところが動的型言語の悲しいところです。結論から言えば、次のコードで Hash から HashWithIndifferentAccess に変換して返しています($RAILS/actionpack/lib/action_controller/request.rbから抜粋)。

module ActionController
  # CgiRequest and TestRequest provide concrete implementations.
  class AbstractRequest
    ...
    def parameters
      @parameters ||= request_parameters.merge(query_parameters).update(path_parameters).with_indifferent_access
    end

with_indifferent_access は次のように定義されています。

def with_indifferent_access
  hash = HashWithIndifferentAccess.new(self)
  hash.default = self.default
  hash
end

シンボルと文字列のどちらでも牽けるハッシュテーブルとしては、理屈上、次の4つの可能性があります。最後の候補は効率的に論外ですが。

  • キーをシンボルに統一
  • キーを文字列に統一
  • シンボルと文字列の両方のキーを登録
  • シンボルを使うキーと文字列を使うキーが混在

HashWithIndifferentAccess.new の実装は「キーを文字列に統一」です。勉強会で、シンボルの方が文字列より効率的なのでハッシュテーブルのキーにはシンボルを使うべし、と主張しておいてなんですが、paramsへのアクセスで使うキーは文字列の方が少しだけ(シンボルから文字列生成する分だけ)速いです。

と言うわけで、サンプルコードも次のように書き直しました。

if params['name'] == 'unknown'
The URL to Trackback this entry is:
http://dev.ariel-networks.com/Members/inoue/ruby-article2/tbping
Add comment

You can add a comment by filling out the form below. Plain text formatting.

(Required)
(Required)
(Required)
This helps us prevent automated spamming.
Captcha Image


Copyright(C) 2001 - 2006 Ariel Networks, Inc. All rights reserved.