Как новый сеанс IRB получает свою переменную область?
IRB - хороший способ поиграть и проверить что-то в Ruby. Также возможно выполнить некоторые настройки, используя скрипт, например:
require 'irb'
class Pirate
def greet
puts "Arrrrr, nice to meet ya"
end
end
IRB.start # You can now instantiate Pirate in IRB
Однако одна вещь, по которой я неясен, это переменная область действия при этом. Если я добавлю эти строки раньше IRB.start
:
smithy = Pirate.new
@blackbard = Pirate.new
... @blackbeard
будет доступен в IRB, но ссылка smithy
получите undefined local variable or method 'smithy' for main:Object
,
Зачем?
1 ответ
Binding
который используется для оценки кода установлен в irb/workspace.rb:51
(Я имею в виду Ruby 1.9.3 rev 35410 здесь):
@binding = eval("def irb_binding; binding; end; irb_binding",
TOPLEVEL_BINDING,
__FILE__,
__LINE__ - 3)
Это означает, что ваш сеанс IRB выполняется в том же контексте, что и код внутри метода верхнего уровня. Заметим:
puts "Outer object ID: %d" % self.object_id
puts "Outer binding: " + binding.inspect
smithy = Pirate.new
@blackbard = Pirate.new
def test
puts "Inner object ID: %d" % self.object_id
puts "Inner binding: " + binding.inspect
p @blackbard
p smithy
end
test
Выход:
Outer object ID: 13230960
Outer binding: #<Binding:0x00000001c9aee0>
Inner object ID: 13230960
Inner binding: #<Binding:0x00000001c9acd8>
#<Pirate:0x00000001c9ada0>
/test.rb:18:in `test': undefined local variable or method `smithy' for main:Object (NameError)
...
Обратите внимание, что контекст объекта (self
) одинаково как внутри, так и снаружи функции. Это потому, что каждый метод верхнего уровня добавляется в глобальный main
объект.
Также обратите внимание, что привязки внутри и снаружи метода различаются. В Ruby у каждого метода есть своя область имен. Вот почему вы не можете получить доступ к локальному имени из IRB, а можете получить доступ к переменной экземпляра.
Честно говоря, IRB - не самая лучшая часть программного обеспечения Ruby. Я обычно использую Pry для такого рода вещей, используя которые вы можете просто сделать:
require 'pry'
binding.pry
И есть сеанс с доступом к текущим локальным переменным.