:yの悲劇

GPS情報を格納するのに、

class Entry < ActiveRecord::Base
  has_one :location
end
  
class Location < ActiveRecord::Base
  # 実際にはGeometry型で格納するので、アクセサを定義
  def x
    point.x
  end
  def y
    point.y
  end
end

こんなモデルを作ると・・・

$ script/console
>> entry = Entry.find(:first)
>> entry.location.x
=> 135.0
>> entry.location.y
=> 35.0
>> entry.location.send :x
=> 135.0
>> entry.location.send :y
ArgumentError: wrong number of arguments (0 for 1)
        from (irb):35:in `y'
        from (irb):35:in `send'
        from (irb):35

xは大丈夫なのにyはだめ?

yの正体は、pのようにyamlを吐くprivate method、Kernel#y in yaml.rb。 何故だ?

entry.location の中身は、実はAssociationProxyで、ActiveRecordのソースを見るとこんな風になっている。

# lib/active_record/associations/association_proxy.rb
module ActiveRecord
  module Associations
    class AssociationProxy #:nodoc:
      attr_reader :reflection
      alias_method :proxy_respond_to?, :respond_to?
      alias_method :proxy_extend, :extend
      instance_methods.each { |m| undef_method m unless m =~ /(^__|^nil\?|^proxy_respond_to\?|^proxy_extend|^send)/ }

entry.location.send :x すると、AssocationProxy#xが無いのでtargetにsendされるが、entry.location.send :y だと、Kernel#yが見つかってしまうのか・・・

当然entry.location.target.send :y だとうまくいく。

Ruby1.9 だとsendの仕様が違ってうまくいきそう。

Thu, 21 Dec 2006 18:51 カテゴリ , ,

タグ ,

  1. By keisuken 21/12/2006 at 21h58


    微妙に今やってるのと重なる(もしかして同じ構成のシステム(^;). とりあえずこちらはlatitude,longitudeにしてます. #Google Mapsが分秒単位じゃなくてはまった口 Ruby勉強ネタになるのかな.

  2. By nanki 22/12/2006 at 13h20


    名前を変更するのが一番早い解決法だったんですが・・・

    せっかくなので原因を探ってみました。 メタ情報を得るメソッド類もほとんどundefされているので、ソースを見るまで意味不明で。

    位置情報を扱うと、コアの部分は似たような構成になりますね。

  3. By babie 11/01/2007 at 00h09


    人柱ありがとう!w latitude, longitude にしまつ。

  4. By nanki 11/01/2007 at 00h47


    AssociationProxy において、private なメソッドにアクセスできてしまうsend を使ってるのがおかしな話なんですが。

    パッチ書く気力が起きない・・・

Comment :yの悲劇


RSS