Ruby – 确定方法的起源?

发送消息时,Ruby对象会搜索是否有一个按该名称响应的方法。 其方法查找按以下顺序搜索,并使用它找到的第一个方法。

  1. 单身方法本身定义(也称为“本征类”的方法)
  2. 在其类中定义的方法
  3. 任何模块都以相反的顺序混合到它的类中(只有最早包含给定模块才有效 – 如果超类包含模块A,并且子类再次包含它,则在子类中忽略它;如果子类包含A然后B然后A,第二个A被忽略)( 更新 :注意这是在Module.prepend存在之前Module.prepend
  4. 它的父类
  5. 混合到父类,父类的父类等的任何方法。

或者,更简单地说,它看起来自己,然后self.class.ancestors中的所有内容按照它们列出的顺序。

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

如果所有这些都失败了,它会查看它是否有一个method_missing方法,或者它的类是否有,它的父类等。

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

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

 > [].method(:length).inspect => "#" > [].method(:max).inspect => "#" 

在Ruby 1.8.7及更高版本中,您可以使用Method#owner来确定定义方法的类或模块。

要获取具有定义它们的类或模块名称的所有方法的列表,您可以执行以下操作:

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

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

要查找在A上定义的实例方法(但不在超类上定义):

 A.methods(false) 

要查找在A及其超类上定义的实例方法:

 A.methods 

要查找定义给定方法的类(或模块):

 method(:my_method).owner 

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

 method(:my_method).receiver 

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

 [1, 2, 3].method(:each_cons) # => # 

告诉我们Array的each_cons方法来自Enumerable模块。