Рубиновые привязки - область действия локальных переменных и констант - PullRequest
3 голосов
/ 26 января 2012

Я хочу запустить 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 Ответ

5 голосов
/ 27 января 2012

Поведение, которое вы наблюдаете, нормальное.Когда вы выполняете C = 1 в области вызова NameSpaces.namespace, постоянная "C" определяется для NameSpaces.(Вы можете подтвердить это, попробовав 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

Обратите внимание, что любые константы, определенные в Object (т. Е. Глобальная область), будут доступны в коде, переданном в eval, и если значения таких констант будут изменены воцененный код, изменение будет видно глобально!

(Даже если вы оцениваете код в контексте BasicObject, который не наследуется от Object, оцененный код может по-прежнему констант доступаопределено для объекта путем добавления префикса имени к «::»)

...