Я выполняю некоторый код Ruby, какой evals Ruby регистрирует каждый раз свои изменения даты. В файле у меня есть постоянные определения, как
Tau = 2 * Pi
и, конечно, они заставляют интерпретатор отобразиться, нежелательное "уже инициализировало постоянное" предупреждение каждый раз, таким образом, я хотел бы иметь следующие функции:
def_if_not_defined(:Tau, 2 * Pi)
redef_without_warning(:Tau, 2 * Pi)
Я мог избежать предупреждения путем записи всех моих постоянных определений как это:
Tau = 2 * Pi unless defined?(Tau)
но это неэлегантно и немного влажно (не DRY).
Есть ли лучший путь к def_if_not_defined
? И как к redef_without_warning
?
--
Решение благодаря Steve:
class Object
def def_if_not_defined(const, value)
mod = self.is_a?(Module) ? self : self.class
mod.const_set(const, value) unless mod.const_defined?(const)
end
def redef_without_warning(const, value)
mod = self.is_a?(Module) ? self : self.class
mod.send(:remove_const, const) if mod.const_defined?(const)
mod.const_set(const, value)
end
end
A = 1
redef_without_warning :A, 2
fail 'unit test' unless A == 2
module M
B = 10
redef_without_warning :B, 20
end
fail 'unit test' unless M::B == 20
--
Этот вопрос стар. Вышеупомянутый код только необходим для Ruby 1.8. В Ruby 1.9 ответ P3t3rU5 не производит предупреждения и просто лучше.
Следующий модуль может сделать то, что вы хотите. Если нет, он может дать несколько указателей на ваше решение
module RemovableConstants
def def_if_not_defined(const, value)
self.class.const_set(const, value) unless self.class.const_defined?(const)
end
def redef_without_warning(const, value)
self.class.send(:remove_const, const) if self.class.const_defined?(const)
self.class.const_set(const, value)
end
end
И как пример его использования
class A
include RemovableConstants
def initialize
def_if_not_defined("Foo", "ABC")
def_if_not_defined("Bar", "DEF")
end
def show_constants
puts "Foo is #{Foo}"
puts "Bar is #{Bar}"
end
def reload
redef_without_warning("Foo", "GHI")
redef_without_warning("Bar", "JKL")
end
end
a = A.new
a.show_constants
a.reload
a.show_constants
Дает следующий вывод
Foo is ABC
Bar is DEF
Foo is GHI
Bar is JKL
Простите меня, если я нарушил какие-либо табу в Ruby, так как я все еще пытаюсь разобраться в структуре Module:Class:Eigenclass в Ruby
Если вы хотите переопределить значение, не используйте константы, используйте вместо них глобальную переменную ($ tau = 2 * Pi), но это тоже не очень хорошая практика. Вы должны сделать его переменной экземпляра подходящего класса.
Для другого случая Tau = 2 * Pi, если не определено? (Tau)
совершенно нормально и наиболее читабельно, поэтому является наиболее элегантным решением.
Если только значения констант не являются довольно странными (например, константы установлены в nil
или false
), лучшим выбором будет использование условного оператора присваивания: Tau ||= 2*Pi
Это установит Tau в 2π, если оно nil
, false
или неопределено, и оставит его в покое в противном случае.