对象的 Ruby 方法查找路径 [英] Ruby method lookup path for an object

查看:47
本文介绍了对象的 Ruby 方法查找路径的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

是否有内置的 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆