Удобная работа с With

Проект месяца 1 место Программист Ruby Писатель 3 место 3 место Учитель Организатор конкурсов 1 место в Готв Ветеран Проект месяца 2 место
Больше
11 года 8 мес. назад - 11 года 8 мес. назад #73485 от DeadElf79
Этот метод мне сильно понравился еще в будни использования VisualBasic, а позднее - и в Delphi. Сегодня я хочу показать его и вам.

Как это работает?
Допустим, у вас есть какой-нибудь объект, содержащий несколько методов, которые вам нужно вызывать последовательно, чтобы добиться нужного результата. Чаще всего это можно заметить в отрисовке в различных меню и вот как оно выглядит:
Code:
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)?
  1. Скопировать и вставлять с помощью Ctrl+C и Ctrl+V
  2. Использовать With

Так выглядит код во втором случае:
Code:
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:
Code:
def with(instance, &block) instance.instance_eval(&block) instance end

Он получает переменную и выполняет в ее контексте указанные в блоке действия, после чего возвращает саму переменную. В качестве переменной также может быть вызов конструктора какого-либо класса. Пример:
Code:
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

У этого метода есть только одно строгое правило - переменная (точнее - передаваемый объект) должен быть указан в скобках перед блоком.

Более сложный пример для самых навороченных (или ленивых?):
Code:
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. Как-то так:
Code:
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)
Последнее редактирование: 11 года 8 мес. назад пользователем DeadElf79.
Спасибо сказали: Lekste, Ren310, strelokhalfer, Amphilohiy, yuryol, KageDesu

Пожалуйста Войти или Регистрация, чтобы присоединиться к беседе.

Проект месяца 1 место Программист Ruby Писатель 3 место 3 место Учитель Организатор конкурсов 1 место в Готв Ветеран Проект месяца 2 место
Больше
11 года 8 мес. назад #73486 от DeadElf79
DeadElf79 ответил в теме Удобная работа с With
Обнаружил небольшую ошибку во втором (расширенном) примере, по причине возникновения которой не рекомендую все же использовать несколько with один в другом.
Code:
def refresh with (self.contents) { clear with(font) { color=system_color bold=true } # по окончании блока изменения могут никак не отразиться на шрифте draw_text(0,0,width-32,32,'Some Text') } end

Лучше использовать:
Code:
def refresh with (self.contents) { clear font.color=Color.new(255,0,0) font.bold=true draw_text(0,0,width-32,32,'Some Text') } end

Оригинала реализации clear у меня нет, поэтому я предполагаю, что в этом методе так же сбрасываются все изменения шрифта так как переопределение шрифта перед перерисовкой текста сбрасывает сделанные изменения.

Также, обнаружилось дополнительное правило, вполне логичное, но незамеченное мною изначально:
Все выполняется в контексте указанного объекта. Соответственно, использовать метод system_color из класса Window_Base, содержащего Bitmap (в contents) уже нельзя. Если придумаю как можно красиво обойти это - дополню тему.
Спасибо сказали: strelokhalfer

Пожалуйста Войти или Регистрация, чтобы присоединиться к беседе.

Программист Ruby Организатор конкурсов Даритель Стимкея 2 место Сбитая кодировка Переводчик 2 место
Больше
11 года 2 мес. назад #78773 от strelokhalfer
Перенес в Факультет, думаю, там оно нужнее.

"Стрелок, что-то ты неочень похож на свой аватар..."(с)

Пожалуйста Войти или Регистрация, чтобы присоединиться к беседе.

Время создания страницы: 0.098 секунд
Работает на Kunena форум