Ruby koans:对 koan 268 感到困惑

Ruby koans: Baffled by koan 268

我有 'solved' Ruby koan 268,但对我来说没有意义。该项目正在使用代理对象(我猜是一种适配器?)到 'impersonate' 电视 class。
这是我的代理 class 的结局:

class Proxy
  def initialize(target_object)
    @object = target_object
    # ADD MORE CODE HERE
    attr_accessor :messages
    @messages = []
  end

  # WRITE CODE HERE
  def method_missing(method_name, *args)
    if @object.respond_to?(method_name)
      @messages.push(method_name)
      @object.send(method_name, *args)
    end
  end

  def messages 
    @messages
  end
end

稍后,Proxy Television 声明如下:

tv = Proxy.new(Television.new)    
tv.power
tv.channel = 10
assert_equal [:power, :channel=], tv.messages

我的问题是,当我之前定义了 attr_accessor :messages 时,为什么我必须将 messages 方法添加到 Proxy?没有最后一个方法,公案就不会'pass'。 (tv.messages returns 无)。

我真的很想理解这一点,因为在我看来我是在通过 attr_accessor 和 messages 方法定义对@messages 的访问来重复自己。如果 attr_accessor 不能让我访问@messages,那有什么意义呢?

谢谢。

我 运行 这个代码在 ruby 2.1.5p273:

class A
  def initialize
    attr_accessor :m
  end

  def a(i)
    @m = i
  end
end

a = A.new

这会引发错误:

NoMethodError: undefined method `attr_accessor' for #<A:0x007f8313022220>
  from (irb):3:in `initialize'

问题是 attr_accessor 是一个 class 方法,而不是实例方法。因此,您不能从 initialize 方法内部调用它。你必须把它放在外面,在 class 体内。然后它将正确设置访问器,它首先会按您预期的那样工作:

class A
  attr_accessor :m

  def a(i)
    @m = i
  end
end

a = A.new
a.a 'hey'
a.m # => "hey"

这个 method_missing 的定义掩盖了错误:任何对不存在的方法的调用只是 returns nil 而不是引发 NameError。

特别是你对 attr_accessor 的调用没有做任何事情,因为 attr_accessor 不是实例方法,所以 method_missing 被调用并吞下了你的错误,所以你对 [需要 =14=] 才能获得 @messages 的值。如果在 initialize 方法之外调用 attr_accessor,那么 messages 的定义确实是多余的。

如果您省略 messages 方法,那么 proxy.messages 最终只会调用 method_missing 并且(除非电视有这样的方法)returns nil。