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

时间:2012-08-26 16:58:34

标签: ruby metaprogramming

我有以下代码:

code = "def hi; \"hi!\"; end"
eval code

hi == "hi!" # true

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

但是,这也意味着评估的代码可以访问我在其外部定义的内容:

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

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

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

2 个答案:

答案 0 :(得分:2)

您可以像这样评估对象内部的代码:

  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)}

通过这种方式,您可以控制是否在evals之间保留定义:您可以重用container实例或处理它并创建新实例。这适用于方法定义和常量,在这些调用之间不保留局部变量。

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

答案 1 :(得分:0)

似乎你不是在谈论让模块成为评估代码的一部分,所以像这样的东西应该可以正常工作:

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

puts EvalMethods::hi == "hi!"