顶层定义的方法在哪里存在?

时间:2014-12-02 05:47:12

标签: ruby metaprogramming

我正在学习一些元编程,我一直试图找到一种方法。假设我有以下课程:

class MyClass
  def self.my_method
  end
  def your_method
  end
end

使用以下代码,我可以在对象空间中搜索每个方法:

type = Class
name = /^my_method$/
result = ObjectSpace.each_object(type).select do |o|
  o.instance_methods(false).grep(name).size > 0 || o.methods.grep(name).size > 0
end
p result

它发现它显示以下输出:

[MyClass]

由于搜索器代码也会搜索实例方法,因此在查找your_method时会显示相同的输出。

即使我向对象添加单例方法:

mc = MyClass.new
def mc.our_method
end

只需改变搜索者:

type = Object
name = /^our_method$/
result = ObjectSpace.each_object(type).select do |o|
  o.methods.grep(name).size > 0
end
p result

它也找到了它:

[#<MyClass:0x8f86760>]

问题是,如何找到顶级对象中定义的方法?这个方法:

def hidden
end

此外,在定义这样的方法时,哪个是当前类?

2 个答案:

答案 0 :(得分:5)

  

定义这样的方法时,哪个是当前的类?

我们可以通过检查此顶级范围中的self来轻松找出我们所处的对象:

self        #=> main
self.class  #=> Object

所以我们不是一个Class,而是一个被称为“main”的Object实例。


  

如何找到顶级对象中定义的方法?

这是有趣的地方。 Ruby中的顶级范围对象具有特殊的行为,但是发现这里定义的方法所处的位置相对容易:

def foo; :bar; end
method(:foo).owner     #=> Object
Object.new.foo         #=> NoMethodError: private method `foo' called
Object.new.send(:foo)  #=> :bar

因此,在顶层定义的方法是Object的(private *)实例方法。您的“搜索者”无法找到它的原因是因为这些方法是私有的,methodsinstance_methods都不包含私有方法,而是您需要private_methodsprivate_instance_methods

Object.instance_methods.include?(:foo)          #=> false
Object.private_instance_methods.include?(:foo)  #=> true

*请注意,Pry(至少v0.10.1)会改变这一点,以便在其REPL公共场所的顶层定义方法。

答案 1 :(得分:0)

如果你有这个:

def my_method() end

class A
  def self.my_method() end
end

class B < A
  def my_method() end
end

class C
  def my_method() end
end

并希望找到您创建的名为'my_method'的方法,您可以这样做:

ObjectSpace.each_object(Class).select do |o|
  o.instance_methods(false).include?(:my_method)
end
  #=> [C, B]

ObjectSpace.each_object(Class).select do |o|
  o.methods(false).include?(:my_method)
end
  #=> [A]

ObjectSpace.each_object(Class).select do |o|
  o.private_instance_methods(false).include?(:my_method)
end
  #=> [Object]