我如何解决Ruby的eval和“已经初始化的常量”?

时间:2011-12-23 07:34:21

标签: ruby eval

我继承了使用eval()作为评估规则引擎中用Ruby代码编写的规则的应用程序的维护。我知道有其他方法的很多,但到目前为止,代码库非常大,而且在此时将其更改为其他内容会非常耗时。所以假设我暂时停止使用eval()

编写的规则通常会从数据库中调用一些相同的对象,并且规则编写器为规则中的变量赋予彼此相同的名称。这导致在开发期间控制台中的页面和页面“已初始化的常量”警告。

我想知道几件事:

首先,如果感觉就像那些正在减慢开发环境中程序执行速度的那样,那么我想知道它是否在生产环境中是一个很大的性能影响,特别是那些警告弹出,而不是eval()本身,我知道这是一个打击。

第二,有没有办法“命名”每个规则的执行,这样它就不会在与请求中所有其他evals相同的范围内定义变量,以避免在整个地方弹出警告?我知道我可以重写所有规则以使用||=语法或检查名称是否已经定义,但是它们中有很多,所以我宁愿从运行{{1如果可能的话。}

**更新示例规则** 一个问题有关于何时向用户显示的规则。例如,如果用户声明他们住在公寓中,则可能需要显示另一个问题以询问公寓楼的大小。所以第二个问题的rule_text可能看起来像:

eval()

调用eval的代码确保在评估之前在范围内有一个current_user变量。

1 个答案:

答案 0 :(得分:1)

呃,eval不是最标准的金币。你可以启动一个drb实例并运行其中的东西而不是eval,这样你至少可以控制正在发生的事情并且不会污染你自己的命名空间。

http://segment7.net/projects/ruby/drb/introduction.html


编辑:在同一过程中添加了另一个运行代码的答案:

我不知道您的规则代码是如何看的,但是可以围绕它包装模块:

# create a module
module RuleEngineRun1;end
# run code in module
RuleEngineRun1.module_eval("class Foo;end")

# get results
#....

# cleanup
Object.send(:remove_const, :RuleEngineRun1)

如果您需要并行运行代码,还可以使用Module.new创建一个匿名模块{#block to eval'd}。


在以后的红宝石中,您可以添加-W0来运行代码而不打印警告,但这样做可能会导致错误被忽视:

$ cat foo.rb 
FOO = :bar
FOO = :bar

$ ruby foo.rb 
foo.rb:2: warning: already initialized constant FOO

$ ruby -W0 foo.rb 

你也可以在Kernel.silence_warnings块中运行你的eval,但是如果你真的遇到了eval'd代码的一些实际问题,那么也可能是毁灭性的,请参阅 Suppress Ruby warnings when running specs