Class 关卡常量在 Ruby 2.3.4 中被破坏

Class level constant broken in Ruby 2.3.4

我有一些代码可以简化为以下内容。它适用于 Ruby 2.3.3 并在 2.3.4 上中断。它有点奇怪,我欢迎提供有关如何重写它的建议以及它为什么会损坏的解释。

require 'forwardable'

class Dummy
  class << self
    TEST = {
      a: Dummy.new,
      b: Dummy.new
    }

    extend Forwardable

    def_delegators :TEST, :[]

    private :new
  end
end

puts Dummy[:a]

Ruby2.3.3

#<Dummy:0x007fbd6d162380>

Ruby 2.3.4

NameError: uninitialized constant TEST

目标是只初始化 TEST 一次并且 .new 是私有的。在 [] 方法中记忆 @test 变量不起作用,因为 new 在哈希创建时是私有的。

编辑

从等式中删除 Forwardable 解决了问题,但我仍然很好奇为什么以及如何改进它的想法。

class Dummy
  class << self
    TEST = {
      a: Dummy.new,
      b: Dummy.new
    }

    def [](key)
      TEST[key]
    end

    private :new
  end
end

puts Dummy[:a]

Ruby 2.3.3 和 2.3.4

#<Dummy:0x007fbd6d162380>

如何修复

require 'forwardable'

class Dummy
  Test = {
    a: Dummy.new,
    b: Dummy.new
  }

  class << self
    extend Forwardable

    def_delegators :"::Dummy::Test", :[]

    private :new
  end
end

puts Dummy[:a]

为什么

Ruby 是开源的。有一个bug #12478, fixed in that commit。提交的消息明确指出它在处理 非模块对象 .

时改变了行为

符号为not converted to Strings anymore and dealed separately, :TEST is not expanded on Dummy level and the constant could not be resolved in different context

为什么这不是错误

在单例上声明常量没有任何意义 类(检查您的旧代码):

Dummy.constants
#⇒ []
Dummy.singleton_class.constants
#⇒ [:TEST]

常数在遗留实现中成功解决,与乘以两个负数得到正结果完全相同:错误被否定。代码运行不正常,偶尔会以意想不到的方式失败两次,但会产生正确的结果。