如何在没有警告的情况下重新定义Ruby常量?

时间:2010-07-30 21:07:42

标签: ruby constants redefine redefinition

我正在运行一些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的答案不会产生任何警告,只是更好。

4 个答案:

答案 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)

除非常量的值非常奇怪(即常量设置为nilfalse),否则最好的选择是使用条件赋值运算符:Tau ||= 2*Pi < / p>

如果Tau为nilfalse或未定义,则会将Tau设置为2π,否则请将其保留。