2010-07-30 65 views
51

我正在运行一些Ruby代码,它会在每次更改日期时发送一个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的答案不会产生任何警告,而是更好。

+5

为什么你想重新定义一个常数?更好地将常量保存在你自己的类或模块中,这样它们永远不会与其他常量发生冲突。 – 2010-07-30 21:11:44

+1

我想重新定义一个常量,因为我想自然地使用常量,就像我没有使用自动源代码重载器一样,所以我不会接受任何“只是不使用常量”的答案。 – 2010-07-30 21:19:16

+2

什么是不雅而不干的关于'Tau = 2 * Pi除非定义?(Tau)'? – jrdioko 2010-12-08 17:42:36

回答

58

以下模块可以做你想做的。如果没有它可以提供一些指引,以您的解决方案

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 

原谅我,如果我打破任何红宝石禁忌在这里,因为我仍然在我的头部周围的一些模块:类:红宝石内的本征类结构

+0

当然,这个答案的关键是首先调用Object.send(:remove_const,'Tau')如果Object.const_defined?('Tau')',它定义了常量,从而抢占警告。伟大的方法。 – ghayes 2013-08-11 22:38:44

+0

是的,或者只是'发送(:remove_const,:CONST)如果const_defined?(:CONST)'如果你在类(不是实例)范围。 – thewoolleyman 2014-06-18 23:32:38

4

如果你想重新定义一个值,那么不要使用常量,而应该使用全局变量($ tau = 2 * Pi),但这也不是一个好习惯。你应该把它作为合适类的实例变量。

对于另一种情况,Tau = 2 * Pi unless defined?(Tau)是完全正确的,最具可读性,因此是最优雅的解决方案。

2

除非常量的值是非常奇怪的(即你必须设置为nilfalse常数),最好的选择是使用条件赋值运算符:Tau ||= 2*Pi

这将设置头到2π,如果它是nil,false或未定义,否则保持不变。

+1

不错的想法...不幸的是,它不是很便携:取决于ruby的版本和实现(ruby/jruby),对|| =常数的作用给了我三种不同的结果。要么它按照预期安静地工作(jruby1.5),要么我得到一个“未初始化的常量”失败(ruby1.8),要么即使没有发生任何动作(jruby1.2)也会发出警告。 – 2010-07-30 22:05:21

3

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

+2

是的。正如您的链接中提到的,在Rails中存在一个更好的silence_warnings实现:http://api.rubyonrails.org/classes/Kernel.html#M002564但是这种方法不如公认的答案,因为它可能对其他方面有副作用线程。 – 2012-08-30 23:23:09

1

以下情况如何?

TAU ||= 2 * Pi 

它适用于我正在研究的宝石。

+5

这永远不会重新定义一个常数,所以不是问题的答案。它怎么得到8票? – jrochkind 2016-05-02 22:57:40

+1

好吧,它回答了def_if_not_defined(:Tau,2 * Pi),我认为这是原始问题,不确定,很久以前 – P3t3rU5 2017-02-28 23:31:04

+1

也重新定义常量是对语言的滥用,即使您可以做到这一点,这并不意味着你应该这样做 – P3t3rU5 2017-02-28 23:32:15

相关问题