对象的 Ruby 方法查找路径 [英] Ruby method lookup path for an object
问题描述
是否有内置的 Ruby 方法或众所周知的库可以返回对象的整个方法查找链?Ruby 查看一系列令人困惑的类(如这个问题中所述) 例如,如果没有任何类响应消息,则与消息对应并在接收器上调用 method_missing
的方法.
Is there a built-in Ruby method or a well-known library that returns the entire method lookup chain for an object? Ruby looks through a confusing sequence of classes (as discussed in this question) for instance methods that correspond with a message and calls method_missing
on the receiver if none of the classes respond to the message.
我把下面的代码放在一起,但我确信它缺少某些情况,或者它是 100% 正确的.请指出任何缺陷,如果存在,请指导我找到一些更好的代码.
I put together the following code, but am sure it is missing certain cases or if it's 100% right. Please point out any flaws and direct me to some better code if it exists.
def method_lookup_chain(obj, result = [obj.singleton_class])
if obj.instance_of? Class
return add_modules(result) if result.last == BasicObject.singleton_class
r = result.last.superclass
method_lookup_chain(obj, result << r)
else
return result + obj.class.ancestors
end
end
def add_modules(klasses)
r = []
klasses.each_with_index do |k, i|
r << k
next if k == klasses.last
r << (k.included_modules - klasses[i+1].included_modules)
end
r.flatten
end
# EXAMPLES
module ClassMethods; end
module MoreClassMethods; end
class A
extend ClassMethods
extend MoreClassMethods
end
p method_lookup_chain(A) # => [#<Class:A>, MoreClassMethods, ClassMethods, #<Class:Object>, #<Class:BasicObject>]
module InstanceMethods; end
class Object
include InstanceMethods
end
module X; end
module Y; end
class Dog
include X
include Y
end
d = Dog.new
p method_lookup_chain(d) # => [#<Class:#<Dog:0x007fcf7d80dd20>>, Dog, Y, X, Object, InstanceMethods, Kernel, BasicObject]
推荐答案
那篇文章让人觉得很困惑,但实际上并非如此.如果你对这些东西感兴趣,你应该阅读Metaprogramming Ruby".在此之前,基本规则是向右和向上一步
:
That other post makes it seem confusing, but it really isn't. If you are interested in such things, you should read "Metaprogramming Ruby". Until then, the basic rule is one step to the right and up
:
Object (superclass)
^
|
Parent class A(superclass)
^
|
Parent class B(superclass)
^
|
obj -> object's class
2) 在 obj 和对象的类之间插入单例类:
2) Singleton classes are inserted between the obj and the object's class:
Object
^
|
Parent class A(superclass)
^
|
Parent class B(superclass)
^
|
object's class(superclass)
^
|
obj -> obj's singleton_class
3) 被包含的模块直接插入到执行包含的类的上方:
3) Included modules are inserted immediately above the class that does the including:
Object
^
|
Parent class A
^
|
Module included by Parent Class B
^
|
Parent class B
^
|
object's class
^
|
obj -> obj's singleton_class
请指出任何缺陷
p method_lookup_chain(Class)
--output:--
[#<Class:Class>, #<Class:Module>, #<Class:Object>, #<Class:BasicObject>]
但是……
class Object
def greet
puts "Hi from an Object instance method"
end
end
Class.greet
--output:--
Hi from an Object instance method
还有..
class Class
def greet
puts "Hi from a Class instance method"
end
end
Class.greet
--output:--
Hi from a Class instance method
在类上调用的方法的查找路径实际上继续经过 BasicObject 的单例类(#
):
The lookup path for a method called on a class actually continues past BasicObject's singleton class(#<Class:BasicObject>
):
class BasicObject
class <<self
puts superclass
end
end
--output:--
Class
在 Class 上调用的方法的完整查找路径如下所示:
The full lookup path for a method called on Class looks like this:
Basic Object
^
|
Object
^
|
Module
^
|
Class
^
|
BasicObject BasicObject's singleton class
| ^
| |
Object Object's singleton class
| ^
| |
Module Module's singleton class
| ^
| |
Class ---> Class's singleton class
查找从 Class 的单例类开始,然后在右侧的层次结构中向上查找.元编程Ruby"声称对所有对象都有统一的查找理论,但对类上调用的方法的查找不符合图3).
The lookup starts in Class's singleton class and then goes up the hierarchy on the right. "Metaprogramming Ruby" claims there is a unified lookup theory for all objects, but the lookup for methods called on a class does not fit the diagram in 3).
您在这里遇到了同样的问题:
You have the same problem here:
class A
end
class B < A
end
p method_lookup_chain(B)
--output:--
[#<Class:B>, #<Class:A>, #<Class:Object>, #<Class:BasicObject>]
应该是这样的:
Basic Object
^
|
Object
^
|
Module
^
|
Class
^
|
BasicObject BasicObject's singleton class
| ^
| |
Object Object's singleton class
| ^
| |
A A's singleton class
| ^
| |
B.greet --> B's singleton class
您需要记住的一件事:在类上调用的任何方法的查找路径都必须在某处包含 Class,因为所有类都继承自 Class.
One thing you need to keep in mind: the lookup path of any method called on a class has to include Class somewhere because ALL classes inherit from Class.
这篇关于对象的 Ruby 方法查找路径的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!