【问题标题】:Getting the owner of a constant获取常量的所有者
【发布时间】:2016-02-21 08:09:33
【问题描述】:

使用一个(n 继承的)方法,定义它的接收器/类可以通过这样做来实现:

class A
  def foo; end
end

class B < A
end

B.instance_method(:foo).owner # => A

有了一个(n 继承的) 常量,没有instance_methodmethod 方法的对应物,所以它并不简单。是否可以实现它定义的类?

class A
  Foo = true
end

class B < A
end

B.some_way_to_extract_the_owner_of_constant(:Foo) # => A

【问题讨论】:

  • B::Foo 是否已定义?
  • 由于没有直接的方法,我猜想也没有间接的方法,否则它会被封装在所说的直接方法中。
  • 一个技巧是B.const_defined? :Foo, falseA.const_defined? :Foo, false。我需要弄清楚,如何递归地把所有祖先链起来。

标签: ruby constants receiver


【解决方案1】:

如下代码:

class A
  Foo = true
end

class B < A
end

B.ancestors.find { |klass| klass.const_defined? :Foo, false }
# => A

【讨论】:

  • 这是个好主意。我想知道它是否在边缘情况下正常工作,例如包含/前置多个模块时,每个模块都有具有相同名称的常量定义。
  • 很好,Arup。我也在使用ancestors.find,但只尝试了constants,这当然行不通。
  • 请注意,多个祖先可能有同名的常量。这段代码应该仍然可以正常工作,因为ancestors 方法按优先级降序返回祖先。
  • @SteveJorgensen 关于ancestors,我在评论中暗示的棘手之处在于prepend-ed 模块与include-d 在ancestors 返回的数组中的模块没有区别.但它可能会正常工作。我自己也不清楚。
  • @sawa 我刚刚尝试了一个实验,看起来ancestors 数组的顺序也可以解决这个问题。前置模块首先出现,然后是 ancestors 调用的目标,然后是包含模块和父类。
【解决方案2】:

类似于@Arup 的回答,但我使用过Module#constants

class Base
end

class A < Base
  Foo = true
end

class B < A
  Foo = false
end

class C < B
end

C.ancestors.find { |o| o.constants(false).include?(:Foo) }
  #=> B

【讨论】:

    猜你喜欢
    • 2022-08-12
    • 1970-01-01
    • 2015-04-21
    • 2016-02-29
    • 1970-01-01
    • 2015-04-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多