重新定义方法时应该何时起作用?

时间:2014-04-28 03:57:28

标签: ruby

Ruby Koansabout_open_classes.rb部分,最终测试是:

class ::Integer
  def even?
    (self % 2) == 0
  end
end

def test_even_existing_built_in_classes_can_be_reopened
  assert_equal true, 1.even?
  assert_equal false, 2.even?
end

似乎def even?没有做任何事情;如果我改变方法,它似乎不起作用:

class ::Integer
  def even?
    (self % 2) != 0
  end
end

测试仍然成功。

我认为这是因为even已在Ruby中定义。那是对的吗?为什么会这样?

1 个答案:

答案 0 :(得分:7)

Ruby核心并不特殊,问题是even?来自Integer,它来自Fixnum。由于Fixnum1的祖先比整数低,因此在Integer中重新定义它没有任何效果,因为从来没有被调用过。

重新定义Fixnum代替正常工作:

1.even?  #=> false
class Fixnum; def even?; true; end end
1.even?  #=> true

而且,作为参考,这里是1的祖先:

1.class.ancestors  #=> [Fixnum, Integer, Numeric, Comparable, Object, Kernel, BasicObject]

您可以通过获取Method对象,然后获取owner来告诉even?来自Fixnum

1.method(:even?).owner  #=> Fixnum
1.method(:ceil).owner   #=> Integer