Ruby – 确定方法的起源?
发送消息时,Ruby对象会搜索是否有一个按该名称响应的方法。 其方法查找按以下顺序搜索,并使用它找到的第一个方法。
- 单身方法本身定义(也称为“本征类”的方法)
- 在其类中定义的方法
- 任何模块都以相反的顺序混合到它的类中(只有最早包含给定模块才有效 – 如果超类包含模块A,并且子类再次包含它,则在子类中忽略它;如果子类包含A然后B然后A,第二个A被忽略)( 更新 :注意这是在
Module.prepend
存在之前Module.prepend
) - 它的父类
- 混合到父类,父类的父类等的任何方法。
或者,更简单地说,它看起来自己,然后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模块。