#ruby #string #variables #menu #highline
#ruby #строка #переменные #меню #highline
Вопрос:
Документация HighLine показывает, что мы можем отобразить строку после того, как пользователь выберет опцию из списка, следующим образом:
choose do |menu|
menu.prompt = "Please choose your favorite programming language? "
menu.choice(:ruby) { say("Good choice!") }
menu.choices(:python, :perl) { say("Not from around here, are you?") }
end
Как мы можем установить переменную в дополнение к отображению текста (или вместо него)? Замена say("Good choice!")
на variable = 1
не сработала и вместо этого вернула ошибку «неопределенная локальная переменная или метод».
Ответ №1:
Локальные переменные уничтожаются, когда метод / блок / процедура завершает выполнение. Но вы можете сделать так, что variable
это не локальная переменная блока:
variable = nil
choose do |menu|
variable = 1
menu.prompt = "Please choose your favorite programming language? "
menu.choice(:ruby) { say("Good choice!") }
menu.choices(:python, :perl) { say("Not from around here, are you?") }
end
puts variable
Блок создает то, что называется closure
, что означает, что он может видеть переменные, которые существовали за пределами блока, когда блок был СОЗДАН. С другой стороны, блок не может видеть переменные за пределами блока во время его выполнения — даже если переменные имеют те же имена, что и переменные, которые может видеть блок. Например,
def do_stuff(amp;block)
x = 1
block.call
end
x = 10
do_stuff {puts x}
--output:--
10
Комментарии:
1. Вау, это было просто. Итак, если я правильно понимаю, все переменные, созданные в блоке, будут уничтожены в конце, потеряв все сохраненное ими значение. Однако, если переменная была создана до блока, она сохранит любое значение, присвоенное ей внутри блока?
Ответ №2:
TL; DR ответ заключается просто в том, что вам нужно определить переменную, доступную за пределами области вашего блока.
Прежде всего, ознакомьтесь с документацией API:
http://rubydoc.info/gems/highline/HighLine#choose-instance_method
Вы увидите def choose( *items, amp;details )
, что метод choose принимает аргументы любой длины, а затем также блок. Вы видите, что блок do ... end
передается вызову choose:
choose do |menu|
menu.choice(:meow) {|q| q = 'foo'}
end
Хорошо, итак, мы видим другой метод, который choice
: http://rubydoc.info/gems/highline/HighLine/Menu#choice-instance_method
# File 'lib/highline/menu.rb', line 136
def choice( name, help = nil, amp;action )
@items << [name, action]
@help[name.to_s.downcase] = help unless help.nil?
update_responses # rebuild responses based on our settings
end
Теперь давайте разберем, .choice(:meow) {|q| q = 'foo'}
используя то, что мы видим из choice
. Он ожидает имя (:meow)
, по умолчанию для справки используется значение nil, если оно не указано (поэтому в моем примере вызова оно равно nil), и, наконец, принимает другой блок, который является {|q| q = 'foo'}
.
Мой пример оценивается как:
1. meow
? 1
=> "foo"
q
=> NameError: undefined local variable or method `q' for main:Object
Почему? потому что q определен только в пределах области действия передаваемого блока. Вы не сможете получить к ней доступ после вычисления этой процедуры. Итак, что вам нужно сделать, это:
1.9.3-p448 :015 > choose do |menu|
1.9.3-p448 :016 > menu.choice(:meow) { @foo = 'foo'}
1.9.3-p448 :017?> end
1. meow
? 1
=> "foo"
1.9.3-p448 :018 > @foo
=> "foo"