С каждым днем все больше приверженцев завоевывает методология экстремального программирования (Extreme Programming — XP), поощряющая, среди прочего, раннее тестирование и постоянную переработку (рефакторинг).
XP — технология, не зависящая от языка, хотя к некоторым языкам она, возможно, более приспособлена. Разумеется, на наш взгляд, в Ruby рефакторинг реализуется проще, чем во многих языках, но это субъективное мнение. Однако, наличие библиотеки Test::Unit
(и других) позволяет «поженить» Ruby и XP. Эта библиотека облегчает автономное тестирование компонентов, она функциональна богата, проста в использовании и доказала свою полезность в ходе разработки эксплуатируемых в настоящее время программ на Ruby. Мы горячо поддерживаем рекомендуемое XP раннее и частое тестирование, а тем, кто желает воплотить этот совет в Ruby, предлагаем ознакомиться с Test::Unit
. ( ZenTest
— еще один отличный пакет, включающий некоторые возможности, которые в Test::Unit
отсутствуют.)
Когда вы будете читать этот раздел, многие обсуждаемые в нем технологии усовершенствуются. Как обычно, самую актуальную информацию можно найти на следующих ресурсах:
Конференция comp.lang.ruby
Архив приложений Ruby
rubyforge.org
ruby-doc.org
Есть и другие полезные ресурсы, особенно для тех, кто говорит по-японски. Трудно перечислять онлайновые ресурсы в печатном издании, поскольку они постоянно изменяются. Поисковая машина — ваш лучший друг.
11.3. Динамические механизмы
Скайнет осознал себя в 2:14 утра по восточному времени 29 августа 1997 года.
Терминатор 2, Судный День
Многие читатели имеют опыт работы со статическими языками, например С. Им я адресую риторический вопрос: «Можете ли вы представите себе написанную на С функцию, которая принимает строку, рассматривает ее как имя переменной и возвращает значение этой переменной?»
Нет? А как насчет того, чтобы удалить или заменить определение функции? А перехватить обращения к несуществующим функциям? Или узнать имя вызывающей функции? Или автоматически получить список определенных пользователем элементов программы (например, перечень всех написанных вами функций)?
В Ruby все это возможно. Такая гибкость во время выполнения, способность опрашивать и изменять программные элементы во время выполнения намного упрощают решение задач. Утилиту трассировки выполнения, отладчик, профилировщик — все это легко написать на Ruby и для Ruby. Хорошо известные программы irb
и xmp
, используя динамические возможности Ruby, творят это волшебство.
К подобным возможностям нужно привыкнуть, их легко употребить во вред. Все эти идеи появились отнюдь не вчера (они стары по крайней мере так же, как язык LISP) и считаются «проверенными и доказанными» в сообществах пользователей Scheme и Smalltalk. Даже в языке Java, который так многим обязан С и C++, есть некоторые динамические средства, поэтому мы ожидаем, что со временем их популярность будет только расти.
11.3.1. Динамическая интерпретация кода
Глобальная функция eval
компилирует и исполняет строку, содержащую код на Ruby. Это очень мощный (и вместе с тем опасный) механизм, поскольку позволяет строить подлежащий исполнению код во время работы программы. Например, в следующем фрагменте считываются строки вида «имя = выражение», затем каждое выражение вычисляется, а результат сохраняется в хэше, индексированном именем переменной.
parameters = {}
ARGF.each do |line|
name, expr = line.split(/\s*=\s*/, 2)
parameters[name] = eval expr
end
Пусть на вход подаются следующие строки:
а = 1
b = 2 + 3
с = 'date'
Тогда в результате мы получим такой хэш: {"а"=>1, "b"=>5,"с"=>"Mon Apr 30 21:17:47 CDT 2001\n"}
. На этом примере демонстрируется также опасность вычисления с помощью eval
строк, содержимое которых вы не контролируете; злонамеренный пользователь может подсунуть строку d= 'rm *'
и стереть всю вашу дневную работу.
В Ruby есть еще три метода, которые интерпретируют код «на лету»: class_eval
, module_eval
и instance_eval
. Первые два — синонимы, и все они выполняют одно и то же: интерпретируют строку или блок, но при этом изменяют значение псевдопеременной self
так, что она указывает на объект, от имени которого эти методы вызваны. Наверное, чаще всего метод class_eval
применяется для добавления методов в класс, на который у вас имеется только ссылка. Мы продемонстрируем это в коде метода hook_method
в примере утилиты Trace
в разделе 11.3.13. Другие примеры вы найдете в динамических библиотечных модулях, например delegate.rb
.
Читать дальше
Конец ознакомительного отрывка
Купить книгу