Чтение онлайн

на главную

Жанры

Программирование на языке Ruby
Шрифт:

С каждым днем все больше приверженцев завоевывает методология экстремального программирования (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
.

Метод

eval
позволяет также вычислять локальные переменные в контексте, не принадлежащем их области видимости. Мы не рекомендуем легкомысленно относиться к этой возможности, но знать, что она существует, полезно.

Ruby ассоциирует локальные переменные с блоками, с определениями высокоуровневых конструкций (класса, модуля и метода) и с верхним уровнем программы (кодом, расположенным вне любых определений). С каждой из этих областей видимости ассоциируются привязки переменных и другие внутренние детали. Наверное, самым главным потребителем информации о привязках является программа

irb
— интерактивная оболочка для Ruby, которая пользуется привязками, чтобы отделить собственные переменные от тех, которые принадлежат вводимой программе.

Можно инкапсулировать текущую привязку в объект с помощью метода

Kernel#binding
. Тогда вы сможете передать привязку в виде второго параметра методу
eval
, установив контекст исполнения для интерпретируемого кода.

def some_method

 а = "local variable"

 return binding

end

the_binding = some_method

eval "a", the_binding # "local variable"

Интересно, что информация о наличии блока, ассоциированного с методом, сохраняется как часть привязки, поэтому возможны такие трюки:

def some_method

 return binding

end

the_binding = some_method { puts "hello" }

eval "yield", the_binding # hello

11.3.2. Метод const_get

Метод

const_get
получает значение константы с заданным именем из модуля или класса, которому она принадлежит.

Поделиться:
Популярные книги

Кондотьер

Листратов Валерий
7. Ушедший Род
Фантастика:
фэнтези
боевая фантастика
аниме
попаданцы
5.00
рейтинг книги
Кондотьер

Хозяин Теней 2

Петров Максим Николаевич
2. Безбожник
Фантастика:
попаданцы
аниме
фэнтези
5.00
рейтинг книги
Хозяин Теней 2

Кодекс Охотника. Книга IX

Винокуров Юрий
9. Кодекс Охотника
Фантастика:
боевая фантастика
городское фэнтези
попаданцы
5.00
рейтинг книги
Кодекс Охотника. Книга IX

Божья коровка 2

Дроздов Анатолий Федорович
2. Божья коровка
Фантастика:
альтернативная история
5.00
рейтинг книги
Божья коровка 2

Паладин из прошлого тысячелетия

Еслер Андрей
1. Соприкосновение миров
Фантастика:
боевая фантастика
попаданцы
6.25
рейтинг книги
Паладин из прошлого тысячелетия

Газлайтер. Том 19

Володин Григорий Григорьевич
19. История Телепата
Фантастика:
попаданцы
аниме
фэнтези
5.00
рейтинг книги
Газлайтер. Том 19

На границе империй. Том 10. Часть 10

INDIGO
Вселенная EVE Online
Фантастика:
космическая фантастика
попаданцы
5.00
рейтинг книги
На границе империй. Том 10. Часть 10

Герой

Бубела Олег Николаевич
4. Совсем не герой
Фантастика:
фэнтези
попаданцы
9.26
рейтинг книги
Герой

Путь Шедара

Кораблев Родион
4. Другая сторона
Фантастика:
боевая фантастика
6.83
рейтинг книги
Путь Шедара

Я все еще князь. Книга XXI

Дрейк Сириус
21. Дорогой барон!
Фантастика:
юмористическое фэнтези
попаданцы
аниме
5.00
рейтинг книги
Я все еще князь. Книга XXI

Черный дембель. Часть 2

Федин Андрей Анатольевич
2. Черный дембель
Фантастика:
попаданцы
альтернативная история
4.25
рейтинг книги
Черный дембель. Часть 2

Газлайтер. Том 29

Володин Григорий Григорьевич
29. История Телепата
Фантастика:
боевая фантастика
попаданцы
аниме
5.00
рейтинг книги
Газлайтер. Том 29

Адвокат Империи 11

Карелин Сергей Витальевич
Адвокат империи
Фантастика:
городское фэнтези
альтернативная история
рпг
дорама
попаданцы
5.00
рейтинг книги
Адвокат Империи 11

Александр Агренев. Трилогия

Кулаков Алексей Иванович
Александр Агренев
Фантастика:
альтернативная история
9.17
рейтинг книги
Александр Агренев. Трилогия