Внедрение локальной переменной в привязку - PullRequest
5 голосов
/ 12 марта 2012

Я пытаюсь установить локальную переменную для существующей привязки

def foo_callback
  lambda { |name| p name }
end
b = foo_callback.binding

В привязке нет начальных локальных переменных:

b.eval("local_variables") # => []

Давайте установимпримитивная локальная переменная для привязки:

b.eval("age=30")

Все работает как положено:

b.eval("local_variables") # => ["age"]
b.eval("age") # => 30

Теперь давайте попробуем установить непримитивную локальную переменную для привязки:

country = Country.first
b.eval("lambda {|v| country = v}").call(country)

Примечание: Техника для задания переменной заимствована из камня facet.Я попробовал реализацию ruby ​​1.9 safe с теми же результатами.

Привязка не отражает локальную переменную country.

b.eval("local_variables") # => ["age"]

Как мне обойти этовопрос?По сути, я хочу объявить новую переменную в привязке, используя значение существующей, не примитивной переменной.

Я на Ruby 1.8.7.

Ответы [ 2 ]

5 голосов
/ 12 марта 2012

Вы создаете country вне привязки, и тогда country внутри lambda действует только в этой области.Почему бы не eval, если вам нужно добавить это в привязку?

Обновление

Попробуйте объявить переменную вне области действия lambdaно внутри объема переплета:

 b.eval("country = nil; lambda {|v| country = v}").call(country)
2 голосов
/ 12 марта 2012

Проблема в том, что вы создаете новую лямбду в другой лямбде, и это создает новую область видимости.

Для большей ясности, привязка 'b' будет иметь в своей области действия все локальные переменные, доступные в области действия функции #foo_callback, и все локальные переменные, доступные в первой лямбде. Вторая лямбда, которую вы создали, - это новая область действия, и поэтому новые локальные переменные, созданные в этой области, не сохраняются за пределами области действия, если они не инициализируются вначале за пределами внутренней области.

Вот почему вы увидите, как многие люди инициализируют локальные переменные как nil перед входом в блок. Вы также можете сделать это, что делает то же самое:

country = country
{...block that sets country to something non-nil...}
return country

Переменные экземпляра не имеют этой проблемы с областью видимости и доступны во внутренней и внешней областях функции.

Пример:

b.eval("lambda {|c| @country = c}").call(country)
b.eval "instance_variables"

должно работать.

И кто-то избил меня до ответа, когда я писал это:)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...