Рубрика:
Разработка /
Особенности языка
|
Facebook
Мой мир
Вконтакте
Одноклассники
Google+
|
ИВАН ШИХАЛЕВ, фрилансер, специализируется на веб-разработке и Ruby, shikhalev@gmail.com
Метапрограммирование в Ruby: разбор примера
Добавление собственных абстракций в объектную модель – это просто. И интересно. От частных примеров – к общим принципам программирования в Ruby
Авторы книги «Programming Ruby: The Pragmatic Program-mers' Guide» называют метапрограммированием расширение и изменение абстракций языка (тогда как собственно программирование пользуется теми, что есть). Конечно, можно поспорить о том, что считать такой абстракцией, а что нет, однако нельзя не заметить, что в современных динамических языках, таких как Ruby или, например, Python, легко делаются некоторые вещи, находившиеся в классических языках именно на языковом уровне и жестко определявшиеся компилятором. Тут можно вспомнить для примера декораторы, о которых я писал в сентябре прошлого года [1]. И сейчас мы рассмотрим нечто подобное. В процессе я буду делать обобщающие отступления, переходя от частного примера к общим принципам программирования в Ruby.
Формулировка задачи
В объектно-ориентированных языках, как правило, имеются такие абстракции, как методы и свойства. В Ruby свойства называются атрибутами, что, впрочем, сути не меняет. Однако в Ruby мы можем и сами определить аналогичные конструкции с нужной нам специфической функциональностью.
Представим, что мы пишем графический редактор, а лучше 3D-конструктор (мебели, например). Нам придется оперировать множеством разнородных (разные классы) объектов, обладающих различными характеристиками, часть которых уместно сделать изменяемыми в процессе редактирования. Характеристики, в общем-то, задаются в разных местах – что-то подгружается из файлов, что-то задается пользователем через поля ввода, что-то меняется посредством мыши и т.д. И, сделав уже половину работы, мы обнаруживаем при тестировании, что отрисовка время от времени выбрасывает ошибку из-за некорректно заданных характеристик – длина доски вдруг оказалась равна строке «стеариновая свечка»...
Проблема в том, что стек вызовов, который мы можем получить из объекта-исключения, в этом случае никак не помогает найти место возникновения реальной ошибки, т.е. то место, где было присвоено некорректное значение, – нужна проверка именно при присваивании. Кроме того, было бы неплохо при изменении некоторых параметров перезапускать процедуру отрисовки.
Ни контроля значений, ни событий при присваивании стандартные атрибуты в Ruby не поддерживают. Конечно, можно вручную определить методы-сеттеры, но лучше все-таки однотипный код вынести в одно определение, которое затем и использовать с различными аргументами. Поскольку термин «свойство» в Ruby не занят, так эти новые конструкции и назовем.
Наши свойства будут поддерживать:
- контроль присваиваемых значений;
- значения по умолчанию;
- события, вызываемые при установке значения.
Определение свойств будет выглядеть примерно так:
property :alpha, filter: String, default: ''
property :beta, :gamma, filter: Integer, default: 0
property :delta, filter: Float,
default: 1.0 do |obj, prop, value|
p [obj, prop, value]
end
Последний вариант задает обработчик события. В случае, когда никаких именованных параметров, даже filter, не задано, property будет работать, в сущности, аналогично стандартному attr_accessor. Заметим, что атрибуты в Ruby определяются не ключевыми словами, а приватными методами класса Module. Логично будет пойти тем же путем.
Замечание: ключевые слова «module» и «class» в Ruby не формируют какое-то сакральное определение, принципиально отличающееся от остальной части программы, а просто переводят исполнение в контекст модуля (или класса соответственно), по необходимости создавая его. Это значит, что внутри определений мы можем писать, в общем-то, произвольный код, учитывая контекст, конечно [2]. При этом благодаря необязательности скобок при вызове такие методы, как attr, include, private, module_function, выглядят структурными элементами языка.
Статью целиком читайте в журнале «Системный администратор», №12 за 2014 г. на страницах 56-59.
PDF-версию данного номера можно приобрести в нашем магазине.
Facebook
Мой мир
Вконтакте
Одноклассники
Google+
|