从Ruby

时间:2016-01-12 13:56:21

标签: ruby reflection

这是 How to determine the class a method was defined in? 的后续问题(希望您不要介意相似性)

给定一个类层次结构,方法可以检索自己的Method实例吗?

class A
  def foo
    puts "A#foo: `I am #{method(__method__)}'"
  end
end

class B < A
  def foo
    puts "B#foo: `I am #{method(__method__)}'"
    super
  end
end

A.new.foo
# A#foo: `I am #<Method: A#foo>'

B.new.foo
# B#foo: `I am #<Method: B#foo>'
# A#foo: `I am #<Method: B#foo>' # <- A#foo retrieves B#foo

这样B.new.foo代替打印

# B#foo: `I am #<Method: B#foo>'
# A#foo: `I am #<Method: A#foo>' # <- this is what I want

在上一个问题中,Jörg W Mittag suspected检索定义方法的类可能会违反面向对象的范例。这也适用于此吗?

不应该是一种方法&#34;了解自己&#34;?

2 个答案:

答案 0 :(得分:3)

我找到了method,确切地说就是这样。

class A
  def foo
    puts "A#foo: `I am #{method(__method__).super_method || method(__method__)}'"
  end
end

我真的很佩服Matz和Ruby核心开发人员。这种方法的存在意味着他们考虑到了这种情况,并考虑过如何处理它。

答案 1 :(得分:2)

根据How to determine the class a method was defined in?的回答和@ sawa关于super_method的回答,你可以使用:

def meth(m, clazz)
    while (m && m.owner != clazz) do 
        m = m.super_method
    end
    return m
end

class A 
  def foo
    puts "A#foo: `I am #{meth(method(__method__), Module.nesting.first)}'"
  end
end

class B < A
  def foo
    puts "B#foo: `I am #{meth(method(__method__), Module.nesting.first)}'"
    super
  end
end


B.new.foo
# B#foo: `I am #<Method: B#foo>'
# A#foo: `I am #<Method: A#foo>'

这里的想法是,因为我们知道方法由Module.nesting.first定义的类/模块,所以我们采用method(__method__)找到的当前方法对象并遍历其super链到找到其所有者与定义方法的类/模块相同的方法实例。