Константа уровня класса сломана в 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]
Ruby 2.3.3
#<Dummy:0x007fbd6d162380>
Ruby 2.3.4
NameError: uninitialized constant TEST
Цель состояла в том, чтобы только инициализировать TEST
один раз и .new
быть частным Memoizing @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]
Руби 2.3.3 и 2.3.4
#<Dummy:0x007fbd6d162380>
1 ответ
Как исправить
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 с открытым исходным кодом. В этом коммите была исправлена ошибка #12478. В сообщении коммита явно указывается, что оно меняет поведение при работе с немодульными объектами.
Символы не преобразуются в String
и больше продаются отдельно, :TEST
не расширяется Dummy
уровень и константа не могут быть разрешены в другом контексте.
Почему это не ошибка
Нет смысла объявлять константы в одноэлементных классах (сверьтесь со старым кодом):
Dummy.constants
#⇒ []
Dummy.singleton_class.constants
#⇒ [:TEST]
Константа была успешно разрешена в устаревшей реализации точно так же, как умножение двух отрицательных значений дает положительный результат: ошибки сводятся на нет. Код не работал должным образом, иногда он дважды не удавался неожиданным, но ценным способом, давая правильный результат.