I want to run eval of strings to define both local variables and constants.
I want to do this in different namespaces. I can do this with local variables
but not with constants. Is there a way to modify the NameSpaces module below
so that constants defined in one binding/namespace are not seen by another?
# 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
Thanks so much for the look. I’m very stuck.
The behavior you are observing is normal. When you execute
C = 1in the scope of a call toNameSpaces.namespace, a constant “C” is defined onNameSpaces. (You can confirm this by tryingNameSpaces::C.)To get the effect you want, you need to use the binding of an anonymous module. Try this:
Note that any constants which are defined in Object (i.e. the global scope) will be available within the code passed to
eval, and if the values of such constants are changed in the evaluated code, the change will be visible globally!(Even if you evaluate code in the context of a BasicObject, which doesn’t inherit from Object, the evaluated code can still access constants defined on Object, by prefixing the name with ‘::’)