如何在Ruby中为eval创建一个单独的命名空间



我有以下代码:

code = "def hi; "hi!"; end"
eval code
hi == "hi!" # true

我可以访问方法hi,因为当它在评估的代码中定义时,它被定义为主对象的方法。

然而,这也意味着被评估的代码可以访问我在它之外定义的东西:

def hi; "hi!"; end
eval "hi == "hi"" # => true

我希望有一个单独的名称空间,我可以在其中运行经过评估的代码;我该怎么做?

我尝试过使用module_eval并为命名空间使用模块,但我无法让它定义一个方法或类,并在另一个评估中访问它。

您可以评估对象内部的代码,如下所示:

  module DSL
    def helper_method_to_be_used_by_evaled_code
      # ...
    end
    # ...
  end
  container = Object.new
  container.extend(DSL)
  File.open(eval_file1, 'r') {|f| container.instance_eval(f.read, eval_file1)}
  File.open(eval_file2, 'r') {|f| container.instance_eval(f.read, eval_file2)}

有了这个,您可以控制是否在eval之间保留定义:您可以重用container实例,也可以处理它并创建新实例。这将适用于方法定义和常量,在这样的调用之间不会保留局部变量。

此外,您可能希望查看BlankState模式,而不是Object。"blankslate"就是一个例子。

您似乎并不是在谈论将模块作为评估代码的一部分,所以这样的东西应该很好:

module EvalMethods
  class << self
    code = "def hi; "hi!"; end"
    eval code
  end
end
puts EvalMethods::hi == "hi!"

最新更新