我正在运行一些Ruby代码,每次日期更改时都会破坏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
?
-
解决方案感谢史蒂夫:
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的答案不会产生任何警告,只是更好。
答案 0 :(得分:60)
以下模块可以执行您想要的操作。如果没有,它可能会为您的解决方案提供一些指示
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中的特征类结构
答案 1 :(得分:4)
如果你想重新定义一个值,那么不要使用常量,而是使用全局变量($ tau = 2 * Pi),但这也不是一个好习惯。你应该把它变成一个合适的类的实例变量。
对于另一种情况,Tau = 2 * Pi unless defined?(Tau)
完全没问题且是最易读的,因此也是最优雅的解决方案。
答案 2 :(得分:3)
此处讨论使用$ VERBOSE抑制警告的另一种方法:http://mentalized.net/journal/2010/04/02/suppress_warnings_from_ruby/
答案 3 :(得分:2)
除非常量的值非常奇怪(即常量设置为nil
或false
),否则最好的选择是使用条件赋值运算符:Tau ||= 2*Pi
< / p>
如果Tau为nil
,false
或未定义,则会将Tau设置为2π,否则请将其保留。