Ruby绑定 - 局部变量与常量的范围

时间:2012-01-26 18:46:42

标签: ruby binding scope constants

我想运行字符串的eval来定义局部变量和常量。 我想在不同的命名空间中执行此操作。我可以用局部变量做到这一点 但不是常数。有没有办法修改下面的NameSpaces模块 这样一个绑定/命名空间中定义的常量不会被另一个看到?

# Example run under ruby 1.9.1
module NameSpaces
  def self.namespace(namespace)
    return binding
  end
end

b1 = NameSpaces.namespace("b1")
b2 = NameSpaces.namespace("b2")

# Set a 'x', then check to make sure its still set in the scope of 'b1'
puts b1.eval("x = 1") # => 1
puts b1.eval("x")     # => 1

# Check to make sure 'x' is NOT set in the scope of 'b2'
begin
  puts b2.eval("x") # NameError exception expected here
rescue Exception => e
  puts e.to_s       # => undefined local variable or method `x'
                    #  for NameSpaces:Module (THIS IS AS EXPECTED.)
end

# Set constant 'C' and do the same checks
puts b1.eval("C = 1") # => 1
puts b1.eval("C")     # => 1

# Check to make sure 'C' is NOT set in the scope of 'b2'
begin
  puts b2.eval("C")  # (I DON'T GET AN EXCEPTION.  NOT AS I HAD HOPED FOR.)
rescue Exception => e
  puts e.to_s
end

非常感谢你的表情。我很困难。

1 个答案:

答案 0 :(得分:5)

您正在观察的行为是正常的。当您在C = 1的调用范围内执行NameSpaces.namespace时,NameSpaces上会定义一个常量“C”。 (您可以尝试NameSpaces::C确认这一点。)

要获得所需的效果,您需要使用匿名模块的绑定。试试这个:

namespace1 = Module.new.class_eval("binding")
namespace2 = Module.new.class_eval("binding")
namespace1.eval("C = 1")
namespace1.eval("C")
=> 1
namespace2.eval("C")
NameError: uninitialized constant #<Module:0xf09180>::C

请注意,在传递给eval的代码中可以使用Object中定义的任何常量(即全局范围),如果在评估的代码中更改了这些常量的值,则更改将是全球可见!

(即使您在BasicObject的上下文中评估代码,它不从Object继承,评估的代码也可以仍然访问在Object上定义的常量,方法是在名称前加上':: “)