Ruby - 确定方法的起源?

Nat*_*ong 27 ruby

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

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

或者,更简单地说,它看起来自己,然后self.class.ancestors按照它们列出的顺序进行所有操作.

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

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

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

Phi*_*oss 25

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

> [].method(:length).inspect
=> "#<Method: Array#length>"
> [].method(:max).inspect
=> "#<Method: Array(Enumerable)#max>"
Run Code Online (Sandbox Code Playgroud)

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

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

obj.methods.collect {|m| "#{m} defined by #{obj.method(m).owner}"}
Run Code Online (Sandbox Code Playgroud)

  • 另一点很棒:`Method`对象也有一个`source_location`方法."现在哪个讨厌的猴子补丁?...":) (6认同)

Chu*_*uck 9

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


hor*_*guy 6

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

A.methods(false)
Run Code Online (Sandbox Code Playgroud)

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

A.methods
Run Code Online (Sandbox Code Playgroud)

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

method(:my_method).owner
Run Code Online (Sandbox Code Playgroud)

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

method(:my_method).receiver
Run Code Online (Sandbox Code Playgroud)