define_method和对象类:奇怪的行为

时间:2014-01-29 04:49:40

标签: ruby metaprogramming eigenclass


编辑:让我稍微谈谈我的意图:

鉴于ruby对象从其类的实例方法获取其方法。

我试图“证明”的是,通过向该对象的类添加实例方法,它们将成为该对象本身的方法。

所以:

class Test;end
Test.class.class_eval do 
  def foo
    puts "I am a method in #{self}"
  end
end
Test.foo
=> I am a method in Test
Test.class.foo
=> I am a method in Class

我实际上已经弄明白为什么会这样。那是因为Class.class是...... Class!由于Class将foo作为其实例方法表的一部分,并且由于Class.class指向自身,因此它也将foo作为可调用的实例方法。

原帖如下:

为了更多地了解Ruby对象模型,我一直在做一些实验,以下行为让我感到惊讶:

假设我们有一个课程测试:

class Test;end

然后,我们将class_eval Test.class添加到Test对象中:

Test.class.class_eval do
  def foo 
    puts 'foo called!'
  end
end

(相当于调用Test.class.send(:define_method,:foo)...)

然后:

irb(main):076:0> Test.foo
=> foo called!

但是将foo发送到课堂也有效:

irb(main):006:0> Test.class.foo
=> foo called!
但是,我仍然无法弄清楚原因。 Class'ingleton_class不包含它(我想到的唯一可能的解释是,该方法被添加到Class的单​​例类中):

Test.class.singleton_methods
=> [:nesting, :constants]

在这种情况下,方法查找如何工作?为什么发送:foo到Test.class也调用方法?我错过了什么吗?


作为参考,我对Test的实例做了同样的事情:

irb(main):001:0> class Test;end
=> nil
irb(main):002:0> _foo = Test.new
=> #<Test:0x007fa2c39e2f38>
irb(main):003:0> _foo.class.class_eval do
irb(main):004:1*   def foo
irb(main):005:2>    puts 'foo called!'
irb(main):006:2>   end
irb(main):007:1> end
=> :foo
irb(main):008:0> _foo.foo
foo called!
=> nil
irb(main):009:0> _foo.class.foo
NoMethodError: undefined method `foo' for Test:Class

这就像我期望的那样。

提前致谢!

3 个答案:

答案 0 :(得分:1)

当您致电Test.class时,它会返回Test 类不是的实际Test类。

irb(main):001:0> class Test;end
=> nil
irb(main):002:0> Test.class
=> Class

当您致电_foo = Test.new时,您正在抓取该课程的实例,然后当您致电_foo.class时,它会返回foo实例的类Test < / p>

在您的第一个示例中, 将foo添加到超类,而不是Test类。

要进一步扩展这一点,您应该做的是在class_eval类上调用Test。 最重要的是,你想要的是一个类方法,而不是一个实例方法。因为Test类实际上是Class的实例,所以实际上在Class类中定义了一个实例方法,而不是在Test中定义类方法。你应该做的是:

Test.class_eval do
  def self.foo
    puts "foo called!" 
  end
end

答案 1 :(得分:0)

你把事情搞混了。

  • Test.class_evalTest的本征类(Test上执行。)
  • Test.class.class_evalTest的本征类'本征类(显然是Class)上执行。)
  • Test.class.singleton_methods返回Class'本征类的方法。

Test.class.class_eval实际上会在Class上执行代码(在您的情况下声明Class'实例方法。)

Test.foo被称为w / out问题,因为您已在#foo上声明ClassTest是其实例(以及Test.class。 )

答案 2 :(得分:0)

长话短说,将foo发送到Test.class的原因是:

Test.class == Class and Class.class == Class

Class.class指向自己。