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

Eld*_*rum 55 ruby constants redefine redefinition

我正在运行一些Ruby代码,每次日期更改时都会破坏Ruby文件.在文件中,我有不断的定义,比如

Tau = 2 * Pi
Run Code Online (Sandbox Code Playgroud)

当然,它们使解释器每次都显示不需要的"已初始化的常量"警告,所以,我想要具备以下功能:

def_if_not_defined(:Tau, 2 * Pi)
redef_without_warning(:Tau, 2 * Pi)
Run Code Online (Sandbox Code Playgroud)

通过编写我的所有常量定义,我可以避免警告:

Tau = 2 * Pi unless defined?(Tau)
Run Code Online (Sandbox Code Playgroud)

但它不够优雅,有点潮湿(不是).

有更好的方法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
Run Code Online (Sandbox Code Playgroud)

-

这个问题很老了.上面的代码只对Ruby 1.8有用.在Ruby 1.9中,P3t3rU5的答案不会产生任何警告,只是更好.

Ste*_*eet 61

以下模块可以执行您想要的操作.如果没有,它可能会提供一些指向您的解决方案

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
Run Code Online (Sandbox Code Playgroud)

并作为使用它的一个例子

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
Run Code Online (Sandbox Code Playgroud)

给出以下输出

Foo is ABC
Bar is DEF
Foo is GHI
Bar is JKL
Run Code Online (Sandbox Code Playgroud)

请原谅我,如果我在这里打破了任何红宝石禁忌,因为我仍然围绕着一些模块:类:Ruby中的Eigenclass结构


Pau*_*nch 6

此处讨论了另一种使用 $VERBOSE 来抑制警告的方法:http : //mentalized.net/journal/2010/04/02/suppress_warnings_from_ruby/

2020 年 5 月 6 日更新:针对链接现已失效的评论,我将旧项目中的示例粘贴到此处,但我不能说这是否以及在什么情况下是一个好方法:

original_verbose = $VERBOSE
$VERBOSE = nil # suppress warnings
# do stuff that raises warnings you don't care about
$VERBOSE = original_verbose
Run Code Online (Sandbox Code Playgroud)

  • 是的。正如您在链接中提到的,Rails 中存在更好的 Silence_warnings 实现:http://api.rubyonrails.org/classes/Kernel.html#M002564 但这种方法不如公认的答案,因为它可能对其他线程。 (2认同)