attr_internal_accessor

Railsのアクション内で、そういえばrequestやparamsとかってどうやってアクセスしてるのだろうと気になったので調べてみました。

とりあえずActionController::Baseを調べてるとassign_shortcuts(request, response)というメソッドを発見。

def assign_shortcuts(request, response)
  @_request, @_params, @_cookies = request, request.parameters, request.cookies

  @_response         = response
  @_response.session = request.session

  @_session = @_response.session
  @template = @_response.template
  @assigns  = @_response.template.assigns

  @_headers = @_response.headers
end

インスタンス変数に色々いれてるけど、そんなものはみたことないのでとりあえず放置。んでattr_accessorかなと思ってみたら、attr_internal :requestとかってのを発見。調べてみました。

active_support/core_ext/module/attr_internal.rb

class Module
  # Declares an attribute reader backed by an internally-named instance variable.
  def attr_internal_reader(*attrs)
    attrs.each do |attr|
      module_eval "def #{attr}() #{attr_internal_ivar_name(attr)} end"
    end
  end

  # Declares an attribute writer backed by an internally-named instance variable.
  def attr_internal_writer(*attrs)
    attrs.each do |attr|
      module_eval "def #{attr}=(v) #{attr_internal_ivar_name(attr)} = v end"
    end
  end

  # Declares an attribute reader and writer backed by an internally-named instance
  # variable.
  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

やっぱりこれでした。文字列の%メソッドがわからなかったので調べてみました。

self % args

文字列のフォーマット。引数をフォーマット文字列(self)で書式化した文字列を返します。

args が配列であれば

sprintf(self, *args)

と同じです。それ以外の場合は、

sprintf(self, args)

と同じです。詳細は sprintfフォーマットを参照してください。

プログラミング言語 Ruby リファレンスマニュアル

sprintfだったのか。てことはやっぱり@_requestとかにアクセスしてるみたいですね。

@request変数にアクセスさせたくないけどアクセサは欲しいからこんなことやってる模様。activesupport-2.1.0/lib/active_support/deprecation.rbとかにちょろちょろ書いてます。黒魔術すぎる。。。