Personal tools
You are here: Home ブログ 井上 Ruby勉強会資料の訂正
« December 2010 »
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 31  
Recent entries
Apache2.4のリリース予定は来年(2011年)初め(あくまで予定) inoue 2010-12-23
Herokuの発音 inoue 2010-12-20
雑誌記事「ソフトウェア・テストPRESS Vol.9」の原稿公開 inoue 2010-12-18
IPA未踏のニュース inoue 2010-12-15
労基法とチキンゲーム inoue 2010-12-06
フロントエンドエンジニア inoue 2010-12-03
ASCII.technologies誌にMapReduceの記事を書きました inoue 2010-11-25
技術評論社パーフェクトシリーズ絶賛発売中 inoue 2010-11-24
雑誌連載「Emacsのトラノマキ」の原稿(part8)公開 inoue 2010-11-22
RESTの当惑 inoue 2010-11-22
「プログラマのためのUXチートシート」を作りました inoue 2010-11-19
「ビューティフルコード」を読みました inoue 2010-11-16
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.