Ruby - 确定方法的起源?

时间:2010-08-16 11:30:35

标签: ruby

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

  1. 自身定义的单例方法(也称为“本征类”上的方法)
  2. 在其类中定义的方法
  3. 任何模块都以相反的顺序混合到它的类中(只有最早包含给定模块才有效 - 如果超类包含模块A,并且子类再次包含它,则在子类中忽略它;如果子类包括A然后B然后A,第二个A被忽略)(更新:请注意,这是在Module.prepend存在之前编写的)
  4. 其父类
  5. 混合到父类,父母的父等等的任何方法
  6. 或者,更简单地说,它会按照列出的顺序查看self.class.ancestors中的所有内容。

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

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

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

4 个答案:

答案 0 :(得分:25)

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}"}

答案 1 :(得分:9)

获取相应的Method(或UnboundMethod)对象并询问其owner。因此,您可以执行method(:puts).owner并获取Kernel

答案 2 :(得分:6)

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

A.methods(false)

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

A.methods

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

method(:my_method).owner

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

method(:my_method).receiver

答案 3 :(得分:1)

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

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

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