如何在没有警告的情况下重新定义 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_define
?以及如何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 的答案不会产生警告,而且更好。
I'm running some Ruby code which evals a Ruby file every time its date changes. In the file, I have constant definitions, like
Tau = 2 * Pi
and, of course, they make the interpreter display the unwanted "already initialized constant" warning every time, so, I'd like to have the following functions:
def_if_not_defined(:Tau, 2 * Pi)
redef_without_warning(:Tau, 2 * Pi)
I could avoid the warning by writing all my constant definitions like this:
Tau = 2 * Pi unless defined?(Tau)
but it is inelegant and a bit wet (not DRY).
Is there a better way to def_if_not_defined
? And how to redef_without_warning
?
--
Solution thanks to 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
--
This question is old. The above code is only necessary for Ruby 1.8. In Ruby 1.9, P3t3rU5's answer produces no warning and is simply better.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
以下模块可能会执行您想要的操作。如果没有,它可能会为您的解决方案提供一些指示
作为使用它的示例
给出以下输出
如果我在这里打破了任何 ruby 禁忌,请原谅我,因为我仍在了解其中的一些 Module:Class:Eigenclass 结构红宝石
The following module may do what you want. If not it may provide some pointers to your solution
And as an example of using it
Gives the following output
Forgive me if i've broken any ruby taboos here as I am still getting my head around some of the Module:Class:Eigenclass structure within Ruby
这里讨论了另一种方法,使用 $VERBOSE 来抑制警告: http:// mentalized.net/journal/2010/04/02/suppress_warnings_from_ruby/
更新 2020/5/6:为了回应链接现已失效的评论,我在这里粘贴了我旧项目中的一个示例,尽管我不能说这是否以及在什么情况下这是一个好方法:
Another approach, using $VERBOSE, to suppress warnings, is discussed here: http://mentalized.net/journal/2010/04/02/suppress_warnings_from_ruby/
Update 2020/5/6: In response to the comment that the link is now dead, I am pasting an example here from my old project, though I can't say whether and in what circumstances it is a good approach:
如果你想重新定义一个值,那么不要使用常量,而是使用全局变量($tau = 2 * Pi),但这也不是一个好的做法。您应该将其设为合适类的实例变量。
对于另一种情况,
Tau = 2 * Pi 除非定义?(Tau)
完全没问题,而且可读性最强,因此是最优雅的解决方案。If you want to redefine a value then don't use constants, use a global variable instead ($tau = 2 * Pi), but that's not a good practice too. You should make it an instance variable of a suitable class.
For the other case,
Tau = 2 * Pi unless defined?(Tau)
is perfectly alright and the most readable, therefore the most elegant solution.除非常量的值非常奇怪(即您将常量设置为 nil 或 false),否则最好的选择是使用条件赋值运算符: Tau ||= 2*Pi
如果 Tau 为
nil
、false
或未定义,则将 Tau 设置为 2π,否则不理会它。Unless the values of the constants are pretty weird (i.e. you have constants set to
nil
orfalse
), the best choice would be to use the conditional assignment operator:Tau ||= 2*Pi
This will set Tau to 2π if it is
nil
,false
or undefined, and leave it alone otherwise.(问题底部令人费解的答案是指我没有看到的 P3t3rU5 的答案。答案中有一个重要方面不在 Steve Weet 中,我一开始就错过了 - 使用“class Object” ”。之前我必须在 https://stackoverflow.com/a/11503625/18096 上有效地阅读相同的答案也许其他人会从对问题关键的阐述中受益。)
我的用例通常会丢弃临时的实验性更改,代码如下:
...答案越小越好。不过,按照 Paul Lynch 的说法,删除
-w
并没有什么帮助,nil
删除$VERBOSE
却可以。不过,也许我们不想在新的初始化程序中禁用警告,所以:哦,好吧:
(The answer that's puzzlingly at the bottom of the question refers to an answer from P3t3rU5 that I don't see. There's an important aspect of the answer there that's not in Steve Weet's and which I missed at first - the use of "class Object". I had to read effectively the same answer over at https://stackoverflow.com/a/11503625/18096 before understanding the one here. Perhaps others would benefit from an elaboration of the crux of the matter.)
My use-cases are usually throw away temporary experimental changes, in code like this:
... where the smaller the answer the better. Dropping the
-w
doesn't help, though, per Paul Lynch,nil
ing out$VERBOSE
does. Still, perhaps we don't want to disable warnings in the new initializer, so:Oh, alright then: