Я люблю функциональность автозагрузки Ruby; однако уходит в будущих версиях Ruby, поскольку он никогда не был потокобезопасным.
Итак, прямо сейчас я хотел бы притвориться, что он уже ушел, и написать свой код без него, реализовать механизм ленивой загрузки. Я хотел бы реализовать его самым простым способом (сейчас я не забочусь о безопасности потоков). Ruby должен позволить нам это сделать.
Пусть начнется добавление класса 'const_missing
:
class Dummy
def self.const_missing(const)
puts "const_missing(#{const.inspect})"
super(const)
end
end
Ruby вызовет этот специальный метод, когда мы попытаемся ссылаться на константу в "Dummy", которая отсутствует, например, если мы попытаемся ссылаться на "Dummy:: Hello", она вызовет const_missing
с символом :Hello
. Это именно то, что нам нужно, поэтому давайте возьмем его дальше:
class Dummy
def self.const_missing(const)
if :OAuth == const
require 'dummy/oauth'
const_get(const) # warning: possible endless loop!
else
super(const)
end
end
end
Теперь, если мы ссылаемся на "Dummy:: OAuth", для этого потребуется файл "dummy/oauth.rb", который, как ожидается, определит константу "Dummy:: OAuth". Там существует возможность бесконечного цикла, когда мы вызываем const_get
(поскольку он может вызывать const_missing
внутренне), но защита от этого выходит за рамки этого вопроса.
Большая проблема заключается в том, что все это решение разрушается, если в пространстве имен верхнего уровня существует модуль с именем "OAuth". Ссылка "Dummy:: OAuth" пропустит его const_missing
и просто верните "OAuth" с верхнего уровня. Большинство реализаций Ruby также предупреждают об этом:
warning: toplevel constant OAuth referenced by Dummy::OAuth
Это было сообщено как проблема еще в 2003 году, но я не мог найти доказательств того, что основная команда Ruby когда-либо беспокоилась об этом. Сегодня большинство популярных реализаций Ruby несут одинаковое поведение.
Проблема заключается в том, что const_missing
молча пропускается в пользу константы в пространстве имен верхнего уровня. Этого не произойдет, если объявить "Dummy:: OAuth" с помощью функции Ruby autoload
. Любые идеи, как обойти это?