Этот метод мне сильно понравился еще в будни использования VisualBasic, а позднее - и в Delphi. Сегодня я хочу показать его и вам.
Как это работает?
Допустим, у вас есть какой-нибудь объект, содержащий несколько методов, которые вам нужно вызывать последовательно, чтобы добиться нужного результата. Чаще всего это можно заметить в отрисовке в различных меню и вот как оно выглядит:
def refresh
self.contents.clear
self.contents.font.color=system_color
self.contents.font.bold=true
self.contents.draw_text(0,0,width-32,32,'Some Text')
end
Что вы можете сделать, чтобы не переписывать один и тот же кусок текста (
self.contents)?
- Скопировать и вставлять с помощью Ctrl+C и Ctrl+V
- Использовать With
Так выглядит код во втором случае:
def refresh
with (self.contents) {
clear
font.color=system_color
font.bold=true
draw_text(0,0,width-32,32,'Some Text')
}
end
Неправда ли, куда проще?
Описание with
Так выглядит сам метод with, который добавляется прямо в Kernel:
def with(instance, &block)
instance.instance_eval(&block)
instance
end
Он получает переменную и выполняет в ее контексте указанные в блоке действия, после чего возвращает саму переменную. В качестве переменной также может быть вызов конструктора какого-либо класса. Пример:
def with(instance, &block)
instance.instance_eval(&block)
instance
end
class Abc
def some
'some'
end
def somedo
'moar some'
end
end
name=Abc.new
puts name.class
with (name) {
puts some
puts somedo
}
new_name=with (Abc.new) { puts some }
puts new_name.class
У этого метода есть только одно строгое правило - переменная (точнее -
передаваемый объект) должен быть указан в скобках перед блоком.
Более сложный пример для самых навороченных (или ленивых?):
def with(instance, &block)
instance.instance_eval(&block)
instance
end
class Abc
attr_reader :defg
def initialize
@defg=Defg.new
end
def some
'some'
end
def somedo
'moar some'
end
class Defg
def moar_work
'i\'m feelin\' lucky!'
end
end
end
name=Abc.new
with (name) {
with(defg) {
puts moar_work
}
}
В данном случае мы видим пример того, что в отрисовке можно при желании можно в такой же блок метода with вписать помимо
self.contents еще и
font. Как-то так:
def refresh
with (self.contents) {
clear
with(font) {
color=system_color
bold=true
}
draw_text(0,0,width-32,32,'Some Text')
}
end
Оригинал кода взят из ответа на данный вопрос:
#with(object) &block trick (StackOverflow.com)