2010-08-16 42 views
24

发送消息时,Ruby对象将搜索以查看它是否具有该名称的方法来响应。其方法查找按以下顺序搜索,并使用它找到的第一个方法。红宝石 - 确定方法的起源?

  1. 上本身定义singleton方法在其类中定义
  2. 方法(在其“eigenclass”又名方法)
  3. 任何模块混入它的类,在夹杂物的相反的顺序(仅是最早的夹杂物给定的模块有任何影响 - 如果超类包含模块A,并且子类再次包含它,则在子类中将被忽略;如果子类包括A,则B和A,第二个A将被忽略)(更新:请注意,此之前写有Module.prepend
  4. 其父类
  5. 混入父类,父父,等

或者,说得简单些,它看起来对自己的任何方法,那么一切都在self.class.ancestors在为了他们上市。

这个查找路径是在调用该方法的时刻;如果您创建了一个类的实例,然后重新打开该类并添加一个方法或通过一个模块混合一个方法,那么现有实例将获得对该方法的访问权限。

如果所有的失败,它看起来,看它是否有一个method_missing方法,或者如果它的类呢,它的父类等

我的问题是这样的:除了检查用手工代码或者使用例如puts "I'm on module A!"这样的示例方法,你能说出给定的方法来自何处吗?例如,你可以列出一个对象的方法,并且看到“这个是在父类上,这个在模块A上,这个在类上,并且覆盖了父类,”etc?

回答

22

Object#method返回Method对象,提供有关给定方法的元数据。例如:

> [].method(:length).inspect 
=> "#<Method: Array#length>" 
> [].method(:max).inspect 
=> "#<Method: Array(Enumerable)#max>" 

在Ruby 1.8.7和以后,就可以使用Method#owner来确定所限定的方法的类或模块。

要获得所有与他们的定义,你可以做类似下面的类或模块的名称的方法列表:

obj.methods.collect {|m| "#{m} defined by #{obj.method(m).owner}"} 
+0

您可以通过使用backports gem来获取1.8.6中的#owner方法。 – rogerdpack 2010-08-17 15:48:25

+5

另一个精彩的地方:'Method'对象也有'source_location'方法。 “现在那个讨厌的猴子补丁在哪里?”:) :) – 2012-07-04 12:40:58

+0

不能相信我对此没有想法。非常有用!非常感谢。 – dimitarvp 2015-07-23 11:34:16

9

获取适当的方法(或UnboundMethod)对象并请求其owner。所以你可以做method(:puts).owner并得到Kernel

+0

您的答案与接受的答案一起是黑暗中的纯光人。谢谢! – dimitarvp 2015-07-23 11:35:06

1

您可以使用Object#method。例如,

[1, 2, 3].method(:each_cons) # => #<Method: Array(Enumerable)#each_cons> 

表明Array的each_cons方法来自Enumerable模块。

4

要找到哪个实例方法上A定义(但不是超):

A.methods(false) 

要找到哪个实例方法上A定义和其超:

A.methods 

找哪家类(或模块)给定的方法定义如下:

method(:my_method).owner 

要查找给定方法的接收器是哪个对象:

+0

要获取特定类型的方法:someobject.private_methods,someobject.public_methods,someobject.protected_methods,someobject.singleton_methods,SomeClass.instance_methods,SomeClass.private_instance_methods,SomeClass.protected_instance_methods,SomeClass.public_instance_methods(与.instance_methods相同)。 – 2010-10-23 11:24:49

+0

'A.methods'应为'A.instance_methods' – Kelvin 2012-02-23 17:06:55