【问题标题】:Load constant from string, as resolved in current scope从字符串加载常量,在当前范围内解析
【发布时间】:2019-02-12 14:02:24
【问题描述】:

假设我有以下结构:

module Library
  class DSL
    def met(str)
      # load `str` here; for this case, `MyApplication::MyClass`
    end
  end

  class Superclass
    extend DSL
  end
end


module MyApplication
  class MySubclass < Library::Superclass
    met 'MyClass'
  end

  class MyClass
  end
end

Library::DSL#met 中,我需要加载常量str,它以字符串的形式提供。显然,如果我只是做Object.const_get(str) 是行不通的。

我需要以某种方式在当前范围 (MyApplication::MySubclass) 的上下文中完全解析 str;因此str 将被解析为MyApplication::MyClass。我需要完全解决这个问题,因为稍后我需要在这个命名空间之外使用这个常量。

【问题讨论】:

  • 我猜A.const_get('C') 太具体了?
  • 确实如此。这只是一个简化的例子,我所追求的不断加载是在库级别,所以它不知道A。基本上,它需要在当前范围内解析C,然后加载它(即:看到C实际上是A::C,然后加载它)。
  • 所以你想像 Ruby 解析文字 C 那样动态解析常量,即它应该考虑嵌套和继承?
  • 我已更新我的问题以更好地反映我的问题的性质。 @Stefan
  • 为什么不传递常量(即类)而不是其名称?

标签: ruby constants


【解决方案1】:

当解析一个常量时,Ruby 首先检查模块的当前嵌套,然后检查最内层模块的祖先。

这可以通过遍历Module.nestingModule.nesting.first.ancestors(按此顺序)来复制。如果一个模块定义了常量,我们可以通过const_get获取它的值:

class A
  class B
    def met
      str = 'C'
      mods = Module.nesting
      mods.concat(mods.first.ancestors)
      mod = mods.find { |c| c.const_defined?(str, false) }
      mod.const_get(str)
    end
  end

  class C
  end
end

A::B.new.met #=> A::C

【讨论】:

  • 我看到Module.nesting 在结构上确定了嵌套,在它被调用的地方。但是,我的设置有点复杂。 A::B 实际上包含在另一个类(class D; include A::B; end)中,它是其他类(class E &lt; D; end)的基类。在E 内部,我需要加载这个常量C,它通常与E 在同一个命名空间中找到,但不一定。所以,归根结底,我正在寻找与Module.nesting 相同的东西,但是是动态的(对实际调用它的嵌套执行相同的查找)。很抱歉让事情变得如此混乱。
  • @linkyndy 不确定我是否可以关注。你能相应地更新你的问题吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-01-13
  • 2016-11-09
  • 1970-01-01
  • 2011-05-15
  • 1970-01-01
  • 2010-11-11
  • 1970-01-01
相关资源
最近更新 更多