Вы находитесь на странице: 1из 332

Майкл Фитцджеральд

Санкт-Петербург
«БХВ-Петербург»
2008
УДК 681.3.06
ББК 32.973.26-018.2
Ф66

Фитцджеральд М.
Ф66 Изучаем Ruby: Пер. с англ. — СПб.: БХВ-Петербург, 2008. —
336 с.: ил.
ISBN 978-5-9775-0225-2
Книга представляет собой руководство по созданию веб-приложений на
языке Ruby. Изучение построено на практических примерах, листинги которых
есть почти на каждой странице.
Даны основы Ruby, рассмотрены условные операторы, строки и регулярные
выражения, операторы, функции, массивы, хэши, работа с файлами, классы.
Описаны обработка XML, рефлексия, метапрограммирование, обработка исключе-
ний, инструментарий разработчика Tk и другие средства, включая RubyGems, RDoc
и Embedded Ruby. Каждая глава завершается списком вопросов по теме. В конце
книги для удобства собраны справочные материалы по языку Ruby и даны от-
веты на контрольные вопросы к главам.
Для веб-разработчиков

УДК 681.3.06
ББК 32.973.26-018.2

Группа подготовки издания:


Главный редактор Екатерина Кондукова
Зам. главного редактора Евгений Рыбаков
Зав. редакцией Григорий Добин
Перевод с английского Наталии Гавриловой
Редактор Анна Кузьмина
Компьютерная верстка Натальи Караваевой
Корректор Виктория Пиотровская
Оформление обложки Елены Беляевой
Зав. производством Николай Тверских

Authorized translation from the English language edition, entitled Learning Ruby, published by O'Reilly Media, Inc., Copyright
© 2007 Michael Fitzgerald. All rights reserved. This translation is published and sold by permission of O'Reilly Media, Inc.,
the owner of all rights to publish and sell the same.
Авторизованный перевод английской редакции, выпущенной O'Reilly Media, Inc., © 2007 Michael Fitzgerald. Все права
защищены. Перевод опубликован и продается с разрешения O'Reilly Media, Inc., собственника всех прав на публикацию
и продажу издания.

Лицензия ИД № 02429 от 24.07.00. Подписано в печать 27.03.08.


Формат 70 1001/16. Печать офсетная. Усл. печ. л. 27,09.
Тираж 2000 экз. Заказ №
"БХВ-Петербург", 194354, Санкт-Петербург, ул. Есенина, 5Б.
Отпечатано с готовых диапозитивов
в ГУП "Типография "Наука"
199034, Санкт-Петербург, 9 линия, 12

ISBN 978-0-596-52986-4 (англ.) © 2007 Michael Fitzgerald


ISBN 978-5-9775-0225-2 (рус.) © Оформление, издательство "БХВ-Петербург", 2008
Оглавление

Об авторе ................................................................................................................ 2

Предисловие ........................................................................................................... 3
Кому следует читать эту книгу? ............................................................................ 3
Как работать с этой книгой .................................................................................... 3
О примерах .............................................................................................................. 4
Как организована эта книга ................................................................................... 5
Соглашения, принятые в этой книге ..................................................................... 6
Комментарии и вопросы ........................................................................................ 7
Safari® Enabled ......................................................................................................... 7
Благодарности ......................................................................................................... 8
Глава 1. Основные положения ........................................................................... 9
Hello, Matz ............................................................................................................. 10
Очень короткая программа на языке Ruby ..................................................... 11
Shebang! .............................................................................................................. 12
Запуск системной команды .............................................................................. 13
Добавление в конец строки .............................................................................. 13
Дублирование .................................................................................................... 14
Вставка команды из командной строки .......................................................... 14
Использование переменной.............................................................................. 14
Подстановка выражения ................................................................................... 15
Форматирование строки ................................................................................... 15
Метод eval и параметр -e .................................................................................. 16
Ввод данных с клавиатуры ............................................................................... 17
Методы ............................................................................................................... 17
Блок..................................................................................................................... 17
Метод each ......................................................................................................... 18
Процедурный объект ....................................................................................... 18
VI Оглавление

XML .................................................................................................................... 18
Класс ................................................................................................................... 19
Инструментарий Tk ........................................................................................... 20
Редактирование и выполнение программ в TextMate .................................... 20
Interactive Ruby ...................................................................................................... 22
Информационные ресурсы................................................................................... 23
Установка Ruby ..................................................................................................... 25
Установка Ruby в Mac OS X Tiger ................................................................... 26
Установка Ruby в Windows с помощью One-Click Installer .......................... 29
Установка двоичных файлов Ruby в Windows ............................................... 30
Установка Ruby в Linux .................................................................................... 32
В разрешении отказано ........................................................................................ 32
Сопоставление типа файлов в Windows ............................................................. 32
Вопросы для самопроверки ................................................................................. 34
Глава 2. Обзорная экскурсия по Ruby ............................................................ 35
Ruby — объектно-ориентированный язык ......................................................... 35
Класс Object и модуль Kernel ........................................................................... 37
Зарезервированные слова языка Ruby ................................................................ 38
Комментарии ......................................................................................................... 40
Переменные ........................................................................................................... 41
Локальные переменные .................................................................................... 43
Переменные экземпляра ................................................................................... 43
Переменные класса ........................................................................................... 43
Глобальные переменные................................................................................... 43
Константы .......................................................................................................... 44
Параллельное присваивание ............................................................................ 44
Строки .................................................................................................................... 45
Регулярные выражения ..................................................................................... 46
Числа и операторы ................................................................................................ 47
Условные операторы ............................................................................................ 48
Массивы и хэши .................................................................................................... 49
Методы................................................................................................................... 50
Возвращаемые значения ................................................................................... 51
Соглашение о присвоении имен методам ....................................................... 52
Параметры по умолчанию ................................................................................ 54
Переменное число параметров......................................................................... 54
Псевдонимы методов ........................................................................................ 55
Блоки ...................................................................................................................... 56
Оператор yield .................................................................................................... 57
Процедурные объекты (procs) .......................................................................... 59
Оглавление VII

Символы................................................................................................................. 61
Обработка исключений ........................................................................................ 62
Документация по языку Ruby .............................................................................. 62
Вопросы для самопроверки ................................................................................. 63
Глава 3. Любовь к условным операторам ..................................................... 65
Оператор if ............................................................................................................. 65
Использование else и elsif ................................................................................. 68
Трехместный оператор ..................................................................................... 69
Оператор case ........................................................................................................ 70
Цикл while .............................................................................................................. 71
Да что ты говоришь! ......................................................................................... 73
Операторы unless и until ....................................................................................... 74
Метод loop ............................................................................................................. 75
Цикл for .................................................................................................................. 76
Метод times ........................................................................................................ 77
Метод upto.......................................................................................................... 78
Метод downto ..................................................................................................... 79
Выполнение кода до или после программы ....................................................... 80
Вопросы для самопроверки ................................................................................. 80
Глава 4. Строки ................................................................................................... 81
Создаем строки ..................................................................................................... 81
Строки с общими ограничителями .................................................................. 83
Документ "здесь и сейчас" ............................................................................... 83
Конкатенация строк .............................................................................................. 84
Получаем доступ к строкам ................................................................................. 85
Сравниваем строки ............................................................................................... 87
Обрабатываем строки ........................................................................................... 88
Вставляем строку в строку ............................................................................... 89
Заменяем всю строку или ее часть .................................................................. 89
Методы chomp и chop ....................................................................................... 90
Метод delete ....................................................................................................... 91
Заменяем подстроку .......................................................................................... 92
Переверни их ..................................................................................................... 92
От строки к массиву .......................................................................................... 93
Преобразуем регистр клавиатуры ....................................................................... 93
Выполняем итерации в строке ......................................................................... 94
downcase, upcase и swapcase ............................................................................ 95
Управляем пробельными символами .................................................................. 95
Выполняем инкремент строки ............................................................................. 97
VIII Оглавление

Преобразуем строки.............................................................................................. 98
Регулярные выражения ........................................................................................ 99
Версия 1.9 и выше ............................................................................................... 104
Вопросы для самопроверки ............................................................................... 105
Глава 5. Математика........................................................................................ 107
Иерархия классов и включенных в них модулей ............................................. 108
Преобразуем числа ............................................................................................. 109
Элементарные математические операции ........................................................ 110
Деление и округление ..................................................................................... 111
Равно, меньше чем или больше чем .............................................................. 112
Операторы сокращенного присваивания ...................................................... 112
Операторы ........................................................................................................ 114
Диапазоны ........................................................................................................... 115
Запросы, касающиеся чисел .............................................................................. 116
Итеративное вычисление через блоки .......................................................... 117
Еще больше математических методов .............................................................. 118
Математические функции .................................................................................. 119
Рациональные числа ........................................................................................... 120
Простые числа ..................................................................................................... 122
Шутки ради ...................................................................................................... 123
Вопросы для самопроверки ............................................................................... 123
Глава 6. Массивы ............................................................................................. 125
Создаем массивы................................................................................................. 126
Драим палубу ................................................................................................... 127
Создаем массивы с помощью блока .............................................................. 127
Существует более простой способ ................................................................ 127
Еще более простой способ ............................................................................. 128
Получаем доступ к элементам ........................................................................... 129
Конкатенация ...................................................................................................... 131
Операции над множествами .............................................................................. 132
Уникальные элементы ........................................................................................ 133
Очищаем стек ...................................................................................................... 133
Сравниваем массивы .......................................................................................... 134
Изменяем элементы ............................................................................................ 135
Как строка ........................................................................................................ 135
Применяем shift и unshift ................................................................................ 136
Удаляем элементы .............................................................................................. 136
Массивы и блоки................................................................................................. 137
Прямая и обратная сортировки.......................................................................... 137
Оглавление IX

Многомерные массивы....................................................................................... 138


Версия 1.9 и выше ............................................................................................... 139
Другие методы работы с массивами ................................................................. 139
Вопросы для самопроверки ............................................................................... 140
Глава 7. Хэши .................................................................................................... 141
Создаем хэш ........................................................................................................ 141
Получаем доступ к хэшам .................................................................................. 143
Выполняем итерации .......................................................................................... 144
Изменяем хэши.................................................................................................... 145
Объединяем хэши ............................................................................................ 145
Сортируем хэш ................................................................................................ 146
Удаляем и очищаем хэш ................................................................................. 146
Замещаем хэш .................................................................................................. 148
Преобразуем хэш в другие классы .................................................................... 148
Версия 1.9 и выше ............................................................................................... 149
Другие методы класса Hash ............................................................................... 149
Вопросы для самопроверки ............................................................................... 150
Глава 8. Работа с файлами .............................................................................. 151
Каталоги ............................................................................................................... 151
Заглянем в каталог .......................................................................................... 152
Поток каталога................................................................................................. 153
Создаем новый файл ........................................................................................... 153
Открываем существующий файл ...................................................................... 154
ARGV и ARGF .................................................................................................. 155
Открываем URI ................................................................................................ 156
Удаляем и переименовываем файлы................................................................. 157
Файловые запросы .............................................................................................. 158
Изменяем режимный код файла и владельца................................................... 159
Класс IO ............................................................................................................... 160
Вопросы для самопроверки ............................................................................... 163
Глава 9. Классы................................................................................................. 165
Определяем класс ............................................................................................... 166
Переменные экземпляра ..................................................................................... 167
Аксессоры ............................................................................................................ 169
Переменные класса ............................................................................................. 172
Методы класса..................................................................................................... 173
Одноэлементные классы................................................................................. 173
Наследование ...................................................................................................... 175
X Оглавление

Модули ................................................................................................................. 177


Методы public, private и protected ..................................................................... 179
Вопросы для самопроверки ............................................................................... 181
Глава 10. С Ruby не соскучишься ................................................................. 183
Форматирование вывода с помощью sprintf .................................................... 183
Обработка XML .................................................................................................. 188
REXML ............................................................................................................. 188
Builder ............................................................................................................... 191
Date и Time........................................................................................................... 193
Класс Time ........................................................................................................ 193
Класс Date ........................................................................................................ 196
Рефлексия ............................................................................................................ 199
Рефлексия для переменных и констант......................................................... 201
Рефлексия для методов ................................................................................... 202
Применение Tk .................................................................................................... 203
Метапрограммирование ..................................................................................... 207
RubyGems............................................................................................................. 208
Обработка исключений ...................................................................................... 214
Создание документации с помощью RDoc ...................................................... 216
Основы RDoc ................................................................................................... 217
Обработка файлов с помощью RDoc............................................................. 222
Embedded Ruby .................................................................................................... 226
Вопросы для самопроверки ............................................................................... 230
Глава 11. Краткий курс по Ruby on Rails..................................................... 231
Откуда взялась среда Rails? ............................................................................... 231
Почему Rails? ...................................................................................................... 232
Полный пакет среды разработки ................................................................... 233
Не повторяйтесь .............................................................................................. 233
Соглашение по конфигурации ....................................................................... 234
Хочу мою MVC ............................................................................................... 234
Скрипты............................................................................................................ 235
Подтверждение правильности ....................................................................... 235
Ajax ................................................................................................................... 236
Миграции ......................................................................................................... 236
Консоль ............................................................................................................ 236
Среда и тестирование...................................................................................... 236
Capistrano ......................................................................................................... 237
Rake ................................................................................................................... 237
Что другие делают с Rails? ................................................................................ 238
Услуги по размещению Rails ............................................................................. 241
Оглавление XI

Установка Rails ................................................................................................... 241


Применение RubyGems для установки Rails ................................................ 241
Дополнительная информация по установке ................................................. 244
Изучаем Rails ....................................................................................................... 244
Обучающие руководства и книги по Ruby ................................................... 245
Краткое руководство .......................................................................................... 246
Вопросы для самопроверки ............................................................................... 254
ПРИЛОЖЕНИЯ ................................................................................................ 255
Приложение 1. Справочник по Ruby ............................................................ 257
Интерпретатор Ruby ........................................................................................... 257
Зарезервированные слова языка Ruby .............................................................. 258
Операторы ........................................................................................................ 260
Escape-символы ................................................................................................... 261
Предопределенные переменные ........................................................................ 262
Глобальные константы ....................................................................................... 266
Регулярные выражения ...................................................................................... 267
Директивы распаковки в String ......................................................................... 269
Директивы упаковки в Array ............................................................................. 272
Флажки и типы полей для sprintf ...................................................................... 273
Файловые тесты .................................................................................................. 275
Директивы форматирования времени ............................................................... 277
Опции RDoc ......................................................................................................... 278
Rake ...................................................................................................................... 280
Приложение 2. Ответы на вопросы для самопроверки ............................ 283
Глава 1 .................................................................................................................. 283
Глава 2 .................................................................................................................. 284
Глава 3 .................................................................................................................. 284
Глава 4 .................................................................................................................. 285
Глава 5 .................................................................................................................. 286
Глава 6 .................................................................................................................. 286
Глава 7 .................................................................................................................. 287
Глава 8 .................................................................................................................. 288
Глава 9 .................................................................................................................. 288
Глава 10 ................................................................................................................ 289
Глава 11 ................................................................................................................ 290
Глоссарий ........................................................................................................... 291
Предметный указатель .................................................................................... 307
XII Оглавление
Роберт Уэйн Дарра (Robert Wayne Darrah)

1950—2006

"Пока мы не встретимся снова"


2 Об авторе

Об авторе

Майкл Фитцджеральд (Michael Fitzgerald) имеет стаж работы писателем


и программистом более двадцати лет и описывает Ruby как свой "пока что
самый любимый язык". Майкл также является автором книг "Learning XSLT,
XML Hacks" и "Ruby Pocket Reference" и соавтором "XML Pocket Reference",
все они опубликованы издательством O'Reilly.
Предисловие

Язык Ruby обратил на себя более пристальное внимание с появлением Ruby on


Rails, среды разработки интернет-приложений. Но — с некоторым опозданием.
Ruby возник одновременно с языком Java, но за пределами Японии пользовался
весьма ограниченной известностью примерно до 2000 года. Последние не-
сколько лет популярность Ruby неуклонно растет, и не без основания.

Кому следует читать эту книгу?


В основном, я полагаю, эту книгу будут покупать две категории читателей:
опытные программисты, которые хотят изучить язык Ruby, и новички, кото-
рые хотят научиться программировать. Я проделал увлекательную работу,
стараясь угодить обеим группам и не вызвать раздражения ни у одной из них.
Это настоящая эквилибристика, и вот как мне удалось справиться с этим:
я буду обращаться к вам так, как будто вы уже являетесь квалифицирован-
ным программистом, но я также постараюсь оказывать максимальную по-
мощь новичкам, в основном в виде комментариев и вставок. Я дам вам знать,
когда можно пропустить раздел, если вы уже "хорошо бьете по мячу".
Если вы достаточно опытный программист, то, возможно, предпочтете сна-
чала изучить примеры кодов, от начала и до конца книги, бегло просматри-
вая, в случае необходимости, пояснения к этим примерам. Можно довольно
быстро понять, что происходит, просто взглянув на текст программы. Код
подается в более или менее логичной манере (по крайней мере, мне так ка-
жется), так что вы сможете сравнительно скоро освоить Ruby. Если же вы
новичок в программировании, то я попытаюсь облегчить вам задачу, давая
пояснения по мере продвижения вперед.

Как работать с этой книгой


Должны ли вы знать все об автомобиле, прежде чем сесть за руль? Должны
вы были знать что-то о впрыске топлива, сгорании или зубчатом ремне при-
вода, чтобы водить машину? Конечно, нет.
4 Предисловие

То же самое происходит и с программированием на новом языке. Я покажу


вам множество программ на языке Ruby, многие из них коротенькие, а затем
расскажу, как и почему они работают — этого достаточно, чтобы выкатить
вас на дорогу. Я выбрал этот подход, потому что убежден, что большую
часть знаний мы получаем, наблюдая, имитируя и играя. И я собираюсь про-
делать много всего такого в своей книге.
Вы должны знать заранее, что эта книга относится к типу "просто садись
и поезжай". Другими словами, вы можете вести автомобиль, даже не зная,
шесть у него цилиндров или восемь.
Дэвид Хейнемейер Хенссон (David Heinemeier Hansson), разработчик Ruby on
Rails, высказал мысль, которая мне понравилась: "Люди обучаются, немного
изменяя вещи, перезагружаясь и раздумывая над произошедшими измене-
ниями". Он прав. Это и мой опыт: за несколько лет я многое узнал, изучая
код, а не читая о нем.
Я также буду продвигаться по материалу как можно быстрее, чтобы не увяз-
нуть в зыбучих песках детализации. Подробности будут поступать своевре-
менно, по мере необходимости; главное сейчас — движение вперед и импульс.
Если вы, следя за тем, что я делаю, будете сразу выполнять программы и из-
менять их на свой вкус, то быстро выучите Ruby. Чем больше вы выполните
этих программ, тем больших навыков достигнете. И в скором времени вы
начнете думать и даже мечтать на языке Ruby. Затем вы просто пойдете сво-
им путем.
Последняя выпущенная версия к моменту написания этой книги — 1.8.6.
Именно с ней я буду работать. Возможно, вам удастся обойтись более старой
версией, но если у вас не установлена 1.8.6 или более поздняя версия, я не
могу гарантировать, что все программы из этой книги будут работать так, как
обещано, хотя велика вероятность, что будут.

О примерах
Я считаю, что обучаться лучше всего, наблюдая за тем, что делают другие,
а затем имитировать то, что видел. Так обучаются дети. Поэтому вы найдете
примеры текстов программ — для наблюдения и имитации — почти на каж-
дой странице этой книги.
Многие примеры можно скачать с сайта http://www.oreilly.com/catalog/
9780596529864. Идея заключается в том, чтобы у вас под рукой было доста-
точно примеров для выполнения большей части основных заданий по про-
граммированию.
Предисловие 5

Как организована эта книга


Книга содержит 11 глав.
 Глава 1. Основные положения.
Дает основные представления о том, где взять Ruby, как его установить,
и большое количество программ, чтобы позволить вам немедленно начать
использовать Ruby.
 Глава 2. Обзорная экскурсия по языку Ruby.
Обходит территорию Ruby быстрым шагом, с кратким освещением его
наиболее важных возможностей.
 Глава 3. Любовь к условным операторам.
Объясняет и демонстрирует, как использовать в Ruby условные операторы
(такие как if и while), включая организацию циклов.
 Глава 4. Строки.
Знакомит с обработкой строк (содержит раздел о регулярных выражениях).
 Глава 5. Математика.
Показывает, как использовать операторы, основные математические
функции, функции из модуля Math, рациональные числа и т. д.
 Глава 6. Массивы.
Проведет вас через массивы в языке Ruby.
 Глава 7. Хэши.
Демонстрирует хэши (hashes) во всех подробностях.
 Глава 8. Работа с файлами.
Показывает, как в Ruby обрабатываются файлы, в том числе запись и чте-
ние файла и т. п.
 Глава 9. Классы.
Рассматривает в деталях классы, включая небольшое введение в объектно-
ориентированное программирование, переменные экземпляра, методы эк-
земпляра класса, переменные класса, методы класса, модули и смешива-
ние (mixins).
 Глава 10. С Ruby не соскучишься.
Представляет разнообразие тем, включая RubyGem, рефлексию (reflection),
метапрограммирование (metaprogramming), обработку исключений и мно-
гое другое.
6 Предисловие

 Глава 11. Краткий курс по Ruby on Rails.


Знакомит с самым существенным в Rails и включает краткий учебный
курс. (Следует отдать должное Ruby on Rails за рост известности Ruby.)
 Приложение 1. Справочник по Ruby.
Преподносит весь справочный материал книги в одном месте.
 Приложение 2. Ответы на вопросы для самопроверки.
Предоставляет ответы на вопросы, приведенные в конце глав (более 100 во-
просов и ответов).
 Глоссарий.
Содержит список терминов, связанных с языком Ruby, и их определения.

Соглашения, принятые в этой книге


В этой книге приняты следующие соглашения по шрифтам:
 курсив предназначен для:
новых терминов в месте, где они определяются, или для выделения
информации;
ссылок на другие главы и разделы;
 полужирный шрифт служит для интернет-адресов, таких как имена до-
менов и URL;
 моноширинный шрифт применяется для:
командных строк и опций, которые должны быть набраны в файле или
в irb буквально;
имен и ключевых слов в программах на языке Ruby, включая имена ме-
тодов, переменных и классов;
 моноширинный курсивный шрифт употребляется для значений, определяе-
мых пользователем;
 моноширинный полужирный шрифт используется для привлечения внимания
к частям программы.

Эта пиктограмма обозначает совет, предложение или замечание.

Эта пиктограмма обозначает предостережение.


Предисловие 7

Комментарии и вопросы
Адресуйте, пожалуйста, комментарии и вопросы, касающиеся этой книги,
издателю:
O'Reilly Media, Inc.
1005 Gravenstein Highway North
Sebastopol, CA 95472
800-998-9938 (in the United States or Canada)
707-829-0515 (international or local)
707-829-0104 (Fax)
Для этой книги имеется страница, на которой перечислены опечатки, даны
примеры и другая дополнительная информация. К ней можно получить дос-
туп по адресу:
http://www.oreilly.com/catalog/9780596529864
Комментарии и технические вопросы по поводу этой книги отправляйте на:
bookquestions@oreilly. com
Дополнительную информацию о книгах, конференциях, Информационных
центрах и сети O'Reilly ищите на Web-сайте O'Reilly:
http://www.oreilly. com

Safari® Enabled
Когда вы видите пиктограмму Safari Enabled на обложке книги
о вашей любимой технологии, это означает, что книга доступна
в Интернете благодаря сервису издательства O'Reilly Network
Safari Bookshelf.
Safari предлагает лучшее решение, чем просто электронные книги. Это вир-
туальная библиотека, где вы без труда отыщите лучшую техническую лите-
ратуру, скопируете примеры кода, скачаете главы и быстро найдете ответы,
если вам нужна самая точная и свежая информация. Посетите этот сервис
бесплатно на Web-сайте http://safari.oreilly.com.
8 Предисловие

Благодарности
Я еще раз хочу поблагодарить моего редактора Саймона Сент-Лорена (Simon
St. Laurent) за предоставленный мне шанс написать эту книгу. Ободряющие
слова Саймона помогли мне продержаться на плаву в четырех книжных про-
ектах!
Я также признателен за комментарии техническим рецензентам Райану Уал-
дрону (Ryan Waldron) и Джоуи Франклину (Joey Franklin). Они вытаскивали
меня на палубу, когда я тонул в бурном море. Спасибо, ребята.
В заключение, что еще более важно, я хочу поблагодарить мою жену Кристи
и дочерей Мелиссу, Эми и Обри за поддержку и веру в меня. Вы придаете
смысл всему.
Глава 1

Основные положения

Возможно, как и вы, за несколько лет я научился программировать на раз-


личных языках — среди них BASIC, FORTRAN, C, C++, C#, Java и JavaScript —
но до сих пор Ruby — мой самый любимый язык программирования. Его ин-
тереснее всего было изучать и применять. Почему? Из-за его синтаксиса. Ес-
ли у вас есть представление о других языках, то вы легко разберетесь с Ruby.
К тому же он очень гибок: Ruby позволит вам делать одни и те же вещи раз-
личными способами, так что вы сами сможете решить, какой из них ваш.
Ruby, скорее, интерпретируемый язык, чем компилируемый. Можно на-
звать его скриптовым языком (языком написания сценариев), объектно-
ориентированным языком, языком обновления изображений. Это не совер-
шенный язык. Он и не должен им быть. Все равно, он мой самый любимый.
В нем определенно есть je ne sais quoi (что-то). Если бы это было не так, то
зачем бы я тратил сотни часов на написание книги о нем? Уж определенно не
ради денег и славы.
По моему мнению, одним из лучших аспектов языка Ruby является его "при-
годность для компоновки" (composability). Пригодность для компоновки — это
степень, до которой вы можете выражать логику путем комбинирования и ре-
комбинирования частей языка (см. книгу James Clark "The Design of RELAX NG"
на http://www.thaiopensource.com/relaxng/design.html#section:5). Ruby этим
обладает, как настоящая звезда.
К тому же, Ruby не находится под контролем комиссий и корпораций. Это
открытое программное средство. Ruby написал Matz, с небольшой помощью
своих друзей. (Кстати, Ruby написан на С и может принимать С-расширения.)
"Matz" — это краткая форма имени Юкихиро Мацумото (Yukihiro Matsumoto,
Япония). Он начал работать над языком Ruby в 1993 году и впервые выпустил
10 Глава 1

его в свет в 1995, в том же году, когда вышел Java. Какое-то время Ruby по-
тратил на то, чтобы добраться до Запада, но когда он это сделал, приблизи-
тельно в 2000 году, то немного устал. Но нашел опору в лице таких людей,
как Дейв Томас (Dave Thomas), Энди Хант (Andy Hunt), Хэл Фултон (Hal
Fulton) и др. Сейчас у Ruby есть свой фан-клуб.
Еще у Ruby есть "захватчик рынка" (killer app). Он называется Ruby on Rails
(http://www.rubyonrails.org). Слышали о нем? Это каркас интернет-
приложений для быстрого и эффективного создания Web-сайтов с базами
данных. Многие действительно любят Rails. Не все, конечно, но многие.
И эти люди обнаружили, что одной из основных причин их любви к Rails яв-
ляется то, что он написан на Ruby.

Hello, Matz
Я полагаю, многие читатели сейчас ожидают от меня первый пример под на-
званием "Hello, world" ("Привет, мир"). Но, несмотря на этический и мораль-
ный долг, я решил заменить его примером "Hello, Matz". Как вы думаете,
учитывая все, что сделал Matz для программирования, не заслужил ли он
немного признания?
Прежде чем двигаться дальше, выясните, не установлен ли уже Ruby на ва-
шем компьютере. Если вы работаете в Mac OS X или каком-либо дистрибу-
тиве Linux, то он уже может быть там, хотя и устаревшей версии; Tiger
(Mac OS X 10.4 или более поздняя версия) поставляется, например, с вер-
сией Ruby 1.8.2.
Чтобы узнать, не прячется ли Ruby в системном блоке, в системе UNIX/Linux
после приглашения в командной строке (не работает в стандартной сис-
теме Windows) наберите:
$ which ruby

Посмотрите, не появился ли ответ, подобный такому (если да, то это хорошая


новость):
/usr/local/bin/ruby

Или просто введите команду для определения версии Ruby (это работает
в UNIX/Linux):
$ ruby –v

или:
$ ruby –version
Основные положения 11

И в Windows:
ruby –v

Если Ruby установлен, то вы должны получить ответ, который выглядит


примерно так:
ruby 1.8.6 (2007-03-13 patchlevel 0) [powerpc-darwin8.9.0]

или в Windows:
ruby 1.8.6 (2007-03-13 patchlevel 0) [i386-mswin32]

ПРЕДЛОЖЕНИЕ
Если Ruby не установлен на компьютере, а вы не совсем уверены, что
справитесь с установкой самостоятельно, прочитайте разд. "Установ-
ка Ruby" далее в этой главе. Следуя приведенным там инструкциям,
установите Ruby. А затем возвращайтесь сюда!

Очень короткая программа на языке Ruby


Теперь, когда Ruby готов к работе, напечатайте в текстовом редакторе,
например, TextPad, следующую строку:
puts "Hello, Matz!"

Такая строка программы называется оператором. Это команда, которую


должна выполнить программа. Команда выведет на экран строку Hello,
Matz!, за которой последует символ перевода строки.
В конце оператора, если хотите, можете поставить точку с запятой (;), как
в языках С или Java, но вы не обязаны этого делать: перевода строки будет
достаточно. (Большинство программирующих на Ruby используют точку
с запятой, только когда пишут несколько операторов на одной строке.)
Сохраните эту программку как текст в файле с именем matz.rb. (Расшире-
ние rb используется по умолчанию для программ, написанных на языке
Ruby.)

СОВЕТ
Неплохая идея сохранить файл в каталоге или папке, в которой вы
собираетесь работать с языком Ruby. Доступ к файлам получать
проще, когда они находятся в одном месте.

Программа выполняется при помощи интерпретатора с языка Ruby. Для вы-


полнения программы наберите после приглашения в командной строке:
$ ruby matz.rb
12 Глава 1

По умолчанию результат выполнения программы появится на экране:


Hello, Matz!

Символ #, помещенный в начало строки, сообщает интерпретатору о том, что


эту строку нужно пропустить:
# a nice greeting for Matz
puts "Hello, Matz!"

Добавьте символ # и за ним любой текст в свою программу в файле matz.rb.


Это называется комментарием. То, что следует за символом #, скрыто от
интерпретатора. Дополнительную информацию о комментариях см. в главе 2.

Shebang!
При выполнении программы на языке Ruby в операционной системе
Windows, обычно нужно перед именем файла с программой писать ко-
манду ruby (если только расширение rb не связано с типом файла; как сде-
лать это, см. в разд. "Сопоставление типа файлов в Windows" далее в этой
главе). В системах UNIX/Linux этого можно избежать, если добавить не-
что под названием "строка shebang (#!)" в начало файла с программой.
Добавьте строку #! в начало файла matz.rb:
#!/usr/local/bin/ruby
# a nice greeting for Matz
puts "Hello, Matz!"

Строка укажет системе, где искать интерпретатор Ruby, а именно в каталоге


/usr/local/bin, стандартном месте установки исполняемых файлов Ruby
(см. разд. "Установка Ruby в Mac OS X Tiger" далее в этой главе). Наиболее
общей альтернативой является #!/usr/bin/env ruby. Выбирайте то, что ра-
ботает у вас. У меня Ruby находится во втором каталоге.

ЗАМЕЧАНИЕ
Как уже говорилось ранее, Tiger поставляется со старой версией Ruby —
версией 1.8.2, которая хранится в /usr/bin. Мы не будем ее использо-
вать.

Перейдите в командную строку на своем Mac или в системе UNIX/Linux


и введите только имя файла:
$ matz.rb

Вы получите тот же самый результат, что и раньше:


Hello, Matz!
Основные положения 13

ПРЕДЛОЖЕНИЕ
Если во время выполнения программы matz.rb вы получили сообще-
ние об отказе в разрешении и не знаете, что с этим делать, я хотел бы
предложить вам помощь. См. разд. "В разрешении отказано" далее
в этой главе.

Теперь я покажу вам другие способы вывода текста "Hello, Matz!", которые
позволят вам оценить мощь Ruby. Здесь я не буду вдаваться в детали того,
что происходит. Просто следуйте инструкциям, наберите и протестируйте
столько программ, сколько захотите. Для тестирования программы выполни-
те следующие шаги:
1. Удалите предыдущую программу из matz.rb.
2. Наберите новую программу.
3. Выполните программу, вызвав интерпретатор Ruby в командной строке,
и посмотрите на результат.
Вы будете удалять старую программу из файла matz.rb и вводить на ее место
новую до тех пор, пока в тексте книги не появится файл с другим именем.
Эти другие файлы с заданными именами можно воссоздать самому или за-
грузить все файлы, упомянутые в книге, со страницы http://www.oreilly.com/
catalog/9780596529864. После загрузки перепишите файлы из zip-архива
в каталог или папку по своему выбору, туда, где вы работаете с Ruby. Пере-
ходите в каталог при помощи команды cd в командной строке.

Запуск системной команды


С помощью system можно выполнить команду операционной системы:
system "echo 'Hello, Matz!'"

Затем попробуйте убрать одинарные кавычки (').


Каждую часть команды можно записать как отдельный параметр для system:
system "echo", "Hello,", "Matz!"

Команда exe аналогична команде system, но она замещает текущий процесс,


и после ее выполнения работа завершается — а вы не всегда этого хотите.

Добавление в конец строки


Добавьте в конец одной строки другую с помощью метода +:
puts "Hello, " + "Matz!"

Добавить строку можно также методом <<:


puts "Hello, " << "Matz!"
14 Глава 1

Дублирование
Что делать, если вы хотите напечатать строку три раза? Как насчет *?
puts "Hello, Matz!" * 3

Получится:
Hello, Matz! Hello, Matz! Hello, Matz!

Или воспользуйтесь методом times:


5.times { print "Hello, Matz! " }

Он продемонстрирует ваш энтузиазм:


Hello, Matz! Hello, Matz! Hello, Matz! Hello, Matz! Hello, Matz!

Можно просто напечатать одно слово три раза, а затем добавить к нему еще
текст с помощью +:
puts "Hello, " * 3 + "Matz!"

И вы получите:
Hello, Hello, Hello, Matz!

Вставка команды из командной строки


Давайте вставим какую-нибудь команду из командной строки:
puts "Hey Matz, I'm running " + `ruby –version`

Если выполнить это, то выходные данные команды, заключенной в грависы


или обратные кавычки (`ruby –version`), будут помещены в результат:
Hey Matz, I'm running ruby 1.8.6 (2006-08-25) [powerpc-darwin8.8.0]

Использование переменной
Можно дать значению имя, присвоив это значение переменной:
hi = "Hello, Matz!"
puts hi # => Hello, Matz!

Здесь hi — пример локальной переменной. Именно локальной, потому что ее


имя начинается со строчной буквы. Локальные переменные и переменные
других типов подробно описаны в разд. "Переменные" главы 2.

ЗАМЕЧАНИЕ
В примерах за символом комментария (#) всегда будет следовать
символ =>. То, что следует за ним, — ожидаемый результат работы
строки программы, программного блока или всей программы в целом.
Основные положения 15

Сложите две или более переменных при помощи метода +:


hi = "Hello, "
person = "Matz!"
puts hi + person # => Hello, Matz!

Подстановка выражения
Вставить значение переменной в строку можно также при помощи подста-
новки выражения — весьма удобной возможности языка Ruby:
person = "Matz!"
puts "Hello, #{person}" # => Hello, Matz!

Конструкция #{...} замещается результатом вычисления выражения, напи-


санного внутри нее. Например, конструкция #{2+2} выдала бы результат 4.
Применив подстановку выражения, можно вытащить параметр из команд-
ной строки и поместить его в выходные данные.
#!/usr/bin/env ruby

puts "Hello, #{ARGV[0]}!"

Ruby хранит параметры командной строки в предопределенной переменной,


которая называется ARGV. ARGV[0] ссылается на первый элемент данных в ко-
мандной строке, нулевой элемент в ARGV. Выполните только что отредакти-
рованную программу (из файла matz.rb) с параметром Matz и полюбуйтесь на
результат:
$ matz.rb Matz
Hello, Matz!

Форматирование строки
Выходные данные можно менять с помощью форматирующего флажка %s
и метода %:
hi = "Hello, %s"
puts hi % "Matz!" # => "Hello, Matz!"
puts hi % "people!" # => "Hello, people!"
puts hi % "universe!" # => "Hello, universe!"

Можно применять метод % так:


"%s, %s!" % [ "Hello", "Matz" ]
16 Глава 1

Здесь % — метод из класса String, который форматирует строку. Вот как это
выглядит с методом sprintf:
sprintf("Hello, %s", "Маtz!") # => "Hello, Matz!"

Для вывода данных на дисплей (стандартное выходное устройство, исполь-


зуемое по умолчанию) предназначен метод printf.
printf( "Hello, %s", "Matz!" ) # => Hello, Matz!

Форматирование строк посредством sprintf описано в разд. "Форматирова-


ние вывода с помощью sprintf " главы 10.

Метод eval и параметр -e


Метод eval вычисляет строку, заключенную в двойные кавычки как опера-
тор или выражение языка Ruby и возвращает результат. Удобен для тестиро-
вания.
eval "puts 'Hello, Matz!'" # => Hello, Matz!

Подобным же образом можно напечатать "Hello, Matz!" без применения от-


дельного файла — с помощью параметра –e (от англ. execute/evaluate — вы-
полнить/вычислить):
ruby -e "puts 'Hello, Matz!'"

Обратите внимание на то, что в параметре –e внутри двойных кавычек при-


меняются одинарные. Параметр –e можно использовать многократно:
ruby -e "print 'Hello, '" -e "puts 'Matz!'"

Два параметра –e дают тот же результат, что и раньше (или то, что выглядит,
как тот же результат):
Hello, Matz!

В первом параметре –e указан метод print, который в отличие от puts не


добавляет в конец строки символы конца строки или новой строки. Если бы
вместо print было написано puts, то результат получился бы такой:
Hello,
Matz!

При желании можно использовать в параметре –e несколько операторов,


разделенных точкой с запятой:
ruby -e "three = 3; puts 'Matz! ' * three"

Получится:
Matz! Matz! Matz!
Основные положения 17

Ввод данных с клавиатуры


Для чтения со стандартного устройства ввода (по умолчанию, с клавиатуры)
можно использовать метод gets.
#!/usr/bin/env ruby

print "Who do you want to say hello to? "


hello = gets
puts "Hello, " + hello

Программа выводит сообщение "Who do you want to say hello to?". Метод
gets читает то, что вы набираете на клавиатуре, и присваивает переменной
hello. Оператор puts выводит слово "Hello" плюс то, что содержится в пе-
ременной hello, на стандартное устройство вывода (по умолчанию, на дис-
плей). Запустите программу, затем наберите ответ на вопрос.
$ matz.rb
Who do you want to say hello to? Matz!
Hello, Matz!

Методы
У вас уже был шанс познакомиться с методами system и eval; а теперь по-
пробуйте определить свой собственный метод с помощью def...end:
def hello
puts "Hello, Matz!"
end

hello # => Hello, Matz!

Метод с именем hello содержит единственный оператор, который выводит


строку "Hello, Matz!". Чтобы увидеть, как он работает, обратитесь к методу,
вызвав его по имени, hello.

Блок
Переопределите метод hello, так чтобы он содержал единственный оператор
yield, затем обратитесь к новой версии hello с помощью блока (программ-
ного кода в фигурных скобках):
def hello
yield
18 Глава 1

end

hello { puts "Hello, Matz!" } # => Hello, Matz!

Оператор yield выполняет блок кода в фигурных скобках (т. е. { puts


"Hello, Matz!" }), связанный с вызовом метода hello. Более подробно
о блоках см. в разд. "Блоки" главы 2.

Метод each
Сделаем еще один шаг. Выведем все элементы массива с помощью метода
each, за которым следует блок:
[ "Hello, ", "Matz!"].each { |e| print e }

Массив — это упорядоченный список элементов. Метод each использует


блок — напоминаю, программный код, заключенный в фигурные скобки —
для выполнения итераций или повторяющейся обработки всех элементов
массива. |e| представляет элементы, извлеченные из массива; оператор
print e печатает каждый элемент массива. Более подробно массивы рас-
смотрены в главе 6.

Процедурный объект
Блок можно преобразовать в объект. Такой объект называется proc (читается
"прок") или процедурный объект (proc — procedure — процедура). Про-
цедурные объекты сохраняют среду выполнения программы, эта информация
упаковывается вместе с ними. Один из способов создания процедурного объ-
екта — это метод lambda. Я воспользовался им для формирования уже такого
знакомого вам приветствия.
prc = lambda { |name| puts "Hello, " + name }

Процедурный объект запоминается в prc как результат обращения к методу


lambda, сохраняющему блок в виде объекта. Теперь можно обратиться к объ-
екту, указав параметр; call выполнит процедурный объект с параметром и
возвратит строку.
prc.call "Matz!" # => Hello, Matz!

Подробную информацию о процедурных объектах см. в разд. "Процедурные


объекты" главы 2.

XML
Для обработки XML (Extensible Markup Language, расширяемый язык разметки
гипертекста) в Ruby встроен REXML (Ruby Electric XML). Поприветствуйте
с его помощью уважаемого основателя, как показано в примерах 1.1 и 1.2.
Основные положения 19

Пример 1.1. matz.xml

<hello>Matz!</hello>

Пример 1.2. matz_xml.rb

#!/usr/bin/env ruby

require "rexml/document"

file = File.new("matz.xml")
doc = REXML::Document.new file
puts doc.to_s

При выполнении эта программа берет XML-файл matz.xml и показывает его


содержимое.

Класс
Поздоровайтесь с разработчиком, воспользовавшись классом Hello, как по-
казано в примере 1.3.

Пример 1.3. hello.rb

class Hello

def initialize( name )


@name = name
end

def hello_matz
puts "Hello, " + @name + "!"
end
end

hi = Hello.new( "Matz" )
hi.hello_matz # => Hello, Matz!

Еще немного про классы написано в главе 2. А глава 9 полностью посвящена им.
20 Глава 1

Инструментарий Tk
Создайте графическую версию "Hello, Matz!" с помощью инструментария Tk
(см. http://www.tcl.tk), как показано в примере 1.4.

Пример 1.4. matz_tk.rb

#!/usr/bin/env ruby

require 'tk'
hello = TkRoot.new
TkLabel.new(hello) do
text "\n Hello, Matz! \n"
pack
end
Tk.mainloop

Метод require загружает библиотеку Tk. Следующая строка программы


создает новый объект TkRoot под именем hello. TkLabel.new добавляет
к этому объекту метку с текстом "Hello, Matz!". Tk.mainloop производит
графическое событие и выводит графику, показанную на рис. 1.1. Программу
можно выполнить, набрав в командной строке:
matz_tk.rb &

Символ & помещает процесс в фоновый режим системы UNIX/Linux. Допол-


нительную информацию о библиотеке Tk и других графических интерфейсах
пользователя можно найти в разд. "Применение Tk" главы 10.

Рис. 1.1. Tk-версия примера "Hello, Matz!" в Mac OS X

Редактирование и выполнение программ


в TextMate
Если в вашем распоряжении Mac (Macintosh), то вы получите гораздо больше
удовольствия от жизни, раздобыв экземпляр TextMate. (Скачайте бесплатную
пробную версию или заплатите за копию на сайте http://www.macromates.com.)
Основные положения 21

В TextMate есть языковой пакет, который превращает редактирование на за-


данных языках — таких как HTML, C, Java, Python, Ruby и Rails — в игру.
Конечно, в других интегрированных средах разработки есть аналогичные
возможности, и я не буду тратить энергию на то, чтобы критиковать их, пуб-
лично или приватно. Разница для меня заключается в том, что TextMat эле-
гантен; он не ошеломляет вас сложными излишествами. Он здесь, чтобы по-
мочь, не вмешиваясь в вашу жизнь.
На рис. 1.2 показана версия файла matz.rb, открытого для редактирования
в TextMate. Чтобы выполнить эту программу в TextMate, просто нажмите
комбинацию клавиш <Command>+<R>, и результат выполнения появится
в отдельном окне (RubyMate), показанном на рис. 1.3.

Рис. 1.2. Редактирование программы на языке Ruby в TextMate

Рис. 1.3. Результат выполнения программы на языке Ruby в TextMate

Далее перечислены приемы работы с Ruby в TextMate.


 Дабавьте шаблоны для Ruby, чтобы ускорить создание файла.
 Вставляйте после ключевых слов Ruby, таких как begin или if, символ
табуляции, и TextMate завершит набор.
22 Глава 1

 Выполняйте однострочную программу при помощи комбинации клавиш


<Control>+<Shift>+<E>. Результат попадет в файл. В других файлах (на-
пример, в файлах HTML) тоже можно так делать.
 Проверяйте синтаксис, не выполняя программу, с помощью комбинации
клавиш <Control>+<Shift>+<V>.
 Поместите курсор на ключевое слово или название метода языка Ruby,
затем нажмите комбинацию клавиш <Control>+<H> для получения справ-
ки по этому термину.

Interactive Ruby
Interactive Ruby или irb — это интерактивная среда типа командной строки
для языка Ruby, позволяющая увидеть результаты (или ошибки) после ввода
каждого оператора. Установив Ruby, вы получили также irb.
Для начала работы с ним, наберите в командной строке:
$ irb –v
В ответ вы должны получить номер версии irb:
irb 0.9.5(05/04/13)

Если irb наличествует, то вы готовы двигаться дальше; если нет, прочтите


разд. "Установка Ruby" далее в этой главе и выполните приведенные там
инструкции.
После ввода irb в командной строке вы получаете командную строку irb.
Наберите в этой командной строке оператор, затем нажмите клавишу <Re-
turn> или <Enter>:
irb(main):00l:0> puts "Hello, Matz! "
Hello, Matz!
=> nil

ЗАМЕЧАНИЕ
nil, помещенный после => в выходных данных, — это значение, воз-
вращенное методом puts. nil имеет особое значение в Ruby. Он
обозначает пустоту и всегда означает ложь.

Оператор puts выводит строку, за которой следует символ новой строки.

ЗАМЕЧАНИЕ
Символ новой строки может быть разным в зависимости от платфор-
мы. В системах Mac OS X и UNIX/Linux это символ LF (от англ. line-
feed — перевод строки); в Microsoft Windows это CR (от англ. carriage
return — возврат каретки), за которым следует LF.
Основные положения 23

Как было сказано ранее, можно присвоить переменной строку или какое-
нибудь другое значение для многократного использования. В приведенной
далее команде строка "Hello, Matz!" присвоена переменной по имени hi
и распечатана при помощи puts:
irb(main):002:0> hi = "Hello, Matz! "
=> "Hello, Matz! "
irb(main):003:0> puts hi
Hello, Matz!
=> nil

Выведите значение переменной hi три раза:


irb(main):004:0> puts hi * 3
Hello, Matz! Hello, Matz! Hello, Matz!
=> nil

Можно проделать несколько простых арифметических операций:


irb(main):006:0> 10 + 10
=> 20
irb(main):007:0> 4*5
=> 20
irb(main):008:0> 100 / 5
=> 20
irb(main):009:0> 50 - 30
=> 20
irb(main):010:0> 80 % 60
=> 20

Можно продолжать и продолжать. irb — великолепная среда для игры с Ruby


и понимания, как он работает, потому что в ней всегда получаешь немедлен-
ный отклик на каждый предпринятый шаг.
У вас еще будет возможность встретиться с irb в этой книге. Фактически, irb
можно использовать для выполнения любой приведенной здесь программы
на языке Ruby.

Информационные ресурсы
На официальном сайте http://www.ruby-lang.org можно найти массу ин-
формации о Ruby. Там есть новости, файлы для загрузки, учебные пособия,
а также документация, списки рассылки и другие материалы. Компания Ruby
Central, Inc. проводит ежегодную Международную конференцию по языку
24 Глава 1

Ruby (International Ruby Conference, http://www.rubycentral.org/conference).


Обычно места на ней очень быстро заканчиваются, так что действуйте соот-
ветственно.
Если не считать страничку с документацией на сайте ruby-lang.org
(http://www.ruby-lang.org/en/documentation), то сайт http://www.ruby-
doc.org — отличное место для охоты за всем, что касается Ruby. RDoc —
это инструмент, генерирующий документацию из исходных текстов Ruby.
Документацию по ядру Ruby, произведенную с помощью RDoc, можно найти на
сайте http:// www.ruby-doc.org/core. На Mac (Tiger или более поздней версии)
хорошим инструментом для быстрого поиска является виджет RDoc для
Dashboard (Инструментальная панель, см. рис. 1.4), спасибо Precision Information
Services (Служба точной информации, http://www.precisionis.com.au). Виджет
можно скачать отсюда: http://www.apple.com/downloads/dashboard/developer/
rubyrdocwidget.html.

Рис. 1.4. Виджет RDoc на Dashboard

Самый популярный из основных списков рассылки по тематике Ruby — это


Ruby-Talk. Подписаться на эту рассылку (что нужно сделать, несомненно)
можно на http://www.ruby-lang.org/en/community/mailing-lists. На этом же
сайте вы увидите несколько других списков. Наиболее полный список совме-
стных рассылок, включая списки на других языках (не английском), находит-
ся на http://www.ruby-forum.com.
RubyForge (http://rubyforge.org) — это ведущий сайт для постоянно увели-
чивающегося числа Ruby-проектов с открытым исходным текстом. В группу
наиболее популярных проектов входят: Mongrel — быстрый HTTP-сервер
Основные положения 25

(http://rubyforge.org/projects/mongrel), RubyGems (http://rubyforge.org/


projects/rubygems) — совершенно простой инструмент для установки паке-
тов программ, и Instant Rails (http://rubyforge.org/projects/instantrails) —
пошаговый инсталлятор для Windows, который включает Ruby, Rails, Apache
и MySQL. Ruby Application Archive (RAA, архив приложений на языке Ruby)
на http://raa.ruby-lang.org предшествовал RubyForge, и все еще остается по-
пулярным сайтом для хостинга Ruby-проектов — их там более 1500 и их
число все растет.
Для дальнейшего чтения выберите книгу Дэйва Томаса ("Dave Thomas,
Programming Ruby, Second Edition"), выпущенную издательством Pragmatic
(http://www.pragmaticprogrammer.com/titles/ruby/index.html или
http://www.oreilly.com/catalog/0974514055/index.html). Эта книга (с кирко-
мотыгой на обложке) хорошо написана и подробна настолько, насколько это
возможно. Она не разочарует. Бесплатную электронную версию ее первого
издания можно найти на http://www.rubycentral.com/book.
Книга Хэла Фултона (Hal Fulton) "The Ruby Way" (издательство Addison-
Wesley) также издана во второй раз (http://www.samspublishing.com/
bookstore/product.asp?isbn=0672328844&rl=l). Она общепризнанна и пред-
ставляется стоящим капиталовложением. Есть еще и другие книги, а также
те, что находятся на пути к читателю — их слишком много, чтобы перечис-
лять (http://www.ruby-lang.org/en/documentation) — но я обращаю ваше
внимание на книги Дэйва и Хэла, потому что они давно в игре и все еще не
вышли из нее.
Да, и пока я не забыл, вы не сможете считаться квалифицированным специа-
листом по Ruby, пока не прочтете руководство "Why's (poignant) guide to
Ruby", написанное why the lucky stiff. Так его зовут. (Я не знаю его настояще-
го имени. Откровенно говоря, я не хочу знать его "настоящее" имя. Чтобы не
портить удовольствие.) Это самое забавное руководство, которое я когда-
либо читал, настоятельно рекомендую. Его можно найти здесь:
http://poignantguide.net/ruby.

Установка Ruby
Ruby доступен на большинстве платформ. В этом разделе вы узнаете, как ус-
тановить Ruby под Mac OS X, Windows и Linux. Основная страница для за-
грузки Ruby находится по адресу: //www.ruby-lang.org/en/downloads. Веро-
ятно, большинство из вас смогло бы разобраться, как установить Ruby,
руководствуясь лишь приведенными там указаниями, но, тем не менее, в ма-
териалах этого раздела вы найдете кое-какие дополнительные инструкции.
26 Глава 1

Процедура установки — это изменяющийся объект, и печатные издания


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

Установка Ruby в Mac OS X Tiger


Как уже говорилось, Tiger поставляется вместе со старой версией Ruby. Ка-
кая это версия, зависит от того, с какой редакцией Tiger вы имеете дело. Моя
редакция Tiger на данный момент имеет номер 10.4.8, и с ней пришла версия
1.8.2. Вам захочется более свежую версию, я тоже хотел.
Проще всего установить Ruby (и другие компьютерные программы) с помо-
щью Locomotive (http://locomotive.raaum.org). Информацию о том, что за-
гружает Locomotive (файлы типа dmg), включая Ruby on Rails, см. на
http://locomotive.raaum.org/ bundles.html. Возможно, этих программ будет
больше, чем вам хотелось. На http://prdownloads.sourceforge.net/locomotive/
Locomotive_2.0.8.dmg?download вы найдете зеркало. Выберите его, а затем
выполняйте указанные шаги, как если бы вы устанавливали любой другой
файл dmg.
Самая безупречная форма установки, по моему мнению, состоит в том, чтобы
загружать и компилировать файлы с исходным текстом. Другими словами,
вы скачиваете дистрибутив файлов заданной версии, извлекаете файлы из
архива, компилируете файлы (те, для которых нужна компиляция), а затем
копируете эти файлы в соответствующие каталоги. Таковы основные шаги,
но есть несколько инструментов, которые сделают эту работу приятнее, на-
пример, configure и make. Воспользуемся предоставляемыми ими преимуще-
ствами, когда будем устанавливать новую версию Ruby под Tiger (эти шаги
можно также применить к установке под Linux).
Эти шаги могут показаться на первый взгляд трудными, но это не так. Просто
следуйте указаниям, и все получится.
Вы найдете превосходные инструкции по установке Ruby под Tiger в книге
Дэна Бенджамина (Dan Benjamin) "Building Ruby, Rails, LightTPD, and
MySQL on Tiger", http://hivelogic.com/articles/2005/12/01/ruby_rails_lighttpd_
mysql_tiger. В ней рассказывается об установке большего числа компьютер-
ных программ, чем вам сейчас нужно. Я воспользовался указанными там ша-
гами только для установки Ruby и подогнал эти шаги для самых последних
версий программного обеспечения.
Чтобы эта процедура установки работала, на вашем Mac должен быть уста-
новлен XCode. XCode — это набор программных инструментов для Apple.
Основные положения 27

Можно прочесть о нем на http://www.apple.com/macosx/features/xcode и


загрузить его с http://developer.apple. com/tools/download. Инструкции по
загрузке там простые.
Как уже говорилось, у Tiger есть некоторые проблемы с Ruby
(http://wiki.rubyonrails.com/rails/pages/HowtoInstallOnOSXTiger). Один из
способов решить их — скачать и установить readline (http://tiswww.tis.case.edu/
~chet/readline/readline.html), что позволит вам редактировать командную
строку (irb использует readline). Далее приведены шаги для загрузки и уста-
новки readline:
1. Отыщите на ftp://ftp.gnu.org/gnu/readline последнюю версию (5.2 на мо-
мент написания книги) и загрузите ее. (Я помещаю на своем Mac архивы с
исходными текстами в каталог lusr/local/src, так чтобы я всегда мог оты-
скать их.) Можно не использовать браузер или FTP. Возьмите curl
(http://curl.haxx.se). Параметр -0 указывает, что последняя часть URL за-
действована для создания имени файла результата.
$ curl -0 ftp://ftp.gnu.org/gnu/readline/readline-5.2.tar.gz

2. Извлеките файлы с помощью tar (x означает "извлечь" (extract), z означа-


ет gunzip, v означает "подробно" (verbose), f означает, что нужно исполь-
зовать архив файлов):
$ tar xzvf readline-5.2.tar.gz

3. Перейдите в каталог:
$ cd readline-5.2

4. Запустите configure (инструмент, порожденный из Autoconf, который


производит основные сценарии для конфигурирования пакетов программ),
заменив {$prefix} на /usr/local:
$ ./configure --prefix=/usr/local

5. Запустите make — инструмент для разработки приложений. Он компили-


рует файлы с исходными текстами и подготавливает все к установке. Ре-
зультаты можно протестировать:
$ make
$ make test

6. И, наконец, выполните установку:


$ make install

Если вы вошли в систему не как root, то можно принять на себя полно-


мочия суперпользователя (привилегированного пользователя), добавив
28 Глава 1

в начало этой команды утилиту sudo (http://www.sudo.ws), которая потре-


бует пароль:
$ sudo make install

Для установки Ruby нужно выполнить очень похожие шаги:


1. Находясь в каталоге /usr/local/src, возьмите архив последней версии (1.8.6
на момент написания книги):
$ curl -0 ftp://ftp.ruby-lang.org/pub/ruby/ruby-1.8.6.tar.gz
2. Извлеките файлы:
$ tar xzvf ruby-1.8.6.tar.gz
3. Смените каталог:
$ cd ruby-1.8.6
4. Запустите configure (активирующий потоки POSIX, с readline):
$ ./configure --prefix=/usr/local --enable-pthread --with-
readline-dir=/usr/local
5. Запустите make, потом тестирование:
$ make
$ make test
6. Установите программу:
$ make install

Вам может потребоваться утилита sudo (http://www.sudo.ws), для кото-


рой необходим пароль):
$ sudo make install

7. Затем установите документацию:


$ make install-doc

или
$ sudo make install-doc

8. Укажите путь, если он еще не указан. Если не знаете, как это сделать, см.
врезку "Как настроить путь" далее в этой главе.
9. Теперь убедитесь, что Ruby занял свое место:
$ ruby -v

10. Вы должны получить радостный ответ:


$ ruby 1.8.6 (2007-03-13 patchlevel 0) [powerpc-darwin8.9.0]

Значит, все в порядке. Вы готовы встретиться с Ruby под Mac OS X.


Основные положения 29

Установка Ruby в Windows с помощью


One-Click Installer
Проще всего установить Ruby под Windows с помощью инсталлятора One-
Click Installer, доступного на сайте Ruby-Forge по адресу
http://rubyforge.org/projects/rubyinstaller. Нужно лишь выполнить такие
шаги:
1. Пойдите на сайт, откуда загружают Ruby, и щелкните по ссылке 1.8.6
One-Click Installer (может быть указана более поздняя версия) или пой-
дите на сайт инсталлятора One-Click Installer и щелкните по ссылке Down-
load. Щелкните на последнем по времени выпуска исполняемом файле
(ruby186-25.exe на момент написания книги).
2. Откройте исполняемый файл. Появится эксперт по установке (рис. 1.5).
Есть шанс включить в загружаемые файлы другие программы, такие как
редактор SciTE (http://www.scintilla.org/SciTE.html). Не забудьте дать
разрешение на установку RubyGems, когда получите запрос, т. к. этот ин-
струмент все равно поставляется по умолчанию, а вы, несомненно, захо-
тите позднее им воспользоваться.
3. Укажите адрес папки назначения (такой как C:\Ruby или C:\Program
Files\Ruby). Если вы попытаетесь установить новую версию поверх ста-
рой, вас попросят сначала деинсталлировать старую версию.

Рис. 1.5. Окно One-Click Installer


30 Глава 1

4. Добавьте каталог bin нового Ruby к своим путям; например, если Ruby
находится в каталоге C:\Ruby, добавьте к своим путям C:\Ruby\bin (см.
врезку "Как настроить путь" далее в этой главе, если не знаете, как это
сделать; указать путь можно и после установки).
5. После установки Ruby откройте окно DOS (командную строку) и наберите:
ruby –v

Вы должны получить ответ, похожий на этот:


ruby 1.8.6 (2007-03-13 patchlevel 0) [i386-mswin32]
6. Проверьте системную переменную PATH и убедитесь, что в ней содержит-
ся путь к двоичным файлам Ruby в каталоге bin. Хотя One-Click Installer
должен сам обо всем этом позаботиться.

Установка двоичных файлов Ruby


в Windows
Установка Ruby с использованием двоичных файлов (предварительно скомпи-
лированных исполняемых файлов) также проста, как и установка с помощью
One-Click Installer. Далее перечислены предлагаемые шаги по установке:
1. Решите, куда хотите установить файлы Ruby — например, в каталог
C:\Ruby или C:\Program Files\Ruby.
2. Загрузите двоичный ZIP-архив последней версии Ruby (1.8.6 на момент
написания книги). Для этого пойдите на страницу загрузки Ruby
http://www.ruby-lang.org/en/downloads и найдите раздел Ruby on Win-
dows, затем щелкните ссылку Ruby 1.8.6 Binary. Или просто укажите на
ftp://ftp.ruby-lang.org/pub/ruby/binaries/mswin32/ (или более позднюю
версию) в браузере. Произойдет загрузка архива файлов.
3. Откройте архив (ruby-1.8.6-i386-mswin32.zip или более поздний) с помо-
щью Windows Explorer (Проводник), а затем извлеките из него файлы
в каталог, выбранный на шаге 1 (рис. 1.6).
4. Поместите каталог bin нового Ruby в свои пути; например, если Ruby
находится в каталоге C:\Ruby, добавьте к своим путям C:\Ruby\bin (см.
врезку "Как настроить путь" далее в этой главе, если не знаете, как это
сделать).
5. После установки Ruby откройте окно DOS (командную строку) и набе-
рите:
ruby -v
Основные положения 31

6. Если вам не удалось получить что-нибудь похожее на приведенный далее


ответ, проверьте свою системную переменную PATH и убедитесь, что она
содержит путь к двоичным файлам Ruby в каталоге bin:
ruby 1.8.6 (2006-08-25) [i386-mswin32]

Рис. 1.6. Каталог C:\Ruby\bin в Windows Explorer

КАК НАСТРОИТЬ ПУТЬ


Если вы работаете под Mac OS X Darwin или Linux (bash), наберите в файле
.bash_login такую строку:
export PATH="/usr/local/bin:...:$PATH"
Каталог Ruby /usr/local/bin окажется в начале пути. Многоточие (...) символи-
зирует любые другие каталоги, которые вы хотите добавить к своему пути.
$PATH — переменная текущего пути. Указанная строка допишет ваши допол-
нения к пути и в то же время сохранит текущий путь. Пути отделяются друг от
друга двоеточием (:).
Если вы работаете под Windows и для установки использовали One-Click
Installer, то путь должен был быть установлен автоматически. (Следующий аб-
зац написан на тот случай, если что-то не сработало.)
Для установки пути в Windows, щелкните Control Panel  System (Панель
управления  Система), перейдите на вкладку Advanced (Дополнительно),
нажмите кнопку Environment Variables (Переменные среды). Среди систем-
ных переменных (System Variables) выберите переменную Path, нажмите
кнопку Edit (Изменить). Добавьте в переменную полное имя пути к каталогу
bin — что-то вроде C:\Ruby\bin — и точку с запятой. Нажмите кнопку OK в окне
диалога Edit System Variable (Изменить системную переменную), затем на-
жмите кнопку OK в окне диалога Environment Variables (Переменные среды).
Вам придется открыть еще раз окно DOS (командную строку), чтобы система
распознала новый путь.
32 Глава 1

Установка Ruby в Linux


Шаги, рассмотренные в разделе об установке Ruby под Mac OS X с исполь-
зованием исходных файлов, годятся и для Linux. Здесь я упомяну о некото-
рых других возможностях. Кто знаком с Linux, тот знает, о чем я говорю.
 Если вы работаете в Red Hat (http://www.redhat.com), то можете найти
последнюю версию Ruby на RPM Find (http://rpmfind.net/linux/rpm2html/
search.php?query=Ruby) и затем воспользоваться rpm для его установки.
 Для Debian (http://www.debian.org) подойдет apt-get (http://www.debian.org/
doc/manuals/apt-howto).
 Для Gentoo (http://www.gentoo.org) возьмите emerge (http://www.gentoo.org/
doc/en/handbook/handbook-x86.xml?part=2&chap=l).

В разрешении отказано
Если вы впервые используете командную оболочку в Mac OS X или Linux,
то что вам делать при получении такого сообщения?
-bash: ./matz.rb: Permission denied

Скорее всего, оно означает, что файл не установлен как исполняемый. Чтобы
исправить такое положение, измените управление доступом к файлу, приме-
нив команду chmod:
chmod 755 matz.rb

755 означает, что теперь в управляющей таблице записано rwxr-xr-x (где r —


это read, читать, w — это write, записывать, а x — это execute, выполнять).
Читать и исполнять файл может каждый (владелец, группа и все остальные,
именно в таком порядке), а записывать в него может только владелец. Для
получения дополнительной информации по chmod наберите в командной
строке man chmod.

Сопоставление типа файлов в Windows


Этот раздел предназначен для тех, кто работает в Windows и никогда раньше
не выполнял сопоставление типа файлов. Если тема вам знакома или у вас
другая платформа, пропустите его.
Сама по себе Windows не знает или не заботится о символах #!, которые в ко-
мандной оболочке системы UNIX/Linux позволяют выполнять программу про-
стым вызовом ее по имени. В Windows можно добиться подобного эффекта,
выполнив сопоставление типа файлов с помощью команд assoc и ftype.
Основные положения 33

ЗАМЕЧАНИЕ
Если для установки Ruby в Windows вы использовали One-Click Ruby
Installer, то все приведенные далее команды были выполнены неглас-
но, автоматически.

Прежде всего, при помощи команды assoc выясните, существует ли сопос-


тавление для расширения rb.
C:\Ruby Code>assoc .rb
File association not found for extension .rb
(Не найдено сопоставление для расширения имени файла rb)

Оно не найдено, поэтому сопоставьте расширение rb с типом файла:


C:\Ruby Code>assoc .rb=rbfile

Теперь проверьте, возникло ли сопоставление:


C:\Ruby Code>assoc .rb
.rb=rbFile
Теперь проверьте, существует ли тип файла:
C:\Ruby Code>ftype rbfile
File type 'rbfile' not found or no open command associated with it.
(Тип файлов 'rbfile' не найден или ему не сопоставлена команда открытия)
Он не найден, его нужно создать:
C:\Ruby Code>ftype rbfile="C:\Program Files\Ruby\bin\ruby.exe" "%l" %*

Убедитесь, что указали правильный путь к исполняемому файлу интерпрета-


тора Ruby и правильные подстановочные переменные. %1 — подстановочная
переменная для файла, который вы собираетесь выполнять, а %* принимает
все остальные параметры, которые могут появиться в командной строке. Вы-
полните проверку:
C:\Ruby Code>ftype rbfile
rbfile="C:\Program Files\Ruby\bin\ruby.exe" "%l" %*

И, наконец, добавьте rb в переменную среды PATHEXT. А вдруг оно уже там?


C:\Ruby Code>set PATHEXT
PATHEXT=.COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH;.tcl
Нет. Нужного нам расширения там нет, придется добавить:
C:\Ruby Code>set PATHEXT=.rb;%PATHEXT%
А затем проверить:
C:\Ruby Code>set PATHEXT
PATHEXT=.rb;.COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH;.tcl
34 Глава 1

Очень хорошо. Теперь выполните программу, указав в командной строке имя


файла с программой, без расширения:
C:\Ruby Code> matz
Hello, Matz!

Для сохранения выполненных установок добавьте эти команды в файл


autoexec.bat или переустановите переменные среды. Добраться до них мож-
но, выбрав Start  Control Panel  System (Пуск  Панель управления 
Система), щелкнув по вкладке Advanced (Дополнительно), а затем нажав
кнопку Environment Variables (Переменные среды).

Вопросы для самопроверки


1. Какое прозвище у изобретателя Ruby?
2. Ruby появился в 1995 году. Какой еще язык программирования был вы-
пущен в свет в том же году?
3. Обязан ли морально или еще как-то каждый, кто пишет книги по про-
граммированию, писать программу "Hello, World!" ("Привет, мир!")?
4. Что означает аббревиатура irb?
5. Какой у Ruby "захватчик рынка" (killer app)?
6. Как называется забавная книга по языку Ruby?
7. Кто написал книгу с киркомотыгой на обложке?
8. Какая у автора любимая среда программирования на Mac?
Глава 2

Обзорная экскурсия по Ruby

В этой главе без особых подробностей представлены основы языка Ruby:


классы и модули, включая класс Object и модуль Kernel, зарезервированные
(ключевые) слова, комментарии, переменные, методы и т. д. Большая часть
тем будет подробно рассмотрена в других разделах книги. Некоторые темы
достойны целых глав, другие — только разделов (находящихся в главе 10).
Я всегда сообщу вам, где еще можно найти информацию по теме. А в этой
главе приведено самое подробное во всей книге обсуждение методов и блоков.

Ruby — объектно-ориентированный язык


Matz, разработчик Ruby, хотел создать собственный язык программирования
с тех самых пор, как оказался в старших классах средней школы. Он мечтал
создать скриптовый язык, но также хотел, чтобы язык был объектно-
ориентированным.
Ruby пошел гораздо дальше простого языка написания сценариев, хотя про-
граммы на нем, возможно, и выглядят как скрипты оболочек. И он — не про-
цедурный язык, но может быть использован в качестве такового.
В Ruby есть классы. В классах содержатся данные в форме переменных
и констант и методы, которые представляют собой компактные совокупности
кода, предназначенные для облегчения выполнения операций над данными.
Классы могут наследовать информацию друг от друга, но только от одного
класса каждый раз. Это позволяет использовать код повторно (а значит, тра-
тить меньше времени на фиксацию и отладку кода) и смешивать код при на-
следовании.
Класс подобен копии. С помощью метода new эта копия может быть присвоена
переменной или стать экземпляром класса и, таким образом, стать объектом.
36 Глава 2

В Ruby почти все представляет собой объект; фактически, все, что Ruby мо-
жет связать с именем переменной, является объектом.
Многое можно узнать о классах, и вы найдете эту информацию в главе 9. Те-
перь же вполне можно обойтись основами. В примере 2.1 показана програм-
ма на языке Ruby, friendly.rb, в которой имеются два класса: Hello и Goodbye.
Вы найдете ее в архиве программ Ruby на странице http://www.oreilly.com/
catalog/learningruby. Запустите эту программу из командной строки, из ка-
талога, где установлен архив. Если примера с кодом нет в файле, наберите
его в irb, чтобы самому увидеть, что он делает. Я призываю вас выполнять
как можно больше программ.

Пример 2.1. friendly.rb

class Hello
def howdy
greeting = "Hello, Matz!"
puts greeting
end
end

class Goodbye < Hello


def solong
farewell = "Goodbye, Matz."
puts farewell
end
end

friendly = Goodbye.new
friendly.howdy
friendly.solong

Выполнив программу из примера 2.1, вы получите в ответ эти сообщения:


$ friendly.rb
Hello, Matz!
Goodbye, Matz.

Искушенные программисты и сами безо всяких объяснений, вероятно, смогут


рассказать, что происходит в примере 2.1. Если вы не один из них, читайте
дальше; в противном случае переходите к следующему заголовку (или перей-
дите к главе 9, если жаждете знать все подробности о классах в языке Ruby).
Обзорная экскурсия по Ruby 37

Класс Hello определяет метод howdy. Этот метод печатает содержимое стро-
ки "Hello, Matz!", присвоенной переменной greeting. Класс Goodbye точно
так же содержит определение метода solong, который печатает строку
"Goodbye, Matz!", присвоенную переменной farewell. Кроме того, класс
Goodbye наследует то, что есть в классе Hello, для этого предназначен сим-
вол <. Это означает, что классу Goodbye не обязательно переопределять метод
howdy. Он его просто наследует.
friendly — объект, экземпляр класса Goodbye. Метод new, вызванный
Goodbye, происходит из класса Object, он создает новый экземпляр friendly
(более подробно о классе Object написано в следующем разделе). Объект
friendly можно использовать для вызова обоих методов, howdy и solong,
т. к. он знает о них по своей сути. Он знает о методе solong, потому что тот
определен внутри класса Goodbye, и он знает о методе howdy, потому что
Goodbye унаследовал его от Hello.
Вот примерно все, что я собирался рассказать вам сейчас. Информация
о классах разбросана по следующим главам. В главе 9 классы разобраны бо-
лее подробно.

АНАЛОГИЯ С ВЕДРОМ
Если вы не знаете, что такое объектно-ориентированное программирование
(ООП), попробуйте уяснить это на простой аналогии. Думайте о классе — цен-
тральном понятии в ООП, как о ведре. Представьте, что в него налита вода,
а сверху плавает один или два ковшика. Вода подобна собственности (дан-
ным или информации), которая содержится в классе, а ковшики — это инст-
рументы (методы), с помощью которых можно обращаться с водой (данными).
Основным инструментом, которым вы воздействуете на класс, является ме-
тод — совокупность кода, которой можно дать имя и использовать много-
кратно. Метод подобен ковшику, которым вы зачерпываете и наливаете воду.
Ведро можно использовать многократно, выливая старую воду и наливая
свежую, и даже помещать его внутрь другого ведра. Это основы ООП, в отсут-
ствие жаргона. Его обильную дозу вы получите в главе 9.

Класс Object и модуль Kernel


Класс Object — основной класс языка Ruby, предок всех других классов,
и он всегда присутствует магическим образом, когда бы вы ни выполняли
программу. Вам не нужно ничего придумывать, чтобы получить доступ к его
возможностям в других классах. Он уже там и ждет вас.
Вместе с классом Object появляется множество функциональных возможно-
стей в форме методов и констант. Эти возможности автоматически наследу-
ются всеми остальными программами Ruby. В этом разделе я познакомлю
вас с некоторыми из них.
38 Глава 2

Object предоставляет такие методы, как == и eql?, class, inspect, object_id


и to_s. В следующих главах вы узнаете о них больше. А обо всех методах
класса Object можно прочитать на странице http://www.ruby-doc.org/core/
classes/Object.html.
Kernel — это модуль в языке Ruby. Модуль подобен классу, но вы не можете
присвоить его в качестве объекта, как это можно проделывать с классом. Од-
нако когда вы включаете или "подмешиваете" модуль в класс, то получаете
доступ ко всем его методам внутри этого класса. Методы из включенного
модуля можно использовать, не заботясь об их реализации.
Object включает модуль Kernel. Это значит, что раз в программах на языке
Ruby у вас всегда есть доступ к Object, вы также получаете все методы
Kernel. Вы уже видели некоторые из них в действии, такие как print и puts.
Подборка наиболее часто используемых методов Kernel включает eval, exit,
gets, loop, require, sleep и sprintf. Вы повстречаетесь с большей их ча-
стью в последующих главах этой книги.
К методам Kernel не нужно приставлять префикс в виде имени объекта или
получателя. Просто вызывайте методы в любой программе, и они будут ра-
ботать. Читайте о модуле Kernel на http://www.ruby-doc.org/core/classes/
Kernel.html.

Зарезервированные слова языка Ruby


У каждого языка программирования есть свой список зарезервированных
слов (также известных как ключевые слова), которые резервируются для соб-
ственных целей языка, с тем чтобы он мог выполнять свою работу. Из этих
слов состоят операторы программы, а без операторов или команд как про-
грамма может сообщить компьютеру, что ему делать?
В табл. 2.1 перечислены зарезервированные слова языка Ruby и кратко опи-
сано назначение каждого из них.

Таблица 2.1. Зарезервированные слова языка Ruby

Зарезервированное Описание
слово
BEGIN Код, заключенный в { и }, выполняется до выполнения
программы
END Код, заключенный в { и }, выполняется, когда программа
заканчивается
alias Создает альтернативное имя (псевдоним) для сущест-
вующего метода, оператора или глобальной переменной
Обзорная экскурсия по Ruby 39

Таблица 2.1 (продолжение)

Зарезервированное Описание
слово
and Логический оператор; то же самое, что &&, только у and
более низкий приоритет (ср. с or)
begin Начинает блок кода или группу операторов; закрывается
при помощи end
break Завершает циклы while или until или метод внутри блока
case Сравнивает выражение с соответствующим выражением
выбора в операторе when; закрывается при помощи end
(см. when)
class Определяет класс; закрывается при помощи end
def Определяет метод; закрывается при помощи end
defined? Специальный оператор, который определяет, существует
ли переменная, метод, суперметод или блок
do Начинает блок и выполняет код в этом блоке; закрывается
при помощи end
else Выполняет следующий за ним код, если значение предше-
ствующего условия в if, elsif, unless или when не true
elsif Выполняет следующий за ним код, если значение предше-
ствующего условия в if или elsif не true
end Заканчивает блок кода (группу операторов), начинающую-
ся с begin, def, do, if и т. д.
ensure Всегда выполняется при завершении блока; используется
после последнего rescue
false Логическая или булевская ложь, экземпляр класса
FalseClass (см. true)
for Начинает цикл for; используется с in
if Выполняет блок кода, если условие имеет значение true.
Закрывается при помощи end (ср. с unless, until)
in Используется в циклах (см. for)
module Определяет модуль; закрывается при помощи end
next Совершает переход в точку перед проверкой условия
в цикле (ср. с redo)
nil Пустая, не проинициализированная или недопустимая
переменная, но не то же самое, что 0; объект класса
NilClass
40 Глава 2

Таблица 2.1 (окончание)

Зарезервированное Описание
слово
not Логический оператор; то же самое, что !
or Логический оператор; то же самое, что ||, только у or бо-
лее низкий приоритет (ср. с and)
redo Совершает переход в точку после проверки условия
в цикле (ср. с next)
rescue Вычисляет выражение после возникновения исключения;
используется перед ensure
retry Вне rescue повторяет вызов метода; в rescue совершает
переход к началу блока (begin)
return Возвращает значение из метода или блока. Может быть
опущено
self Текущий объект (вызванный при помощи метода)
super Вызывает метод с тем же самым именем из суперкласса.
Суперкласс — родитель данного класса
then Продолжение для if, unless и when. Может быть опущено
true Логическая или булевская истина, экземпляр класса
TrueClass (см. false)
undef Метод в текущем классе становится неопределенным
unless Выполняет блок кода, если условие имеет значение false
(ср. с if, until)
until Выполняет блок кода, если условие имеет значение false
(ср. с if, unless)
when Начинает выражение выбора (одно или несколько) после
case
while Выполняет код, пока условие имеет значение true
yield Выполняет блок, переданный методу
__FILE__ Имя текущего исходного файла
__LINE__ Номер текущей строки в текущем исходном файле

Комментарии
Комментарий скрывает строки от интерпретатора Ruby таким образом, что
они отбрасываются или игнорируются. Это позволяет программисту (т. е.
вам) вставлять в программу разного рода информацию, чтобы другие смогли
Обзорная экскурсия по Ruby 41

понять, что в ней происходит. В Ruby есть два основных стиля комментирова-
ния. Знак # может находиться в начале отдельной строки:
# Я комментарий. Меня нужно игнорировать.

Или в той же самой строке после оператора или выражения:


name = "Floydene Wallup" # это тоже комментарий

Можно растянуть комментарий на несколько строк, как здесь:


# Это комментарий.
# .
# И это тоже комментарий.
# Я уже все сказал.

А вот и другой стиль. Этот блок комментария скрывает от интерпретатора


несколько строк с помощью операторных скобок =begin/=end:
=begin
Это комментарий.
Это тоже комментарий.
И это тоже комментарий.
Я уже все сказал.
=end

Блок может превратить в комментарий одну строку или столько строк,


сколько вы захотите.

Переменные
Переменная — это идентификатор или имя, которому может быть при-
своено значение, и это значение имеет или будет иметь тип во время вы-
полнения (когда программа выполняется). В следующем операторе пере-
менной x присвоено значение 100 при помощи знака присваивания:
x = 100

Теперь локальная переменная x содержит значение 100. Но, эй, какого оно
типа? По-моему, оно выглядит как целое — а как вы думаете? И что об этом
думает Ruby?
Большинство современных языков программирования, таких как C++ и Java,
статически типизировано. В основном это означает, что переменной при-
сваивается тип в тот момент, когда она объявляется, и, т. к. эти языки к тому
же строго типизированы, переменная остается того же самого типа до тех
пор, пока не будет приведена к другому типу, если это вообще возможно.
42 Глава 2

Например, в языке Java вам придется объявлять переменную, указав ее тип


(int) слева:
int months = 12;
int year = 2007;

В Ruby нет объявления типов. В нем просто присваивают значения перемен-


ным, вот так:
months = 12
year = 2007

По желанию можно поставить в конце строки точку с запятой, но все, что вам
действительно нужно, — это символ новой строки.
Очевидно, что значения в x, months и year целого типа, но вам не пришлось
задавать их тип, потому что Ruby автоматически сделал это за вас. Это
называется динамической типизацией или "утиной" типизацией (duck
typing).
Вот как работает динамическая типизация: если вы увидели приспособив-
шуюся к воде птицу, и она ходит как утка, крякает как утка, летает как утка и
плавает как утка, то, скорее всего, это утка. Ruby подобным же образом
смотрит на присвоенное переменной значение, и если оно "ходит", "кря-
кает", "летает" и "плавает" как целое, то Ruby предполагает, что и в об-
щем оно может действовать как целое.
Давайте спросим Ruby, что он думает об x, т. е. целая ли это переменная,
с помощью метода kind_of? (это метод из класса Object).
x.kind_of? Integer # => true

Так и есть, значение x ведет себя как целое! Собственно говоря, это экземп-
ляр класса Fixnum, который наследует от класса Integer.
x.class # => Fixnum

Изменим значение x с целого на значение с плавающей точкой с помощью


метода to_f из класса Fixnum (он наследуется также другими классами).
x.to f # => 100.0

ЗАМЕЧАНИЕ
Как я уже отмечал в главе 1, когда бы вы ни увидели стрелку => в коде
примера, она всегда следует за символом комментария (#). То, что
следует за =>, это результат вычисления строки или блока кода или
всей программы.
Обзорная экскурсия по Ruby 43

Локальные переменные
Ранее я обращался к x как к локальной переменной. Что это означает? Это
означает, что переменная имеет локальную область видимости (контекст).
Например, когда локальная переменная определена внутри метода или цикла,
ее область видимости находится внутри того метода или цикла, где она оп-
ределена. За его пределами ей нет применения.
Имена локальных переменных должны начинаться со строчной буквы или
с символа подчеркивания (_), например, alpha или _beta. Другой признак, по
которому в Ruby можно определить локальную переменную, состоит в том,
что ее имени не предшествует никакой специальный символ или знак, кроме _.
Любые другие типы переменных можно легко распознать по предшествую-
щему символу. В эти другие типы входят глобальные переменные, перемен-
ные экземпляра и переменные класса.

Переменные экземпляра
Переменная экземпляра — это переменная, к которой обращаются через эк-
земпляр класса и которая, следовательно, принадлежит заданному объекту.
Имя переменной экземпляра начинается с единичного знака "эт" (@), вот так:
@hello = hello

Получить доступ к переменным экземпляра вне их класса можно только при


помощи методов-аксессоров (от англ. accessor — средство доступа). О методах-
аксессорах мы поговорим в главе 9.

Переменные класса
Переменная класса совместно используется всеми экземплярами класса. Для
заданного класса существует только одна копия переменной класса. В Ruby
ей предшествуют два знака "эт" (@@). Вы должны проинициализировать пе-
ременную класса (объявить для нее значение) до того, как ее использовать.
@@times = 0

Вы увидите переменные класса в действии в главе 9.

Глобальные переменные
Глобальные переменные доступны в программе глобально, внутри любой
структуры. Их областью видимости является вся программа целиком. Их
имена начинаются со знака доллара ($).
$amount = "0.00"
44 Глава 2

Глобальные переменные трудно отслеживать. Лучше при разработке своего


кода используйте переменные класса или константы. То, что думает Matz
о глобальных переменных, я процитирую: "They are ugly, so don't use them"
("Они ужасны, поэтому не используйте их"). Я непременно следовал его совету.
(Применяйте вместо них одноэлементные множества (singleton); см. главу 9.)

Константы
Константы на протяжении жизни программы на языке Ruby содержат посто-
янные значения. Константы — это переменные, чьи имена начинаются
с заглавной буквы или содержат только заглавные буквы. Далее приведено
описание константы с именем Matz:
Matz = "Yukihiro Matsumoto"
puts Matz # => Yukihiro Matsumoto

Если константа определена внутри класса или модуля, то вы можете полу-


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

Параллельное присваивание
Мне нравится способность Ruby выполнять параллельное присваивание (как
в языках Perl, Python и JavaScript 1.7). Что это такое? Это способ присвоить
значение группе или серии переменных в одном операторе, на одной строке.
Часто мы присваиваем значения переменным по одному на каждой строке:
x = 100
y = 200
z = 500

С помощью параллельного присваивания вы проделаете то же самое, отделив


переменные, а затем и значения, запятыми:
x, y, z = 100, 200, 500

Можно присваивать даже значения различных типов, таких как строка, число
с плавающей точкой и целое число:
a, b, c = "cash", 1.99, 100

Параллельное присваивание практично. Это так характерно для всего, напи-


санного на Ruby.
Обзорная экскурсия по Ruby 45

Строки
Строка — это последовательность букв, цифр и других символов. В Ruby
есть несколько способов создания строки, но, пожалуй, простейший из них —
непосредственно написать ее, заключив в кавычки (годятся и двойные, и оди-
нарные). Тут у нас цитата из "Уолдена" Генри Торо:
thoreau = "If a man does not keep pace with his companions, perhaps it is
because he hears a different drummer."

Можно получить доступ к строке thoreau и обработать ее с помощью мето-


дов класса String. Например, можно извлечь часть строки с помощью метода
[], указав диапазон. Давайте возьмем символы с 37 по 46:
thoreau[37..46] # => "companions"

Или, начиная с конца строки и используя отрицательные числа, возьмем сим-


волы со второго от конца по восьмой:
thoreau[-8..-2] # => "drummer"

Можно выполнить итерацию над всеми символами строки с помощью блока,


который "перемалывает" каждый байт (8-битовую последовательность) стро-
ки в коде ASCII и генерирует символ (с помощью метода chr), и отделить
каждый символ косой чертой:
thoreau.each_byte do |c|
print c.chr, "/"
end
# => I/f/ /a/ /m/a/n/ /d/o/e/s/ /n/o/t/ /k/e/e/p/ /p/a/c/e/ /w/i/t/h/
/h/i/s/ /c/o/m/ p/a/n/i/o/n/s/,/ /p/e/r/h/a/p/s/ /i/t/ /i/s/
/b/e/c/a/u/s/e/ /h/e/ /h/e/a/r/s/ /a/ / d/i/f/f/e/r/e/n/t/
/d/r/u/m/m/e/r/./

ЗАМЕЧАНИЕ
Если вы в своей программе хотите использовать что-нибудь еще кроме
символов ASCII, вам следует прочесть это замечание; в противном
случае, эта информация вам, возможно, не нужна. Должен признать,
что полагать, будто символ синонимичен байту, по крайней мере, ста-
ромодно. В более широком смысле, в мире, основанном на Unicode,
символы могут быть представлены более чем одним байтом. На-
пример, кодировка символов UTF-8 представляет символы длиной от
одного до четырех байтов. По умолчанию, Ruby использует кодировку
символов ASCII, но вы можете сменить ее, установив (в начале про-
граммы) значение переменной $KCODE равным "u" (для UTF-8), "e"
(для EUC), "s" (для SJIS) и "a" или "n" (для ASCII или NONE).
46 Глава 2

Кстати, метод chr преобразует код символа (произведенный с помощью


each_byte) в фактический символ. Вам следует знать также и об обратном
методе — операторе ?, который по символу определяет его код. Я продемон-
стрирую это с помощью irb:
irb(main):001:0> ?I
=> 73
irb(main):002:0> ?f
=> 102
irb(main):003:0> ?\ # вы его не можете видеть, но это пробел
=> 32
irb(main):004:0> ?m
=> 109
irb(main):005:0> ?a
=> 97
irb(main):006:0> ?n
=> 110

Я не хочу здесь больше вдаваться в подробности относительно строк, вы уз-


наете достаточно много о них в главе 4.

Регулярные выражения
Регулярное выражение — это специальная последовательность символов,
которая сопоставляется со строками или множеством строк. Регулярные вы-
ражения часто применяются для поиска образца в строке, с тем чтобы вы
могли сделать что-то еще с этой строкой или выполнить какие-то другие опе-
рации. Регулярные выражения также служат для извлечения строки или под-
строки (части строки) и применения ее в другом месте.
Регулярные выражения используют элементы (один или несколько симво-
лов), чтобы проинструктировать механизм регулярных выражений, как ис-
кать заданную строку. Комбинация специальных символов, заключенная ме-
жду двумя косыми чертами (//), составляет шаблон регулярного выражения.
Вот некоторые примеры таких элементов:
 ^ — сопоставляется с началом строки;
 $ — сопоставляется с концом строки;
 \w — сопоставляется с символом слова;
 [...] — сопоставляется с любым символом в квадратных скобках;
 [^...] — сопоставляется с любым символом не в квадратных скобках;
Обзорная экскурсия по Ruby 47

 * — сопоставляется с нулевым вхождением или несколькими вхожде-


ниями предшествующего регулярного выражения;
 + — сопоставляется с одним или несколькими вхождениями предшест-
вующего регулярного выражения;
 ? — сопоставляется с нулевым или единичным вхождением предшест-
вующего регулярного выражения.
Вот пример регулярного выражения, применяемого для сопоставления стро-
ки при помощи метода scan класса String.
hamlet = "The slings and arrows of outrageous fortune"
hamlet.scan(/\w+/) # => ["The", "slings", "and", "arrows",
# "of", "outrageous", "fortune"]

Это регулярное выражение выполняет сопоставление с одним или несколь-


кими (+) символами слова (\w) и помещает все соответствия в массив.
Я расскажу более подробно о регулярных выражениях в главе 4. Там вы най-
дете таблицу всех шаблонов регулярных выражений, распознаваемых Ruby.

Числа и операторы
Почти в любом объектно-ориентированном языке программирования числа
считаются фундаментальными элементарными объектами, называемыми
примитивами. Они не связаны напрямую ни с каким классом; они просто
есть. Но не так обстоят дела в Ruby: даже числа здесь являются экземпляра-
ми класса.
Например, число 1001, положительное целое, представляет собой экземпляр
класса Fixnum, дочернего класса для класса Integer, который является до-
черним классом класса Numeric. Число 1001.0, значение с плавающей точ-
кой, представляет экземпляр класса Float, который также является дочерним
классом класса Numeric. (На рис. 5.1 показана связь между этими двумя клас-
сами.)
Числа сопровождаются операциями над этими числами. Например, числа
можно сложить, вычесть, разделить, умножить, возвести число в степень
(взять экспоненту) и вернуть остаток от деления (выполнить деление по
модулю). Это лишь некоторые из операций.
В Ruby лучше всего знакомиться с математическими операциями с помощью
irb. Попробуйте сделать это в irb:
irb(main):001:0> 3 + 4 # сложение
=> 7
48 Глава 2

irb(main):002:0> 7 - 3 # вычитание
=> 4
irb(main):003:0> 3 * 4 # умножение
=> 12
irb(main):004:0> 12 / 4 # деление
=> 3
irb(main):005:0> 12**2 # возведение в степень (экспонента)
=> 144
irb(main):006:0> 12 % 7 # деление по модулю (остаток от деления)
=> 5

Вот несколько операторов присваивания языка Ruby в действии:


irb(main):007:0> x = 12 # присваивание
=> 12
irb(rnain):008:0> x += 1 # сокращенное присваивание со сложением
=> 13
irb(main):009:0> x -= 1 # сокращенное присваивание с вычитанием
=> 12
irb(main):010:0> x *= 2 # сокращенное присваивание с умножением
=> 24
irb(main):011:0> x /= 2 # сокращенное присваивание с делением
=> 12

В Ruby также имеется модуль Math, который включает математические


функции всех видов (в форме методов класса), такие как квадратный корень,
косинус, тангенс и так далее. Вот пример вызова метода sqrt из модуля Math:
irb(main):012:0> Math.sqrt(16)
=> 4.0

Ruby предоставляет несколько особых математических классов, таких как


Rational для операций с дробями. О числах и операторах вы узнаете намного
больше из главы 5. В табл. 5.1 представлены все математические операторы
Ruby, а также указано старшинство операций.

Условные операторы
Как в любом языке программирования, в Ruby имеются условные операторы,
в которых проверяется, является ли условие истинным или ложным. Затем,
в зависимости от ответа, выполняется блок кода. Вот на скорую руку пример-
Обзорная экскурсия по Ruby 49

чик с оператором if, в котором проверяется, имеет ли переменная нулевое зна-


чение:
value = 0

if value.zero? then
puts "value is zero. Did you guess that one?"
end

Метод zero? возвращает true (истина), если значение value равно нулю, что
и произошло, поэтому выполнился следующий оператор (или любые другие
операторы в блоке кода if/end). По принятому для Ruby соглашению, любой
метод в Ruby, за которым идет вопросительный знак, возвращает булево зна-
чение, true или false. Это соглашение, однако, никому не навязывается.
Другие условные операторы представляют собой знакомые case и while
и менее знакомые until и unless. Все условные операторы, какие только
можно найти в Ruby, описаны в главе 3.

Массивы и хэши
Массив — это упорядоченная последовательность индексированных значе-
ний, причем индекс в ней начинается с нуля. Это одна из самых общеприня-
тых структур данных в теории вычислительных систем. Вот как массив вы-
глядит в Ruby:
pacific = ["Washington", "Oregon", "California"]

Массив называется pacific. Он содержит три строки — имена трех штатов


на западном побережье США. Эти строки являются элементами массива.
Конечно, элементы массива могут иметь любой допустимый в Ruby тип, а не
только строковый. Здесь приведен только один способ определения массива.
Как вы увидите в главе 6, сделать это можно многими другими способами.
Если бы вы захотели получить доступ к одному из этих элементов, то могли
бы сделать это, задав с помощью метода его индекс. Например, чтобы полу-
чить доступ к первому элементу, индекс которого 0, вы могли бы воспользо-
ваться методом [].
pacific[0] # => "Washington"

Вызов этого метода извлекает значение элемента 0, Washington. Все о масси-


вах в Ruby вы узнаете из главы 6.
Хэш — это таблица ключей к значениям. Это тоже очень распространенная
структура данных. В отличие от массива, в котором элементы индексируются
50 Глава 2

положительными целыми числами, хэши предоставляют вам право выбрать,


как вы будете индексировать значения ключом. Это делается вот так:
pacific = {"WA" => "Washington", "OR" => "Oregon", "CA" => "California"}

Определение хэша заключено в фигурные скобки, тогда как массив опреде-


ляется в квадратных скобках. К тому же, каждое значение связывается (=>)
с ключом. Один из способов получения доступа к значениям в хэше — по их
ключам. Чтобы получить доступ в хэше к значению Oregon, вы могли бы
воспользоваться методом [] класса Hash.
pacific["OR"] # => "Oregon"

Применение ключа OR возвращает значение Oregon. Ключи и значения могут


быть любого типа, не только строкового. Более подробно хэши рассмотрены
в главе 7.

Методы
Методы обеспечивают средства сбора кода (операторов и выражений) в од-
ном месте, так чтобы воспользоваться им было легко и, при необходимости,
многократно. Вы можете определять методы для выполнения любого рода
вещей. В действительности, большая часть математических операторов в Ruby
является методами.

ЗАМЕЧАНИЕ
Это самое активное обсуждение методов, какое только можно найти
в книге, так что, вполне вероятно, вам захочется позднее вернуться
обратно в этот раздел.

Вот несложное описание метода с именем hello, созданное с помощью клю-


чевых слов def и end:
def hello
puts "Hello, Matz!"
end

hello # => Hello, Matz!

Метод hello просто выводит строку при помощи puts. Обратная сторона за-
ключается в том, что с помощью undef можно сделать метод неопределенным.
undef hello # делает неопределенным метод с именем hello

hello # попытаюсь вызвать этот метод теперь


Обзорная экскурсия по Ruby 51

NameError: undefined local variable or method 'hello' for main:Object


(Ошибка именования: неопределенная локальная переменная или метод 'hello'
в main:Object)
from (irb):11
from :0

Можно также определять методы, у которых есть параметры, как показано


здесь, в методе repeat:
def repeat( word, times )
puts word * times
end

repeat("Hello! ", 3) # => Hello! Hello! Hello!


repeat "Good-bye! ", 4 # => Good-bye! Good-bye! Good-bye! Good-bye!

У метода repeat имеются два параметра — word и times. Вы можете вы-


звать метод, указав параметры в круглых скобках или без скобок. Вы даже
можете определять параметры метода без круглых скобок, но я обычно так
не делаю.
Поскольку ставить круглые скобки вы не обязаны, то при использовании ме-
тодов операций, таких как +, можно получить математическое уравнение
в обыкновенном виде. Каждая нижеприведенная строка фактически является
допустимым вызовом метода + класса Fixnum:
10 + 2 # => 12
10.+ 2 # => 12
(10).+(2) # => 12

Возвращаемые значения
У методов есть возвращаемые значения. В других языках вы можете явно
доставить возвращаемое значение при помощи оператора return. В Ruby
возвращается последнее значение метода с явно заданным оператором return
или без него. В этом своеобразие языка Ruby. Вот как проделать это в irb:
1. Прежде всего, определите метод matz, который просто содержит строку:
irb(main):001:0> def matz
irb(main):002:1> "Hello, Matz!"
irb(main):003:1> end
=> nil

2. Вызвав метод matz, посмотрите на результат его работы. Он доступен


в irb, но не виден, если выполнять программу в командном процессоре.
52 Глава 2

Чтобы действительно увидеть выходные данные, используйте метод вме-


сте с puts:
irb(main):004:0> matz
=> "Hello, Matz!"
irb(main):005:0> puts matz
Hello, Matz!
=> nil

3. Теперь присвойте метод matz переменной output и выведите output при


помощи puts:
irb(main):006:0> output = matz
=> "Hello, Matz!"
irb(main):007:0> puts output
Hello, Matz!
=> nil

4. Если хотите, можете явно использовать оператор return. Перепишите


matz, добавив на этот раз оператор return, и вы получите тот же самый
результат:
irb(main):008:0> def matz
irb(main):009:1> return "Hello, Matz!"
irb(main):010:1> end
=> nil
irb(main):011:0> matz
=> "Hello, Matz!"
irb(main):012:0> puts matz
Hello, Matz!
=> nil
irb(main):013:0> output = matz
=> "Hello, Matz!"
irb(main):014:0> puts output
Hello, Matz!
=> nil

Соглашение о присвоении имен методам


В Ruby имеются соглашения о последнем символе в именах методов — со-
глашения, которые широко используются, но языком не навязываются.
Обзорная экскурсия по Ruby 53

Если имя метода заканчивается знаком вопроса (?), как в eql?, то метод воз-
вращает булево значение — true или false. Например:
x = 1.0
y = 1.0
x.eql? y # => true

Если имя метода заканчивается восклицательным знаком (!), как в delete!,


то это указывает на то, что метод является "разрушительным", т. е. он произ-
водит изменения по месту нахождения объекта, а не его копии. Он изменяет
сам объект. Обратите внимание на разницу в результате выполнения методов
delete и delete! в классе String:
der_mensch = "Matz!" # => "Matz!"
der_mensch.delete( "!" ) # => "Matz"
puts der_mensch # => Matz!
der_mensch.delete!( "!" ) # => "Matz"
puts der_mensch # => Matz

Если имя метода заканчивается знаком равенства (=), как в family_name=, то


это метод-"setter" ("сеттер"), т. е. такой, который осуществляет присваивание
или устанавливает переменную, такую как переменная экземпляра класса
в классе:
class Name
def family_name=( family )
@family_name = family
end
def given_name=( given )
@given_name = given
end
end

n = Name.new
n.family_name= "Matsumoto" # => "Matsumoto"
n.given_name= "Yukihiro" # => "Yukihiro"
p n # => <Name:0x1d441c @family_name="Matsumoto",
# @given_name="Yukihiro">

В Ruby существует более удобный способ создавать методы сеттеры/геттеры


или аксессоры. Чтобы узнать, как это сделать, см. главу 9.
54 Глава 2

Параметры по умолчанию
Метод repeat, показанный ранее, имеет два параметра. Вы можете присвоить
этим параметрам значения по умолчанию при помощи знака равенства, за
которым следует значение. Когда метод вызывается без параметров, значения
по умолчанию выбираются автоматически.
Переопределите repeat со значениями по умолчанию: Hello для word и 3 для
times. Затем вызовите его без параметров и с параметрами.
def repeat( word="Hello! ", times=3 )
puts word * times
end

repeat # => Hello! Hello! Hello!


repeat( "Goodbye! ", 4 ) # => Goodbye! Goodbye! Goodbye! Goodbye!

Когда вы вызываете repeat без параметров, для них используются значения


по умолчанию; но если вы вызываете repeat с параметрами, то значения по
умолчанию отбрасываются и замещаются значениями параметров.

Переменное число параметров


Иногда заранее не известно, сколько параметров будет у метода. К этому
можно приспособиться, т. к. в Ruby можно передать методу переменное чис-
ло параметров, если у параметра задать префикс в виде звездочки (*). Про-
стая программка, которая делает это, показана в примере 2.2.

Пример 2.2. num_args.rb

def num_args( *args )


length = args.size
label = length == 1 ? " argument" : " arguments"
num = length.to_s + label + " ( " + args.inspect + " )"
num
end

puts num_args
puts num_args(1)
puts num_args( 100, 2.5, "three" )

В этой программе для определения того, будет ли существительное argument


иметь единственное или множественное число, используется трехместный
Обзорная экскурсия по Ruby 55

оператор (?:). (С трехместным оператором вы познакомитесь ближе в сле-


дующей главе.)
Когда такой синтаксис используется для переменного числа параметров, па-
раметры сохраняются в массиве, как показывает метод inspect. Трем вызо-
вам метода num_args предшествуют puts, чтобы можно было увидеть воз-
вращаемые методом значения при стандартном выводе результатов.
0 arguments ( [] )
1 argument ( [1] )
3 arguments ( [100, 2.5, "three"] )

Переменные параметры можно устанавливать наряду с обычными парамет-


рами. Секрет состоит в том, чтобы список переменных параметров (тот, что
начинается с символа *) всегда шел в конце списка параметров. В примере
2.3 показан метод с двумя обычными параметрами и местом для большего
числа параметров.

Пример 2.3. two_plus.rb

def two_plus( one, two, *args )


length = args.size
label = length == 1 ? " variable argument" : " variable arguments"
num = length.to_s + label + "(" + args.inspect + ")"
num
end
puts two_plus( 1, 2 )
puts two_plus( 1000, 3.5, 14.3 )
puts two_plus( 100, 2.5, "three", 70, 14.3 )

Вот результаты (показано только, сколько получено переменных параметров;


обычные параметры игнорируются):
0 variable arguments ([])
1 variable argument ([14.3])
3 variable arguments (["three", 70, 14.3])

Попробуйте вызвать two_plus вообще без параметров и посмотрите, какой


ответ придет от интерпретатора.

Псевдонимы методов
В Ruby есть ключевое слово alias, которое создает альтернативные имена
методов — псевдонимы. Назначение псевдонима означает, что вы, в сущности,
56 Глава 2

создаете копию метода с новым именем метода, несмотря на то, что оба вы-
зова методов будут указывать на один и тот же объект. Применение alias
(или метода alias_method из Module) дает возможность получить доступ
к методам, которые были заменены.
В приведенном далее примере в irb показано, как создать альтернативное имя
для метода greet:
irb(main):001:0> def greet
irb(main):002:1> puts "Hello, baby!"
irb(main):003:1> end
=> nil
irb(main):004:0> alias baby greet # для greet альтернативное имя baby
=> nil
irb(main):005:0> greet # вызов метода
Hello, baby!
=> nil
irb(main):006:0> baby # вызов по альтернативному имени
Hello, baby!
=> nil
irb(main):007:0> greet.object_id # каков идентификатор объекта?
Hello, baby!
=> 4
irb(main):008:0> baby.object_id # указывает на тот же самый объект
Hello, baby!
=> 4

Блоки
Блок в Ruby больше, чем просто блок или группа операторов. В определен-
ном контексте блок имеет особое значение. Такой тип блока, как вы увидите,
всегда вызывается в соединении с методом. В сущности, на него ссылаются
как на безымянную функцию.
Блок в Ruby часто (но не всегда) является идиоматическим выражением для
извлечения всех значений из структуры данных путем выполнения итераций
над этой структурой. Он что-то вроде "дай мне все, что у тебя там есть, по
одной штуке за раз". Я продемонстрирую вам обычное использование блока.
Помните массив pacific? Вот он снова:
pacific = [ "Washington", "Oregon", "California" ]
Обзорная экскурсия по Ruby 57

Можно вызвать блок для pacific, чтобы извлечь все его элементы, по одно-
му за раз, с помощью метода each. Вот один из способов сделать это:
pacific.each do |element|
puts element
end

Имя между двумя символами || (|element|) может быть любым именем по


вашему выбору. Блок использует его как локальную переменную для сохра-
нения пути к каждому элементу в массиве и дальнейших манипуляций этим
элементом. В этом блоке для распечатки каждого элемента массива исполь-
зуется puts:
Washington
Oregon
California

Можно заменить do/end парой фигурных скобок, как это обычно и делают,
чтобы получить более компактную запись (между прочим, фактически, фи-
гурные скобки имеют более высокий приоритет, чем do/end):
pacific.each { |e | puts e }

Метод each есть в десятках классов, таких как Array, Hash и String. Но пусть
у вас не возникнет неправильное представление. Выполнение итераций над
структурами данных — не единственный способ применения блоков. По-
звольте привести вам простой пример использования yield, ключевого слова
языка Ruby.

Оператор yield
Прежде всего, определим крошечный метод gimme, в котором нет ничего,
кроме оператора yield:
def gimme
yield
end

Чтобы узнать, что делает yield, вызовите gimme в одиночестве и посмотрите,


что произойдет:
gimme
LocalJumpError: no block given
(Ошибка локального перехода: не задан блок)
from (irb):11:in `gimme'
from (irb):13
from :0
58 Глава 2

Вы получили здесь ошибку, потому что работа yield состоит в том, чтобы
выполнять блок кода, связанный с методом. В вызове gimme таковой отсутст-
вовал. Этой ошибки можно избежать, воспользовавшись методом
block_given? из модуля Kernel. Переопределите gimme, добавив оператор if:
def gimme
if block_given?
yield
else
puts "I'm blockless!"
end
end

Оператор if — это условный оператор. Если в вызове метода задан блок, то


block_given? возвратит true и yield выполнит блок, в противном случае,
если блок не задан, выполнится код после else.
Попробуйте еще раз с блоком и без.
gimme { print "Say hi to the people." } # => Say hi to the people.
gimme # => I'm blockless!

Если снабдить gimme блоком, то он достанет код из этого блока, напечатав


строку "Say hi to the people."; а если нет, gimme выдаст строку "I'm blockless!".
Из спортивного интереса, переопределите метод gimme, чтобы он содержал
два оператора yield, затем вызовите его с блоком. Он выполнит блок дважды.
def gimme
if block_given?
yield
yield
else
puts "I'm blockless!"
end
end

gimme { print "Say hi again. " } # => Say hi again. Say hi again.

Еще одна вещь, которую вы должны знать. После выполнения yield управ-
ление передается оператору, непосредственно следующему за yield. Чтобы
проиллюстрировать это, давайте переопределим gimme еще раз.
def gimme
if block_given?
yield
Обзорная экскурсия по Ruby 59

else
puts "Oops. No block."
end
puts "You're welcome." # выполняется сразу после yield
end

gimme { print "Thank you. " } # => Thank you. You're welcome.

Я уверен, что с помощью этой малой толики кода вы узнали, насколько гиб-
кими могут быть блоки. В своем воображении я вижу, как небольшое грибо-
образное облако вырастает над вашей головой под воздействием идей ис-
пользования блоков.
Но для полного понимания того, на что способны блоки, вам необходимо уз-
нать кое-что о procs ("проках").

БЛОКИ — ЭТО ЗАМЫКАНИЯ


Знаете ли вы, что такое замыкание? Если да, то я поражен — должно быть,
вы изучали его как специалист по теории вычислительных систем (computer
science major). Если вы не знаете, что это, но вас разбирает любопытство, чи-
тайте дальше. Замыкание — это безымянная функция или метод. Это как ме-
тод в методе, который ссылается на переменные или использует их совместно
с объемлющим или внешним методом. В Ruby замыкание или блок обрамляют-
ся фигурными скобками ({}) или скобками do/end и их выполнение зависит от
связанного с ними метода (такого как each).

Процедурные объекты (procs)


В Ruby позволительно сохранять процедуры — или "проки" (procs), как их
называют — в виде объектов, в комплекте вместе со своим контекстом. Вы
можете сделать это несколькими способами. Один из них состоит в вызове
метода new для класса Proc; другой заключается в вызове методов lambda или
proc из Kernel. (Кстати, вызов lambda или proc предпочтительнее по сравне-
нию с Proc.new, потому что lambda и proc выполняют проверку параметров.)
В примере 2.4 продемонстрировано, как создать процедурный объект обоими
способами.

Пример 2.4. proc.rb

#!/usr/bin/env ruby

count = Proc.new { [1,2,3,4,5].each do |i| print i end; puts }


60 Глава 2

your_proc = lambda { puts "Lurch: 'You rang?'" }


my_proc = proc { puts "Morticia: 'Who was at the door, Lurch?'" }

# Какой тип объектов вы только что создали?


puts count.class, your_proc.class, my_proc.class

# Вызов всех "проков"


count.call
your_proc.call
my_proc. call

Программа, после того как даст вам знать, что каждый из созданных вами
объектов является объектом класса Proc, выполнит следующий вывод, вы-
звав каждую процедуру с помощью метода call:
12345
Lurch: 'You rang?'
Morticia: 'Who was at the door, Lurch?'

Метод может быть вызван с блоком, и он вернет результат выполнения бло-


ка, даже если у метода нет параметров. Запомните, блок всегда должен быть
связан с вызовом метода.
Вы можете даже уговорить метод на лету преобразовать связанный с ним
блок в proc. Для этого необходимо создать для метода параметр, которому
предшествует амперсанд (&). Я проведу вас через это в примере 2.5.

Пример 2.5. return_block_proc.rb

#! /usr/local/bin/ruby

def return_block
yield
end

def return_proc( &proc )


yield
end

return_block { puts "Got block!" }


return_proc { puts "Got block, convert to proc!" }
Обзорная экскурсия по Ruby 61

Вот результат:
Got block!
Got block, convert to proc!

У метода return_block нет параметров. Все, что у него есть, — это оператор
yield внутри его тела. Задача оператора yield, напомню еще раз, состоит
в выполнении блока, когда блок передан методу. Старый добрый метод мо-
жет стать безумно разносторонним.
У следующего метода, return_proc, есть один параметр, $proc. Если у мето-
да есть параметр, имя которого начинается с амперсанда, он примет блок —
если тот представлен — и преобразует его в объект класса Proc. С yield
в теле метод выполняет блок cum proc (блок с "прок"), и ему не приходится
заботиться о методе call из Proc.

Символы
В Ruby есть специальный объект под названием символ (symbol). Все, что
вам действительно необходимо знать о них на данный момент, — это то, что
они являются "заполнителями" для идентификаторов и строк. Вы всегда може-
те распознать их по предшествующему двоеточию (:).
Невозможно непосредственно создать символ, присвоив ему значение. Он соз-
дается при помощи вызова для строки методов to_sym или intern или посред-
ством присвоения одного символа другому символу. Чтобы лучше уяснить
это, отправим строку по замкнутому маршруту: из строки в символ и обратно
в строку.
name = "Matz"
name.to_sym # => :Matz
:Matz.id2name # => "Matz"
name == :Matz.id2name # => true

Ваши ладошки вспотели? Я знаю, символ умеет сбивать с толку. Это нечто
абстрактное, потому что вы действительно не видите, что происходит под
колпаком интерпретатора Ruby. На поверхности же содержимое строки name
магическим образом трансформировалось в метку символа. Ну и что?
"А то", когда символ создан, во время выполнения программы в памяти
хранится только одна его копия. То есть Ruby, вместо того чтобы делать
копию за копией, хранит ссылку на адрес единственной ячейки памяти.
Программы на языке Ruby очень экономны и не поглощают память в боль-
ших количествах.
62 Глава 2

В Ruby on Rails используется множество символов, и вполне вероятно, что


когда вы узнаете их лучше, тоже будете применять. Внутри Ruby использу-
ются тонны символов. Для доказательства выполните эту строку кода:
Symbol.all_symbols

И вы увидите их более 1000 штук!

ЗАМЕЧАНИЕ
Если вы опытны в программировании на языках Java или C#, вам
поможет такая аналогия: символы в Ruby подобны внешним (interned)
строкам, содержащимся во внешнем строковом пуле (string intern pool).

Обработка исключений
Подобно языкам Java, C++ и др., в Ruby предлагается обработка исключений.
Исключительная ситуация возникает, когда программа совершает трансгрес-
сию (правонарушение), и нормальный ход этой программы прерывается.
Ruby подготовлен к таким ситуациям, но вы можете управлять ими по-
своему, при помощи обработки исключений.
В Java и C++ есть блоки try; в Ruby вам точно так же следует воспользовать-
ся блоком begin. В Java и C++ применяется оператор catch, в то время как
в Ruby есть оператор rescue. Там, где в Java служит finally, Ruby предпо-
читает ensure.
Вы узнаете о том, как выполнять обработку исключений, в главе 10.

Документация по языку Ruby


Когда я говорю "Документация по языку Ruby", то главным образом
имею в виду документацию, сгенерированную при помощи RDoc
(http://rdoc.sourceforge.net), программы, которая извлекает документацию
из исходных файлов Ruby, написанных на С и Ruby.
В исходных файлах документация хранится в комментариях и закодирована
так, что RDoc легко может найти ее. Например, знаки равенства (такие как
===) на левой границе выделяют заголовок, а текст с отступами отформати-
рован как код. RDoc может генерировать результаты в виде файлов HTML,
XML, ri (Ruby information — информация о Ruby) или файлов справки
Windows (chm).
Для просмотра сгенерированной с помощью RDoc документации по Ruby
в формате HTML отправляйтесь на страницу http://www. ruby-doc.org/core.
Обзорная экскурсия по Ruby 63

Если документация по Ruby уже установлена в вашей системе, что весьма


вероятно, если вы следовали инструкциям по установке в главе 1, то можете
набрать в командной строке приведенную далее инструкцию и получить
в ответ отформатированную документацию. Наберите:
ri Kernel.print

и получите результат, который выглядит вот так:


------------------------------------------------------------ Kernel#print
print(obj, ...) => nil
-------------------------------------------------------------------------
Prints each object in turn to +$stdout+. If the output field separa-
tor (+$,+) is not +nil+, its contents will appear between each
field. If the output record separator (+$\+) is not +nil+, it will
be appended to the output. If no arguments are given, prints +$_+.
Objects that aren't strings will be converted by calling their
+to_s+ method.
(Печатает каждый объект поочередно в +$stdout+. Если разделитель вы-
водимых полей (+$,+) не +nil+, его содержимое появится между полями.
Если разделитель выводимых записей (+$\+) не +nil+, то он будет до-
бавлен к выводу. Если параметры не заданы, печатается +$_+. Объекты,
которые не являются строками, будут преобразованы при помощи вызова
для них метода +to_s+ .)

print "cat", [1,2,3], 99, "\n"


$, = ","
$\ = "\n"
print "cat", [1,2,3], 99

_produces:_
(выводит:)

cat12399
cat, 1, 2, 3, 99

В главе 10 вы найдете учебное пособие по созданию документации с помо-


щью RDoc.

Вопросы для самопроверки


1. В чем состоит одно из основных отличий между классом и модулем?
2. Какой модуль включает класс Object?
3. Какой синтаксис используется для создания блока комментариев?
64 Глава 2

4. С какого специального символа начинается переменная экземпляра? Пе-


ременная класса? Глобальная переменная?
5. Какое основное свойство отличает константу?
6. Когда имя метода заканчивается знаком вопроса (?), что это по договоренно-
сти означает?
7. Блок — это вид безымянного _________________.
8. Что такое proc?
9. Какова наиболее важная характеристика символа?
10. Что такое RDoc?
Глава 3

Любовь к условным операторам

Многие из управляющих структур языка Ruby, такие как if и while, давно


стали разменной монетой, привычной для программистов, в то время как
другие, например, unless и until, не так известны. Считайте управляющие
структуры, в которых содержатся условные операторы, тестами на детекторе
лжи. Каждый раз, когда вы применяете управляющую структуру с условным
оператором, вы спрашиваете: это — истинно или ложно? Когда получен же-
лаемый ответ — true или false, в зависимости от того, как вы разработали
программу — выполняется соответствующий блок кода.

ЗАМЕЧАНИЕ
Две связанные друг с другом структуры rescue и ensure, которые
служат для обработки исключений, здесь не рассматриваются. Они
обсуждаются в главе 10.

В этой главе представлены управляющие структуры Ruby, и как обычно,


с множеством примеров. Начнем с оператора if — самой тривиальной струк-
туры, которую можно найти в любом языке программирования.

Оператор if
Давайте начнем с самого простого и усложнять будем постепенно.
if 1 == 1 then
print "True!"
end

Если правда, что 1 равно (==) 1, а так оно и есть, то оператор if возвра-
щает true, что приводит к выполнению блока кода, состоящего из одного
66 Глава 3

оператора print. (Кстати, этот оператор if можно было бы записать на од-


ной строке.)
Теперь создайте переменную и сравните ее с числом. Если переменная и число
равны, выполните код.
x = 256
if x == 256
puts "x equals 256"
end
# => x equals 256

Обратите внимание на то, что мы выбросили ключевое слово then из опера-


тора if. Нет необходимости использовать его в этом примере. Кроме того,
необязательно использовать end, если записать весь код на одной строке:
x = 256
if x == 256 then puts "x equals 256" end

В действительности, вы можете изменить порядок вещей, поместив if после


puts и отбросив then и end.
x = 256
puts "x equals 256" if x == 256

Когда вы вот так меняете порядок, if становится модификатором оператора.


Как вы увидите позже, такое можно проделать и с другими управляющими
структурами.
Другой способ компоновки оператора if состоит в замещении then двоето-
чием (:), вот так:
x = 256
if x == 256: puts "x equals 256" end

Потренируйтесь немного с этим кодом. Измените x таким образом, чтобы


при проверке в if не возвращалось значение true. Поменяйте текст, который
выводит оператор. Поместите что-либо другое в блок. Продолжайте до тех
пор, пока не вложите в код всю душу.
Теперь я покажу вам несколько других операторов для тестирования истин-
ности или ложности выражения или совокупности выражений. В этом при-
мере оператор && означает "и".
ruby = "nifty"
programming = "fun"

if ruby == "nifty" && programming == "fun"


Любовь к условным операторам 67

puts "Keep programming!"


end
# => Keep programming!

Другими словами, код в блоке выполняется, если истинны оба выражения.


С помощью && можно задать проверку нескольких выражений:
if a == 10 && b == 27 && с == 43 && d == -14
print sum = a + b + c + d
end

Сумма будет напечатана, если все эти выражения истинны. Можно вместо &&
поставить ключевое слово and.
if ruby = "nifty" and programming == "fun" and weather == "nice"
puts "Stop programming and go outside for a break!"
end

Еще один вариант — оператор ||; синонимом для этого оператора явля-
ется or. Когда вы используете || или or, код выполняется, если хотя бы одно
из выражений возвращает true:
if ruby == "nifty" or programming == "fun"
puts "Keep programming!"
end

Строка "Keep programming!" будет напечатана, если хотя бы одно из двух


выражений истинно. А больше двух выражений можно? Ну, конечно:
if a == 10 || b == 27 || с = 43 || d = -14
print sum = a + b + c + d
end

|| и or, && и and называются логическими операторами. В Ruby доступно


также множество других операторов, таких как:
delete_record if record != 0x8ff # не равно

if amt > 1.00 then desc = "dollars" end # больше чем

desc = "cents" if amt < 1.00 # меньше чем

if height >= 6 then print "L or XL" end # больше или равен (не меньше)

print "shrimpy" if weight <= 100 # меньше или равен (не больше)
68 Глава 3

Еще два логических оператора меняют значение проверки. Это ! и not.


if !queue then print "The queue is empty." End

Здесь сказано, что если queue не равно true, то значение оператора вычисля-
ется как истинное, и оператор print печатает "The queue is empty!". Альтер-
нативой для ! является ключевое слово not.
if not queue then print "The queue is empty." end

Использование else и elsif


При программировании, время от времени, вы расставляете признаки, пове-
левающие программе выполнить задание. Обычно признак просто несет зна-
чение, true или false. Предположим, что у вашей программы есть признаки
queue и pr. Если признак равен true, то выполняется код в блоке; если он
равен false, то блок игнорируется.
if queue
pr = true
else
pr = false
end

start_printer if pr # starts if pr is true

Ключевое слово else открывает для if аварийный люк. Другими словами,


если оператор if не вычисляет значение true, будет выполняться код после
else, а если if не вычисляет false, то код после else игнорируется.
Для pr или queue мне не пришлось использовать логические операторы, т. к.
они сами принимали значения или true или false, и это готовый ответ, кото-
рый необходим интерпретатору Ruby от if, чтобы начать действовать.

ЗАМЕЧАНИЕ
Вокруг слов true или false нет кавычек, потому что они не являются
строками. Фактически, true — единственный экземпляр класса
TrueClass. Его дополнение, false, является единственным экземп-
ляром класса FalseClass. Еще true и false считаются псевдопе-
ременными, которые выглядят, как переменные, а ведут себя, как
константы, и которым не могут быть присвоены значения.

Ключевое слово elsif обеспечивает вас после начального if одним или не-
сколькими промежуточными вариантами, в которых можно протестировать
различные операторы (выражения).
Любовь к условным операторам 69

ЗАМЕЧАНИЕ
Обратите внимание, в elsif только одна буква e, не две. Мои пальцы
все время забывают об этом, и я оказываюсь в отладочном режиме.

В представленном далее операторе if содержится несколько операторов


elsif;они будут выяснять при помощи символов, какой в настоящее время
используется язык: английский (:en), испанский (:es), французский (:fr)
или немецкий (:de), чтобы решить, как представить слово "собака":
lang = :es
if lang == :en
print "dog"
elsif lang == :es
print "perro"
elsif lang == :fr
print "chien"
elsif lang == :de
print "Hund"
else
puts "No language set; default = 'dog'."
end
# "perro" is assigned to dog

Вы можете записать этот оператор немного плотнее, поставив после знаков


двоеточие:
if lang == :en: print "dog"
elsif lang == :es: print "perro"
elsif lang == :fr: print "chien"
elsif lang == :de: print "Hund"
else puts "No language set; default = 'dog'."
end

СОВЕТ
Не ставьте после else (последнего оператора) двоеточие.

Трехместный оператор
Трехместный оператор (?:) или оператор с основанием три — это сжатая
структура, проникшая в Ruby из С. В языке С он назывался условным выра-
жением. Условное выражение разбито на три части.
70 Глава 3

Вот пример чего-то полезного, что можно проделать с трехместным оператором:


label = length == 1 ? " argument" : " arguments"

Здесь label на основе значения length присваивается строковое значение.


Если значение length равно 1, то label будет присвоено строковое значение
argument (единственное число); но если это не так, т. е. если значение length
иное, чем 1, то значением label станет строка arguments (множественное
число).
Если разобраться, трехместный оператор оказывается отличным средством
кратко выразить логику на одной строке.

Оператор case
Оператор case языка Ruby также обеспечивает способ выразить логические
условия в лаконичной форме. Он подобен операторам elsif с двоеточиями,
но вместо if вы пишете case, а вместо elsif — when.
Вот пример, подобный тому, что вы видели раньше, использующий lang
с символами :en, :es, :fr и :de:
lang = :fr
dog = case lang
when :en "dog"
when :es : "perro"
when :fr : "chien"
when :de : "Hund"
else "dog"
end
# "chien" присвоено переменной dog

case/when гораздо короче, чем if/elsif/else, т. к. по его логике == подразу-


мевается — и вам не приходится все время набирать == или имя переменной.
Оператор case языка Ruby подобен оператору switch, знакомой по С конст-
рукции, но case — более мощный. Для меня досадным обстоятельством, ка-
сающимся switch, в C, C++ и Java является невозможность переключиться
непосредственно на строки (несмотря на то, что это можно сделать в C#).
Если бы в переменной lang вместо символов содержалась бы строка, то ваш
код выглядел бы так:
lang = "de"

dog = case lang


Любовь к условным операторам 71

when "en": "dog"


when "es": "perro"
when "fr": "chien"
when "de": "Hund"
else "dog"
end
# Переменной dog присвоено "Hund"

В следующем примере для проверки значений используется несколько


диапазонов. Диапазон — это диапазон чисел.
scale = 8
case scale
when 0: puts "lowest"
when 1..3: puts "medium-low"
when 4..5: puts "medium"
when 6..7: puts "medium-high"
when 8..9: puts "high"
when 10: puts "highest"
else puts "off scale"
end
# => high

Диапазон 1..3 означает диапазон чисел от 1 до 3, включительно. Так как


значение scale равно 8, scale соответствует диапазону 8..9 и case возвра-
щает строку "high". Но когда вы используете три точки, как в диапазоне
1...5, конечное значение 5 исключается. Совокупности точек, .. и ...,
называются операторами диапазона; две точки включают все числа диапа-
зона, а три точки исключают последнее число из диапазона. Негласно case
использует оператор === из Range, который проверяет, является ли значение
членом диапазона.

Цикл while
Цикл while выполняет содержащийся в нем код до тех пор, пока условие ос-
тается истинным. Приведенный далее фрагмент кода задает начальное значе-
ние счетчика равным 0 и создает массив breeds, содержащий четыре элемента
с названиями пород лошадей. Он также создает временный массив с именем
temp. (О массивах вы узнаете в главе 6.)
Несколько следующих абзацев до некоторой степени относятся к фундамен-
тальным знаниям и предназначены для начинающих программистов. Но если
72 Глава 3

за душой у вас большая практика программирования, просто перейдите к са-


мому коду.
Цикл while выполняется до тех пор, пока условие (i < breeds.size) истин-
но. Переменная i начинает свою коротенькую жизнь, равной 0, а размер или
длина массива breeds равна 4.
В конце цикла i увеличивается на 1, и затем управление возвращается в на-
чало цикла. При первом прохождении цикла i равно 0, и этот 0, как пара-
метр, подставляется в breeds[i], что приводит к выбору первого элемен-
та массива (называемого нулевым) — строкового значения quarter. Этот
элемент добавляется посредством << в конец массива temp. Метод
capitalize из класса String изменяет quarter на Quarter. Здесь к i при по-
мощи оператора += добавляется 1, так что i становится равным 1. И цикл вы-
полняется снова, с самого начала.
Процесс продолжается до тех пор, пока i не станет равно 4, вследствие чего
проверка условия для while завершается неудачно. Интерпретатор с языка
Ruby перемещается к следующему допустимому оператору, т. е. temp.sort!,
который сортирует новый массив по алфавиту. Он не делает копию, а изме-
няет массив по месту. Вы узнаете об этом по "солдатику" ! в конце имени
метода (sort!). Затем содержимое temp замещает содержимое breeds, и мас-
сив приведен в порядок.
i = 0
breeds = [ "quarter", "arabian", "appalosa", "paint" ]
puts breeds.size # => 4
temp = []

while i < breeds.size do


temp << breeds[i].capitalize
i +=1
end

temp.sort! # => ["Appalosa", "Arabian", "Paint", "Quarter"]


breeds.replace( temp )
p breeds # => ["Appalosa", "Arabian", "Paint", "Quarter"]

Кстати, do здесь необязательно, такая форма цикла тоже легальна:


while i < breeds.size
temp << breeds[i].capitalize
i +=1
end
Любовь к условным операторам 73

Еще одна форма, которую можно применить, включает begin/end:


temp =98.3

begin
print "Your temperature is " + temp.to_s + " Fahrenheit. "
puts "I think you're okay."
temp += 0.1
end while temp < 98.6

puts "Your temperature is " + temp.to_s + " Fahrenheit. Are you okay?"

Когда вы используете while таким образом (while в конце), операторы


в цикле выполняются один раз до того, как проверяется условие. Это как
в цикле do/while в языке C.
Кроме того, как и для if, можно применять while в качестве модификатора
оператора, в конце оператора:
cash = 100_000.00
sum = 0
cash += 1.00, sum while cash < 1_000_000.00
# символы подчеркивания игнорируются

Так что cash просто продолжает расти, пока не сравняется с $1 000 000.00.
Вот бы мне так!

Да что ты говоришь!
Можно вырваться из цикла while с помощью ключевого слова break.
Например, скажем, вы организовали цикл, как раньше, но хотите остановить
обработку, когда дойдете до определенного элемента в массиве. Чтобы сбе-
жать оттуда, воспользуйтесь break:
while i < breeds.size
temp " breeds[i].capitalize
break if temp[i] == "Arabian"
i +=1
end
p => temp # => ["Quarter", "Arabian"]

Когда модификатор if, следующий за break, отыщет "Arabian" в массиве


temp, произойдет выход из цикла. Следующий оператор (который называется
метод p) показывает, что мы не продвинулись слишком далеко, добавляя
элементы в конец массива temp.
74 Глава 3

Операторы unless и until


Операторы unless и until подобны if и while, за исключением того, что они
выполняются до тех пор, пока условия в них равны false, в то время как
операторы if и while выполняются, пока условия равны true. Конечно, if
и while используются гораздо чаще, чем unless и until, но приятно, что
Ruby предлагает большие выразительные возможности.
И в самом деле, оператор unless подобен инвертированному оператору if.
Сначала возьмем оператор if:
if lang == "de"
dog = "Hund"
else
dog = "dog"
end

Теперь я переведу его в unless:


unless lang == "de"
dog = "dog"
else
dog = "Hund"
end

В сущности, в этом примере говорится, что пока значение lang не равно de,
переменной dog будет присваиваться значение "dog"; в противном случае dog
будет присвоено значение "Hund".
Видите, как операторы поменялись местами? В операторе if присвоение
"Hund" переменной dog идет первым; в примере с unless первым идет при-
своение "dog" переменной dog.
Как в случае с if, можно применять unless в качестве модификатора опера-
тора:
puts age += 1 unless age > 29

Собственно, как unless является инвертированной формой if, так и until


является инвертированной формой while. Сравните следующие операторы.
Первым идет цикл while:
weight = 150
while weight < 200 do
puts "Weight: " + weight.to_s
weight += 5
end
Любовь к условным операторам 75

А вот та же логика, выраженная при помощи until:


weight = 150
until weight == 200 do
puts "Weight: " + weight.to_s
weight += 5
end

И для while, и для until есть другая форма — с begin/end:


weight = 150
begin
puts "Weight: " + weight.to_s
weight += 5
end until weight == 200

В этой форме операторы в цикле вычисляются один раз до проверки условий.


И, наконец, и while, и until могут служить модификаторами оператора:
puts age += 1 until age > 28

Метод loop
Метод loop происходит из модуля Kernel. Он позволяет выполнять цикл не-
прерывно, — как for(;;) в С — пока вы или программа не сделаете что-
нибудь, чтобы вырваться из него.
Выполните код из примера 3.1.

Пример 3.1. loop.rb

loop do
print "Type something: "
line = gets
break if line =~ /q|Q/
puts line
end

Вы увидите подсказку "Type something:". Метод gets (также из Kernel) из-


влечет то, что вы набрали, и это будет присвоено переменной line. Однако
если line соответствует q или Q, вы покинете цикл здесь и сейчас; в против-
ном случае puts выведет содержимое line на стандартное устройство выво-
да. Когда повстречается end, управление будет возвращено в начало цикла.
76 Глава 3

Цикл for
Цикл for — знакомая структура для опытных программистов. В этом приме-
ре в for для распечатки списка чисел от 1 до 5 используется диапазон (1..5).
for i in 1..5 do
print i, " "
end
# => 1 2 3 4 5

Обратите внимание на do и end. Вы можете выбросить do. Он не обязателен,


но вы должны сохранить end:
for i in 1..5
print i, " "
end
# => 1 2 3 4 5

Если вы захотите записать цикл for на одной строке, вам придется вставить
do обратно:
for i in 1..5 do print i, " " end # => 1 2 3 4 5

Вот пример цикла for, в котором печатается таблица умножения (от 1 до 12)
для числа 2:
for i in 1..12
print "2 x" + i.to_s + " = ", i * 2, "\n"
end
# =>
2 x 1 = 2
2 x 2 = 4
2 x 3 = 6
2 x 4 = 8
2 x 5 = 10
2 x 6 = 12
2 x 7 = 14
2 x 8 = 16
2 x 9 = 18
2 x 10 = 20
2 x 11 = 22
2 x 12 = 24
Любовь к условным операторам 77

С вложенными циклами for вы легко сможете напечатать всю таблицу ум-


ножения от 1 до 12:
for i in 1..12
for j in 1..12
print i.to_s + " x " + j.to_s + " = ", j * i, "\n"
end
end

Вот только часть результатов:


1 x 1 = 1
1 x 2 = 2
1 x 3 = 3
1 x 4 = 4
1 x 5 = 5
1 x 6 = 6
1 x 7 = 7
1 x 8 = 8
1 x 9 = 9
1 x 10 = 10
1 x 11 = 11
1 x 12 = 12
2 x 1 = 2
2 x 2 = 4
2 x 3 = 6

И т. д.
Все это прекрасно, но у for есть конкуренты в лице методов times, upto
и downto.

Метод times
Метод times (из Integer) удобен и лаконичен. Сравните с циклом for:
for i in 0..9
print i, " "
end
# => 0 1 2 3 4 5 6 7 8 9

Этот вызов times:


10.times { |i| print i, " " } # => 0 1 2 3 4 5 6 7 8 9
78 Глава 3

Оба фрагмента кода производят один и тот же результат. Метод times, как
вы можете видеть, использует блок, и он немного проще для набора. Он при-
меняется широко, и он в стиле Ruby — классный, наглядный, лаконичный.
Сможете догадаться, какую форму предпочитаю я?

Метод upto
Метод upto — удобный метод, который делает те же самые вещи, что цикл
for, но записывается короче. В классах Integer, String и Date имеются ме-
тоды upto, но здесь я покажу только Integer-версию (String-версию вы уви-
дите в главе 4).
Например, имеется цикл for, в котором печатается список чисел:
for i in 1..10
print i, " "
end
# => 1 2 3 4 5 6 7 8 9 10

Сравните его с upto, который делает в точности то же самое:


1.upto(10) { |i| print i, " " } # => 1 2 3 4 5 6 7 8 9 10

Метод upto для своего волшебства применяет блок. Цикл for к вашим услу-
гам, но я предпочитаю upto. Просто он немного быстрее.
Вот другой пример upto, который печатает таблицу умножения на 2:
1.upto(12) { |i| print "2 x " + i.to_s + " = ", i * 2, "\n"}
# =>
2 x 1 = 2
2 x 2 = 4
2 x 3 = 6
2 x 4 = 8
2 x 5 = 10
2 x 6 = 12
2 x 7 = 14
2 x 8 = 16
2 x 9 = 18
2 x 10 = 20
2 x 11 = 22
2 x 12 = 24
Любовь к условным операторам 79

Накропать это было нетрудно. А что если вы хотите сделать всю таблицу ум-
ножения от 1 до 12? Попробуйте это:
1.upto(12) { |i| 1.upto(12) { |j| print i.to_s + " x " + j.to_s +
" = ", j * i, "\n"} }

Здесь вы видите вложенную пару upto. На мой вкус upto немного короче,
чем for.

Метод downto
Метод downto похож на upto, но отсчет идет в обратном направлении.
И в классе Integer, и в Date есть методы downto, но я покажу вам Integer-
версию (в классе String метода downto нет). Подобно upto, этот метод ис-
пользует блок:
5.downto(1) { |i| print i, " " } # => 5 4 3 2 1

Программа timer.rb, показанная в примере 3.2, содержит метод, который на-


зывается timer. Параметр к этому методу задает количество минут, которые
вы хотите отсчитать.

Пример 3.2. timer.rb

def timer( start )


puts "Minutes: " + start.to_s
start_time = Time.now
puts start_time.strftime("Start_to_time: %I:%M:%S %p")
start.downto(1) { |i| sleep 60 }
end_time = Time.now
print end_time.strftime ("Elapsed time: %I:%M:%S %p")
end

timer 10

Метод timer применяет в блоках метода downto метод sleep из Kernel. Класс
Time — это один из встроенных в Ruby классов. Метод now из Time берет момен-
тальный снимок текущего времени, а метод strftime возвращает строку, отфор-
матированную с помощью форматирующих директив: %I — для часов, %M — для
минут и %S — для секунд. (Вы сможете найти полный список форматирующих
директив для Time в табл. П1.13.) Вот результат работы этой программы:
Minutes: 10
Start to_time: 09:40:00 AM
Elapsed time: 09:50:00 AM
80 Глава 3

Выполнение кода до или после программы


В заключение я хочу упомянуть две других управляющих структуры, BEGIN
и END. Эти структуры дают возможность выполнить код до и после выполне-
ния программы. И за BEGIN, и за END следуют блоки, заключенные в фигур-
ные скобки ({}), как в примере 3.3.

Пример 3.3. bmi.rb

BEGIN { puts "Date and time: " + Time.now.to_s }

def bmi( weight, height )


703.0*(weight.to_f/(height.to_f**2))
End

my_bmi = bmi( 196, 73 )


puts "Your BMI is: " + x = sprintf( "%0.2f", my_bmi )
END { puts "You've got some work ahead of you." }
(Вам предстоит поработать)

Вопросы для самопроверки


1. Почему case/when более удобны, чем if/elsif/else?
2. Что такое трехместный оператор?
3. Что такое модификатор оператора?
4. Почему upto или downto более удобны, чем обычный цикл for?
5. Оператор unless является инвертированной формой другой управляющей
структуры. Какой?
6. Какие синонимы у && и || ?
7. Какая управляющая структура является, вероятно, самой тривиальной
управляющей структурой, применяемой в Ruby и других языках?
8. В чем преимущество использования begin/end в операторе while?
Глава 4

Строки

Попросту говоря, строка в языках программирования — это последователь-


ность из одного или нескольких символов, обычно представленная на каком-
то естественном языке. Вы, вероятнее всего, будете использовать методы из
класса String. Манипулирование строками — обычная рутина, с которой
приходится иметь дело программисту. К счастью, Ruby предоставляет в этой
области массу благоприятных возможностей.
За более подробной информацией о строковых методах отправляйтесь на
страницу сайта http://www.ruby-doc.org/core/classes/String.html. Получить
сведения о методе можно в командной строке. Например, чтобы узнать о ме-
тоде экземпляра chop из класса String, наберите:
ri String#chop

или
ri String.chop

Между именами класса и метода можно набрать # или точку (.). Само собой
разумеется, что у вас установлен пакет документации по языку Ruby и к нему
указан путь (см. разд. "Установка Ruby" главы 1).

Создаем строки
Можно создавать строки с помощью метода new. Например, в этой строке
создается новая, пустая строка, названная title:
title = String.new # => ""

Теперь у вас есть новая строка, но она наполнена только "виртуальным" воз-
духом. Можно проверить строку, не пустая ли она, с помощью метода empty?:
title.empty? # => true
82 Глава 4

Вы, вероятно, захотите убедиться, что строка не пустая, до того, как возьме-
тесь обрабатывать ее, или вам понадобится завершить процесс обработки,
когда очередь дойдет до пустой строки. Можно также проверить длину стро-
ки или ее размер:
title.length

или
title.size # => 0

Методы length и size выполняют одну и ту же вещь: они оба возвращают


целое число, показывающее, сколько символов содержит строка.
Метод new может принимать строковый параметр:
title = String.new( "Much Ado about Nothing" )

Теперь проверьте title:


title.empty? # => false
title.length # => 22

Ну вот, пожалуйста. Строка не так бессодержательна, как прежде.


Другое средство создания строки — метод String из модуля Kernel:
title = String( "Much Ado about Nothing" )
puts title # => Much Ado about Nothing

Но есть еще более простой способ. Для генерации новой строки не нужны
методы new или String. Прекрасно подойдут оператор присваивания и пара
двойных кавычек:
sad_love_story = "Romeo and Juliet"

Можно воспользоваться также одинарными кавычками:


sad_love_story = 'Romeo and Juliet'

Разница между двойными и одинарными кавычками состоит в том, что двой-


ные кавычки интерпретируют символы escape-последовательности, а оди-
нарные кавычки сохраняют их. Я покажу вам, что это означает. Вот то, что
вы получите с двойными кавычками (интерпретируют \n как newline — но-
вую строку):
lear = "King Lear\nA Tragedy\nby William Shakespeare"
puts lear # => King Lear
# A Tragedy
# by William Shakespeare
Строки 83

А вот то, что вы получите с одинарными кавычками (сохраняют \n в контексте):


lear = 'King Lear\nA Tragedy\nby William Shakespeare'
puts lear # => King Lear\nA Tragedy\nby William Shakespeare

Полный список символов escape-последовательности см. в табл. П1.3.

Строки с общими ограничителями


Еще одно средство создания строки — это общие ограничители, которым
предшествует символ %. Строка вкладывается между парой символов-
ограничителей, таких как !, { или [ (они не должны быть буквенно-
цифровыми). Во всех приведенных далее примерах ограничение производит-
ся различными символами (можно ставить даже кавычки):
comedy = %!As You Like It!
history = %[Henry V]
tragedy = %(Julius Ceasar)

%Q является эквивалентом строки в двойных кавычках; %q эквивалентно стро-


ке в одинарных кавычках; а %x используется для строки в обратных кавычках
(`) при выводе команды.

Документ "здесь и сейчас"


Документ "здесь и сейчас" (here document) позволит вам компоновать одну
строку (string) из нескольких набираемых на ходу строк текста (lines), сохра-
няя при этом разделители строк. Документ "здесь и сейчас" формируется при
помощи метода << и ограничивающего символа или ограничивающей строки
по вашему выбору. Я сохранил 29-й сонет Шекспира как документ "здесь и
сейчас", с ограничителем 29:
sonnet = <<29
When in disgrace with fortune and men's eyes
I all alone beweep my outcast state,
And trouble deaf heaven with my bootless cries,
And look upon myself, and curse my fate,
Wishing me like to one more rich in hope,
Featured like him, like him with friends possessed,
Desiring this man's art, and that man's scope,
With what I most enjoy contented least;
Yet in these thoughts my self almost despising,
Haply I think on thee, and then my state,
84 Глава 4

Like to the lark at break of day arising


From sullen earth, sings hymns at heaven's gate;
For thy sweet love remembered such wealth brings
That then I scorn to change my state with kings.
29

Этот документ сохранен в строке sonnet, но можно создать документ "здесь


и сейчас" и не помещать его в строку. Где бы ни оборвалась набранная стро-
ка текста, туда будет помещен разделитель (такой как \n). Теперь наберите:
puts sonnet

Сами увидите, где будут разорваны строки.


Можно также "ограничить ограничитель" для получения разнообразных эф-
фектов:
sonnet = <<hamlet # то же самое, что строка в двойных кавычках
0 my prophetic soul! My uncle!
hamlet

sonnet = <<"hamlet" # снова, как строка в двойных кавычках


0 my prophetic soul! My uncle!
hamlet

sonnet = <<'ghost' # то же самое, что строка в одинарных кавычках


Pity me not, but lend thy serious hearing
To what I shall unfold.
ghost

my_dir = <<`dir` # то же, что в обратных кавычках


ls -l
dir

ind = <<-hello # для введения отступа


Hello, Matz!
hello

Конкатенация строк
В Ruby можно дополнить существующую строку, применяя различные спо-
собы конкатенации. С Ruby вам не придется скакать через обруч, как при-
шлось бы, если бы вы писали на языке с неизменными строками.
Строки 85

Соседние строки могут быть сцеплены просто потому, что они стоят рядом
друг с другом:
"Hello, " " " "Matz" "!" # => "Hello, Matz!"

Можно также воспользоваться методом +:


"Hello," + " " + "Matz" + "!" # => "Hello, Matz!"

Вы можете даже смешивать двойные и одинарные кавычки, пока они долж-


ным образом составляют пару.
Еще один способ состоит в применении метода <<. Можно добавить единст-
венную строку:
"Hello, " << "Matz!" # => Hello, Matz!

Или соединить строки вместе, несколько раз вызвав <<:


"Hello," << " " << "Matz" << " ! " # => Hello, Matz!

Альтернативой << является метод concat (который, однако, не позволяет


формировать цепочку):
"Hello, ".concat "Matz!"

Или можно записать это вот так:


h = "Hello, "
m = "Matz!"
h.concat(m)

Можно сделать строку неизменной при помощи метода freeze из класса


Object:
greet = "Hello, Matz!"
greet.freeze

# попробуйте добавить что-нибудь в конец строки


greet.concat("!") # => TypeError: can't modify frozen string
(Ошибка типа: невозможно модифицировать замороженную строку)

# объект заморожен?
greet.frozen? # => true

Получаем доступ к строкам


Можно извлекать сегменты строки и обрабатывать их с помощью метода []
из класса String. Это псевдоним метода slice: в любом месте, где вы ис-
86 Глава 4

пользуете [], вы можете использовать slice, с теми же самыми параметрами.


slice! выполняет изменения по месту и является эквивалентом []=.
В приведенных далее примерах показано, как получить доступ к строкам:
line = "A horse! a horse! my kingdom for a horse!"
cite = "Act V, Scene IV"
speaker = "King Richard III"

Если ввести к методу [] строку в качестве параметра, то он вернет эту стро-


ку, если, конечно, найдет:
speaker['King'] # => "King"

В противном случае он вернет nil — другими словами, он попытается сооб-


щить вам: "Я не нашел строку, которую вы искали". Если определить объект
из Fixnum (целое) в качестве индекса, метод вернет десятичный код символа,
найденного в месте, на которое указывает индекс:
line[7] # => 33

В месте по индексу 7 метод [] нашел символ 33 (!). Если вы добавите метод


chr (из класса Integer), то получите и сам символ:
line[7].chr # => "!"

Можно задать смещение и длину (два объекта из Fixnums), чтобы сообщить


методу [] позицию, с которой вы хотите начать, и сколько символов вы хо-
тите извлечь:
line[18, 23] # => "my kingdom for a horse!"

Вы начинаете с позиции 18, на которую указывает индекс, и затем выбираете


23 символа, включительно. Если хотите, можно записать результат с заглав-
ной буквы с помощью метода capitalize:
line[18, 23].capitalize # => "My kingdom for a horse!"

(Подробности о capitalize и других аналогичных методах будут сообщены


далее в этой главе.)
Введите диапазон, чтобы ухватить диапазон символов. Две точки (..) озна-
чают, что надо включать последний символ:
cite[0..4] # => "Act V"

Три точки (...) означают, что последнее значение надо исключить:


cite[0...4] # => "Act "

Можно также воспользоваться регулярными выражениями (см. конец главы),


как показано здесь:
line[/horse!$/] # => "horse!"
Строки 87

Регулярное выражение /horse!$/ задает вопрос: "Находится ли слово horse,


за которым стоит восклицательный знак (!) в конце строки ( $)?" Если это
так, то возвращается horse!; и nil, в противном случае. При добавлении
другого параметра метод ввернет порцию соответствующих данных, начи-
ная с 0, как в этом примере:
linе[/^А horse/, 0] # => "A horse"

Метод index возвращает индекс, который указывает на положение соответ-


ствующей подстроки. То есть если вы используете индекс таким образом:
line.index("k") # => 21

то 21 укажет индекс места, на котором буква k встречается в строке.


Если разобрались, посмотрите, что происходит в следующих примерах:
line[line.index("k")] # => 107
line[line.index("k")].chr # => "k"

Если вам понятны эти операторы, то вы начинаете схватывать суть! Это не


заняло много времени, не так ли? А если вы не поняли, что произошло, то вот
вам мое объяснение: когда был вызван line.index("k"), он вернул значе-
ние 21, которое было подано в качестве числового параметра методу []; по
существу, это был вызов line[21].

Сравниваем строки
Время от времени вам необходимо протестировать две строки, чтобы по-
смотреть, одинаковые они или нет. Можно проделать это с помощью ==.
Например, вы хотели бы проверить строку перед тем, как напечатать что-то:
print "What was the question again?" if question == ""

Итак, имеются две версии первого предложения Геттисбергского посла-


ния (Gettysburg Address) Авраама Линкольна, одна из так называемого
"Hay manuscript", другая из "Nicolay" (см. http://www.loc.gov/exhibits/gadd/
gadrft.html):
hay = "Four score and seven years ago our fathers brought forth, upon
this continent, a new nation, conceived in Liberty, and dedicated to the
proposition that all men are created equal."
nicolay = "Four score and seven years ago our fathers brought forth,
upon this continent, a new nation, conceived in liberty, and dedicated
to the proposition that \"all men are created equal\"
("Восемь десятков и семь лет минуло с того дня, как отцы наши создали на
этой земле новую нацию, основанную на идеалах Свободы и свято верящую,
что все люди созданы равными.")
88 Глава 4

Строки только немного отличаются друг от друга (например, в версии


"Hay..." Liberty написано с прописной буквы). Давайте сравним эти строки:
hay == nicolay # => false

Результат равен false, потому что иначе должно было быть полное совпаде-
ние. (Оставим историкам выяснять, насколько они соответствуют друг дру-
гу.) Можно также приложить метод eql? и получить тот же самый результат,
несмотря на то, что eql? и == слегка различны:
 == возвращает true, если равны два объекта String, и false в противном
случае.
 eql? возвращает true, если две строки равны по длине и содержимому,
и false в противоположном случае.
Здесь eql? возвращает false:
hay.eql? nicolay # => false

Еще одно средство сравнения строк — это метод <=>, обычно его называют
spaceship operator (оператор "космический челнок"). Он сравнивает значения
кодов символов строки, и возвращает –1 (меньше), 0 (равны) или 1 (больше),
в зависимости от результата сравнения, которое производится с учетом реги-
стра клавиатуры:
"a" <=> "a" # => 0
"a" <=> 97.chr # => 0
"a" <=> "b" # => -1
"a" <=> "`" # => 1

Сравнение без учета заглавных и строчных букв возможно при помощи ме-
тода casecmp, который дает те же самые варианты результатов, что и "косми-
ческий челнок" <=> (–1, 0, 1), но не заботится о регистре:
"a" <=> "A" # => 1
"a".casecmp "A" # => 0
"ferlin husky".casecmp "Ferlin Husky" # => 0
"Ferlin Husky".casecmp "Lefty Frizzell" # => -1

Обрабатываем строки
Вот забавная штука, с которой можно начать. Метод * повторяет строку с
помощью целого множителя:
"A horse! " * 2 # => "A horse! A horse! "
Строки 89

Можно также прицепить строку к результату:


taf= "That's ".downcase * 3 + "all folks!"
# => "that's that's that's all folks!"
taf.capitalize # => "That's that's that's all folks!"

Вставляем строку в строку


Метод insert позволяет вставить одну строку по указанному индексу
в другую. Например, вы можете подправить орфографию:
"Be carful.".insert 6, "e" # => "Be careful."

или добавить слово (плюс пробел):


"Be careful!".insert 3, "very " # => "Be very careful!"

и даже добавить метод *, чтобы просто показать, что вы это можете:


"Be careful!".insert 3, "very " * 3 # => "Be very very very careful!"

Заменяем всю строку или ее часть


При помощи метода []= можно видоизменить всю строку или ее часть, по
месту. (Подобно методу [], который представляет собой эквивалент slice,
метод []= является альтернативным именем для slice!, так что, где бы вы
ни использовали []=, вы можете указывать slice!, с теми же самыми пара-
метрами.)
Даны следующие строки (какой-то плут отредактировал текст нашего Шек-
спира):
line = "A Porsche! a Porsche! my kingdom for a Porsche!"
cite = "Act V, Scene V"
speaker = "King Richard, 2007"

Введите строку как параметр к методу []=, и он, если найдет ее, вернет но-
вую, откорректированную строку; и nil в противном случае.
speaker[", 2007"]= "III" # => "III"
p speaker # => "King Richard III"

Уже лучше.
Если вы определите Fixnum (целое) в качестве индекса, метод вернет строку
с корректировкой, которую вы поместили по указанному индексу. (Длины
строк Ruby подгоняет автоматически, если замещающая строка имеет длину,
отличную от оригинала.)
cite[13]= "IV" # => "IV"
p cite # => "Act V, Scene IV"
90 Глава 4

По индексу 13 метод []= нашел подстроку "V" и заменил ее на "IV".


Можно указать смещение и длину (два Fixnum), чтобы сообщить методу []=
позицию в строке, с которой вы хотите начать, и количество символов, кото-
рое вы хотите извлечь:
line[39,8]= "Porsche 911 Turbo!" # => "Porsche 911 Turbo!"
p line # => "A Porsche! a Porsche! my kingdom for a Porsche 911 Turbo!"

Вы начинаете с индекса 39 и отсюда убираете 8 символов (включительно).


Можно также ввести диапазон, чтобы указать диапазон символов, кото-
рый вы хотите заменить. Включите последний символ с помощью двух
точек ( ..):
speaker[l3..l5]= "the Third" # => "the Third"
p speaker # => "King Richard the Third"

Можно воспользоваться регулярными выражениями (см. разд. "Регулярные


выражения" далее в этой главе), как показано здесь:
line[/Porsche!$/]= "Targa!" # => "Targa!"
p line # => "A Porsche! a Porsche! my kingdom for a Targa!"

Регулярное выражение /Porsche!$/ проверяет, есть ли Porsche! в конце


строки ($). Если это правда, то вызов метода []= заменяет "Porsche!" на
"Targa!".

Методы chomp и chop


Метод chop (или chop!) отсекает от строки последний символ, а метод
chomp (chomp!) отсекает разделитель записей ( $/) — обычно просто символ
перевода строки (newline). Рассмотрим строку joe, лимерик, созданный
как документ "здесь и сейчас":
joe = <<limerick
There once was a fellow named Joe
quite fond of Edgar Allen Рое
He read with delight
Nearly half the night
When his wife said "Get up!" he said "No."
limerick # => "There once was a fellow named Joe\nquite fond of Edgar
# Allen Poe\n He read with delight\n Nearly half the night\nWhen his
# wife said \"Get up!\" he said \"No.\"\n"
Строки 91

Применим метод chomp!, чтобы удалить последний разделитель записей (\n):


joe.chomp! # => "There once was a fellow named Joe\nquite fond of
# Edgar Allen Poe\n He read with delight\n Nearly half the
# night\nWhen his wife said \"Get up!\" he said \"No.\""

Теперь применим его снова, и chomp! вернет nil без изменения строки, по-
тому что в конце строки больше нет разделителя записей:
joe.chomp! # => nil

chop, прожорливый близнец chomp'а, не проявляет милосердия к строке,


с азартом удаляя последний символ (кавычку):
joe.chop! = "There once was a fellow named Joe\nquite fond of Edgar
# Allen Poe\n He read with delight\n Nearly half the night\nWhen his
# wife said \"Get up!\" he said \

Метод delete
С помощью delete или delete! можно удалить символы из строки:
"That's call folks!".delete "c" # => "That's all folks"

Выглядит просто, потому что в эту строку входит только одна буква с, а зна-
чит, вы не видите интересных побочных эффектов, которые обязательно бу-
дут в следующем примере. Предположим, вы хотите избавиться от лишнего l
в alll:
"That's alll folks".delete "l" # => "That's a foks"

О-о. Он избавил меня от всех l. Я не могу использовать delete так, как хочу.
Как же мне привести в порядок alll? Что если я использую два l вместо
одного?
"That's alll folks".delete "ll" # => "That's a foks"

Я получил тот же результат. (Я знал, что так будет.) Это из-за того, что
delete использует пересечение (а оно одинаково в обоих случаях) своих па-
раметров, чтобы решить, какую часть строки удалить. Хорошо хоть можно
отвергнуть весь параметр или его часть с помощью знака вставки (^), кото-
рый применяется аналогичным образом в регулярных выражениях:
"That's all folks".delete "abcdefghijklmnopqrstuvwxyz", "^ha"
# => "haa"

Знак вставки отвергает оба символа в параметре, а не только первый (можно


написать "^h^а" и получить тот же самый результат).
92 Глава 4

Заменяем подстроку
Попробуйте gsub (или gsub!). Этот метод замещает подстроку (первый па-
раметр) замещающей строкой (второй параметр):
"That's alll folks".gsub "alll", "all" # => "That's all folks"

Или вы могли бы сделать это так:


"That's alll folks".gsub "lll", "ll" # => "That's all folks"

Метод replace замещает строку оптом. Не просто подстроку, а всю целиком.


call = "All hands on deck!"
call.replace "All feet on deck!" # => "All feet on deck!"

Но почему бы не проделать это таким способом?


call = "All hands on deck!"
call = "All feet on deck!"

Разве вы не получили тот же самый результат? Не совсем тот. Когда вы ис-


пользуете метод replace, call остается тем же самым объектом, с тем же
самым идентификатором, а когда вы дважды присваиваете call строку, объ-
ект и его идентификатор меняются. Просто тонкость, о которой вы должны
знать.
# тот же самый объект
call = "All hands on deck!" # => "All hands on deck!"
call.object_id # => 1624370
call.replace "All feet on deck!" # => "All feet on deck!"
call.object_id # => 1624370

# другой объект
call = "All hands on deck!" # => "All hands on deck!"
call.object_id # => 1600420
call = "All feet on deck!" # => "All feet on deck!"
call.objected # => 1009410

Переверни их
Реверсирование символов означает такое их изменение, которое соответству-
ет чтению в противоположном направлении. Вы можете проделать это при
помощи метода reverse (или reverse!, если предпочитаете стойкие по-
вреждения). Скажем, вы хотите перевернуть латинский алфавит:
"abcdefghijklmnopqrstuvwxyz".reverse # => "zyxwvutsrqponmlkjihgfedcba"
Строки 93

Или, возможно, вы любите палиндромы:


palindrome = "dennis sinned"
palindrome.reverse! # => "dennis sinned"
p palindrome

Ущерб невелик. Даже несмотря на то, что reverse! изменил строку по месту.
Подумайте немного об этом.

От строки к массиву
Метод split без труда преобразует строку в массив. Первый вызов split
обойдется без параметров:
"0123456789".split # => ["0123456789"]

Это было просто, а как насчет разложения на отдельные значения и преобра-


зования их в элементы? Сделаем это при помощи регулярного выражения
(//), которое "нашинкует" первоначальную строку на объединение символов.
"0123456789".split (//) # => ["0", "1", "2", "3", "4", "5",
# "6", "7", "8", "9"]

В следующем примере регулярное выражение разглядит запятую и пробел


(/, /):
c_w = "George Jones, Conway Twitty, Lefty Frizzell, Ferlin Husky"
# => "George Jones, Conway Twitty, Lefty Frizzell, Ferlin Husky"
c_w.split(/, /)
# => ["George Jones", "Conway Twitty", "Lefty Frizzell", "Ferlin Husky"]

Преобразуем регистр клавиатуры


В слове, предложении или фразе можно преобразовать первую букву в про-
писную, а остальные в строчные, с помощью capitalize или capitalize!.
(К этому моменту вы уже должны понимать разницу между ними.) Вот пара
предложений, которая находится под влиянием capitalize:
"Ruby finally has a killer app. It's Ruby on Rails.".capitalize
# => "Ruby finally has a killer app. it's ruby on rails."

Обратите внимание на то, что второе предложение начинается не с пропис-


ной буквы, что не очень-то хорошо. Теперь вы видите, что capitalize
преобразует в заглавную только первую букву в строке, а не начала сле-
дующих друг за другом предложений. Планируйте свои действия в соответ-
ствии с этим.
94 Глава 4

Выполняем итерации в строке


Чтобы добиться желаемого эффекта, вам придется разложить строку. Далее
приведен список пунктов меню, сохраненный в строке. Их отделяет друг от
друга \n. Метод each (или его синоним each_line) выполняет итерацию над
каждым отдельным пунктом, а не просто над первым словом во всей строке,
и преобразует его первую букву в заглавную:
"new\nopen\nclose\nprint".each { |item| puts item.capitalize } # =>
# New
# Open
# Close
# Print

Кстати, имеется еще один метод — each_byte. Он разбирает строку отдель-


но, байт за байтом, возвращая десятичное значение символа, на который ука-
зывает индекс. Напечатаем каждый символ как десятичное число, отделяя их
при помощи /:
"matz".each_byte { | b | print b, " / " } # => 109/97/116/122/

ЗАМЕЧАНИЕ
В этом примере подразумевается, что символ представляется един-
ственным байтом, что происходит не всегда. Для Ruby набором сим-
волов по умолчанию является ASCII, символ которого может быть
представлен байтом. Однако в UTF-8 представление одного символа
занимает от одного до четырех байтов. Можно изменить набор симво-
лов с ASCII на UTF-8, определив $KCODE='u' в начале программы.

Преобразуем каждое полученное десятичное число в его символьный эквива-


лент методом chr из Integer:
"matz".each_byte { |b| print b.chr, "/" } # => m/a/t/z/

Или будем добавлять результаты в конец массива out:


out =[] # создаем пустой массив
"matz".each_byte { |b| p out << b} # =>
[109]
[109, 97]
[109, 97, 116]
[109, 97, 116, 122]
p out # => [109, 97, 116, 122]

С массивами вы познакомитесь поближе в главе 6.


Строки 95

downcase, upcase и swapcase


ВЫ ЗНАЕТЕ, КАК БЫВАЕТ ДОСАДНО ЧИТАТЬ ЧТО-ЛИБО, НАПИСАННОЕ
ПРОПИСНЫМИ БУКВАМИ! Это мешает чтению. Вот одна причина радо-
ваться, что в Ruby есть методы downcase и downcase!.
"YOU KNOW IT CAN BE ANNOYING TO READ SOMETHING THAT IS IN ALL UPPERCASE
LETTERS!".downcase
# => "you know it can be annoying to read something that is all in upper-
case letters!"

Так-то лучше. Но теперь первая буква тоже оказалась строчной. Полиция


грамматики заинтересуется нами. Приведем все в порядок, добавив для пред-
ложения вызов capitalize.
"YOU KNOW IT CAN BE ANNOYING TO READ SOMETHING THAT IS ALL IN UPPERCASE
LETTERS!".downcase.capitalize
# => "You know it can be annoying to read something that is all in upper-
case letters!"

Хорошо. Правда, пришлось попыхтеть.


А что, если вы хотите идти другим путем и поменять строчные буквы на
прописные? Например, вы хотите привлечь чье-либо внимание, переписав
весь текст предупреждения заглавными буквами. Можете сделать это при
помощи upcase или upcase!.
"warning! keyboard may be hot!".upcase
# => WARNING! KEYBOARD MAY BE HOT!

Возможно, вдруг вы захотите поменять местами прописные буквы и строч-


ные. Используйте swapcase или swapcase!. Например, вы можете сделать
так, чтобы список букв латинского алфавита, который начинался со строч-
ных букв, теперь начинался с прописных:
"aAbBcCdDeEfFgGhHiI".swapcase # => "AaBbCcDdEeFfGgHhIi"

Управляем пробельными символами


Применив приведенные далее методы, вы сможете поместить пробелы (или
другие пробельные символы) слева или справа от строки, отцентрировать
строку с помощью пробелов (или других символов), а также отсечь пробелы.
Прежде всего, создадим строку — название пьесы Шекспира:
title = "Love's Labours Lost"

Какова длина строки? Это может оказаться для вас важным (length и size —
синонимы).
title.size # => 19
96 Глава 4

Длина строки title составляет 19 символов. С этой информацией на буксире


мы можем начать преобразования. Методы ljust и rjust подобьют строку
пробелами или, если указать, другими символами. Строка будет выровнена
по правому краю, и количество пробелов, или других символов, должно быть
больше длины строки. Уловили смысл? Надеюсь, что да. Давайте сделаем
пример или два.
Давайте вызовем эти два метода с параметром (целым числом), который
меньше или равен длине строки.
title.ljust 10 # => "Love's Labours Lost"
title.rjust 19 # => "Love's Labours Lost"

Что произошло? Ничего! И все потому, что параметр должен быть больше
длины строки, чтобы что-нибудь делалось. Добавляемые пробелы рассчиты-
ваются на основе длины строки и значения параметра. Смотрите:
title.ljust 20 # => "Love's Labours Lost "
title.rjust 25 # => " Love's Labours Lost"

Теперь видите, как оно работает? В вызове ljust справа будет добавлен один
пробел (20 – 19 = 1), а вызов rjust добавит шесть пробелов слева (25 – 19 = 6).
Если кажется, что все должно быть наоборот, просто запомните, что строка
всегда выровнена по правому краю. Все еще в недоумении? Я тоже, но мы бу-
дем продолжать. Если хотите, можете использовать другой символ вместо про-
бела, определенного по умолчанию:
title.rjust( 21, "-" ) # => "--Love's Labours Lost"

или использовать не один символ — последовательность будет повторена:


title.rjust 25, "->" # => "->->->Love's Labours Lost"

OK, теперь давайте действительно заморочим вам голову:


title.rjust(20, "-").ljust(21, "-") # => "-Love's Labours Lost-"

Возможно, когда-нибудь вы и сами захотите проделать что-либо подобное.


Если захочется сдвинуть строку к центру, лучше воспользоваться методом
center:
title.center 23 # => " Love's Labours Lost "
title.center 23, "-" # => "--Love's Labours Lost--"

И еще один совет — я использую center для создания комментария:


filename = "hack.rb" # => "hack.rb"
filename.size # => 7
filename.center 40-7, "#" # => "#############hack.rb#############"
Строки 97

Мы добавляли пробелы и другие символы. Что если вы захотите просто из-


бавиться от них? Используйте lstrip, rstrip и strip (lstrip!, rstrip!
и strip!). Предположим, что у вас есть строка, окруженная с двух сторон
пробелами:
fear = " Fear is the little darkroom where negatives
develope. -– Michael Pritchard "

Опа. Заснул, оставив палец на клавише <Пробел>, — дважды! Сейчас я легко


приведу все в порядок, начав с левой стороны (внесем изменения в первона-
чальную строку при помощи lstrip!):
fear.lstrip! # => "Fear is the little darkroom where negatives
develope. -- Michael Pritchard "
Теперь правая сторона:
fear.rstrip! # => "Fear is the little darkroom where negatives
develope. -- Michael Pritchard"
Или проделаю все это за один раз:
fear.strip! # => "Fear is the little darkroom where negatives
develope. -- Michael Pritchard"
Метод strip удаляет также и другие виды пробельных символов:
"\t\tBye, tabs and line endings!\r\n".strip
# => "Bye, tabs and line endings!"

Выполняем инкремент строки


В Ruby в классе String есть несколько методов, которые позволят вам
произвести последовательные строки, т. е. строки, которые приращива-
ются, начиная с самого правого символа. Вы можете приращивать строки
при помощи next и next! (или succ и succ!). Я предпочитаю использовать
next. (Метод с ! вносит изменения по месту.) Например:
"a".next
или
"a".succ # => "b"
Помните, next приращивает самый правый символ:
"aa".next # => "ab"

Метод добавляет символ, когда достигает границы, или добавляет цифру или
десятичный разряд в подходящих случаях, как показано в этих примерах:
"z".next # => "aa" два a после одного z
"zzzz".next # => "aaaaa" пять a после четырех z
98 Глава 4

"999.0".next # => "999.1" приращение на .1


"999".next # => "1000" приращение от 999 до 1000

Здесь мы говорим не только о буквах, а о любом символе из используемого


набора символов (в этих примерах — из ASCII):
" ".next # => "!"

Объединим в цепочку вызовы next — давайте попробуем три:


"0".next.next.next # => "3"

Как вы видели ранее, next также работает с числами, представленными


в виде строк:
"2007".next # => "2008"

Можно заставить его поработать, когда числа представлены не в виде строк,


правда, этот метод из другого класса, не String. Например:
2008.next # => 2009

В действительности вместо String этот вызов использует метод next из


Integer. (Date, Generator, Integer
и String — во всех этих классах есть ме-
тоды next.)
С next даже можно использовать код символа, через chr:
120.chr # => "x"
120.chr.next # => "y"

Упрощает приращение метод upto из String, в котором указывается блок.


Например, этот вызов upto печатает латинский алфавит:
"a".upto("z") { |i| print i } # => abcdefghijklmnopqrstuvwxyz

Вы могли бы проделать то же самое при помощи цикла for и включающего


диапазона:
for i in "a".."z"
print i
end

Вам решать, что проще. Цикл for требует не намного больше ударов по кла-
вишам (29 против 31, включая пробелы). Но я предпочитаю upto.

Преобразуем строки
Можно преобразовать строку в число с плавающей точкой (Float) или в це-
лое число (Fixnum). Для преобразования строки в число с плавающей точкой,
Строки 99

а точнее, экземпляра класса String в экземпляр класса Float, воспользуйтесь


методом to_f:
"200".class # => String
"200".to_f # => 200.0
"200".to_f.class # => Float

Аналогично, чтобы преобразовать строку в целое число, используйте to_i:


"100".class # => String
"100".to_i # => 100
"100".to_i.class # => Fixnum

Чтобы преобразовать строку в символ (класс Symbol), можно применить ме-


тод to_sym или intern.
"name".intern # => :name
"name".to_sym # => :name

Экземпляром класса Symbol становится значение строки, а не ее имя:


play = "The Merchant of Venice".intern # => :"The Merchant of Venice"

Преобразуем объект в строку при помощи to_s. Ruby вызывает метод to_s из
класса объекта, не из класса String (круглые скобки необязательны).
(256.0).class # => Float
(256.0).to_s # => "256.0"

Регулярные выражения
Вы уже видели регулярные выражения в действии. Регулярное выражение —
это специальная последовательность символов, которая помогает вам устано-
вить соответствие либо найти другие строки или наборы строк при помощи
специализированного синтаксиса, хранящегося в шаблоне. Синтаксис для регу-
лярных выражений был придуман математиком Стивеном Клини (Stephen
Kleene) в 50-х годах прошлого века.
Я потрачу время на демонстрацию некоторых шаблонов, предназначенных
для поиска строк. В этом небольшом обсуждении вы познакомитесь с основ-
ными положениями: как использовать базовые строковые шаблоны, квадрат-
ные скобки, чередование, группирование, привязки, быстрые комбинации,
операторы повторения и фигурные скобки. Синтаксис регулярных выраже-
ний для языка Ruby приведен в табл. 4.1.
Нам нужен небольшой текст для обработки. Вот начальные строки 29-го со-
нета Шекспира:
opening = "When in disgrace with fortune and men's eyes\nI all alone be-
weep my outcast state,\n"
100 Глава 4

Обратите внимание на то, что в этой строке две строки текста, разделенных
символом перевода строки \n. Можно установить соответствие с первой
строкой текста, просто задав слово в шаблоне:
opening.grep(/men/)
# => ["When in disgrace with fortune and men's eyes\n"]

Между прочим, grep — не метод класса String; он происходит из модуля


Enumerable, который входит в класс String, поэтому он доступен для обра-
ботки строк. Метод grep принимает шаблон в качестве параметра и может также
принять блок (см. http://www.ruby-doc.org/core/ classes/Enumerable.html).
Если использовать пару квадратных скобок ([]), то можно искать совпадение
для любого символа из скобок. Давайте попробуем подобрать слово man или
men, применив []:
opening.grep(/m[ae]n/)
# => ["When in disgrace with fortune and men's eyes\n"]

Подойдет также строка со словом man.


Чередование позволит вам искать совпадение для альтернативных форм
шаблона, при помощи символа "вертикальная черта" (|):
opening.grep(/men|man/)
# => ["When in disgrace with fortune and men's eyes\n"]

Группирование использует круглые скобки для группировки подвыражений,


таких как это, в котором содержится чередование:
opening.grep(/m(e|a)n/)
# => ["When in disgrace with fortune and men's eyes\n"]

Привязки привязывают шаблон к началу (^) или концу ($) строки текста:
opening.grep(/^When in/)
# => ["When in disgrace with fortune and men's eyes\n"]
opening.grep(/outcast state,$/)
# => ["I all alone beweep my outcast state,\n"]

^ означает, что совпадение найдено, если текст "When in" находится в начале
строки текста, а с $ совпадение для "outcast state" будет засчитано, если
этот текст будет найден в конце строки текста.
Можно задать начало и окончание строк в шаблоне при помощи быстрых
комбинаций. Синтаксис быстрых комбинаций краток — единственный
символ, которому предшествует обратная косая черта. Например, быст-
рая комбинация \d представляет цифру; то же самое, что [0-9], но короче.
Строки 101

Подобно ^, быстрая комбинация \A соответствует началу строки, но не


строки текста:
opening.grep(/\AWhen in/)
# => ["When in disgrace with fortune and men's eyes\n"]

Подобно $, быстрая комбинация \z соответствует концу строки, но не строки


текста:
opening.grep(/outcast state,\z/)
# => ["I all alone beweep my outcast state,"]

Быстрая комбинация \Z ищет соответствие концу строки перед символом пе-


ревода строки (\n), т. е. подразумевается, что в конце строки находится сим-
вол перевода строки (иначе она не работает).
Давайте сообразим, как задать соответствие номеру телефона в форме
(555)123-4567. Предположим, что строка phone содержит подобный номер
телефона, тогда его найдет такой образец:
phone.grep(/[\(\d\d\d\)]?\d\d\d-\d\d\d\d/) # => ["(555)123-4567"]

Обратная косая черта предшествует круглой скобке (\(...\)), чтобы дать


знать механизму регулярных выражений, что это символ. В противном слу-
чае механизм будет считать круглые скобки объемлющими подвыражение.
Три \d в круглых скобках представляют три цифры. Дефис (-) является
просто однозначным символом, так что вы можете использовать его в шаб-
лоне как есть.
Знак вопроса (?) — это оператор повторения. Он указывает нулевое или еди-
ничное вхождение предыдущего шаблона. Так что телефонный номер, кото-
рый вы ищете, может иметь код зоны в круглых скобках, а может не иметь.
Шаблон кода зоны окружен [ и ], поэтому оператор ? применяется ко всему
коду зоны. Любая из форм телефонного номера, с кодом зоны или без него,
будет работать. Вот способ использования ? с единственным символом, u:
color.grep(/colou?r/)
# => ["I think that colour is just right for you office."]

Оператор "плюс" (+) указывает на один или несколько предыдущих шабло-


нов, в этом случае цифр:
phone.grep(/[\(\d+\)]?\d+-\d+/) ft # => ["(555)123-4567"]

Фигурные скобки ({}) позволяют указать точное число цифр, например,


\d{3}или \d{4}:
phone.grep(/[\(\d{3}\)]?\d{3}-\d{4}/) # => ["(555)123-4567"]
102 Глава 4

ЗАМЕЧАНИЕ
Можно также определить количество цифр "по крайней мере" с помощью
{m,}> и минимальное/максимальное количество с помощью {m,n}.

В классе String есть также метод =~ и оператор !~. Если метод =~ обна-
руживает совпадение, он возвращает смещение, т. е. позицию, с которой
в строке началось совпадение:
color =~ /colou?r/ # => 13

Оператор !~ возвращает true, если он не нашел совпадения в строке, и false


в противном случае:
color !~ /colou?r/ # => false

Интерес представляют также классы Regexp и MatchData. Класс Regexp


(http://www.ruby-doc.org/core/classes/Regexp.html) позволит вам создать
объект "регулярное выражение". Класс MatchData (http://www.ruby-doc.org/
core/classes/MatchDataMtml) обеспечит особую переменную $-, которая
при сопоставлении с шаблоном инкапсулирует все результаты поиска.
Этот обзор предоставил вам базовые знания о регулярных выражениях
(см. список в табл. 4.1). Руководствуясь ими, вы сможете определить почти
любой шаблон.
Таблица 4.1. Регулярные выражения в языке Ruby

Шаблон Описание
/pattern/опции Шаблон pattern между двумя косыми чертами, за которым
следуют необязательные опции, т. е. один или несколько сим-
волов: i — независимость от регистра; о — подстановка; x —
игнорирование пробельных символов, допускаются коммента-
рии; m — сопоставление нескольких строк текста, символы пе-
ревода строки считаются обычными символами
%r!pattern! Основная строка с разделителями для регулярного выражения,
где ! — произвольный символ
^ Соответствует началу строки текста
$ Соответствует концу строки текста
. Соответствует любому символу
\1...\9 Соответствует n-ому групповому подвыражению
\10 Соответствует n-ому групповому подвыражению, если соответ-
ствие уже найдено; в противном случае ссылается на восьме-
ричное представление кода символа
\n, \r, \t и т. д. Соответствует символу в обозначении с обратной косой чертой
Строки 103

Таблица 4.1 (продолжение)

Шаблон Описание
\w Соответствует символу слова; то же, что [0-9A-Za-z]
\W Соответствует символу неслова
\s Соответствует пробельному символу, как в [\t\n\r\f]
\S Соответствует непробельному символу
\d Соответствует цифре, то же, что [0-9]
\D Соответствует нецифре
\A Соответствует началу строки
\Z Соответствует концу строки или символу перед символом пе-
ревода строки в конце строки
\z Соответствует концу строки
\b Соответствует границе слова снаружи [] или символу возвра-
та каретки (0x08) внутри []
\B Соответствует границе неслова
\G Соответствует точке, где закончилось последнее совпадение
[..] Соответствует любому единичному символу в квадратных
скобках
[^..] Соответствует любому единичному символу не в квадратных
скобках
* Соответствует нулевому (или большему) количеству предыду-
щих регулярных выражений
*? Соответствует нулевому (или большему) количеству предыду-
щих регулярных выражений (не поглощающий)
+ Соответствует одному или нескольким предыдущим регуляр-
ным выражениям
+? Соответствует одному или нескольким предыдущим регуляр-
ным выражениям (не поглощающий)
{m} Соответствует в точности m предыдущим регулярным выраже-
ниям
{m,} Соответствует, по меньшей мере, m предыдущим регулярным
выражениям
{m,n} Соответствует, по меньшей мере, m, но самое большее n пре-
дыдущим регулярным выражениям
{m,n}? Соответствует, по меньшей мере, m, но самое большее n пре-
дыдущим регулярным выражениям (не поглощающий)
104 Глава 4

Таблица 4.1 (окончание)

Шаблон Описание
? Соответствует нулевому количеству или одному предыдущему
регулярному выражению
| Чередование, как color | colour
( ) Группирование регулярных выражений или подвыражений, как
col(o|ou)r
(?#..) Комментарий
(?:..) Группирование без обратных ссылок (без запоминания сопос-
тавленного текста)
(?=..) Определяет позицию с шаблоном
(?!..) Определяет позицию с отрицанием шаблона
(?>..) Определяет независимый шаблон без поиска с возвратом
(?imx) Включает опции i, m или x
(?-imx) Отключает опции i, m или x
(?imx:..) Включает опции i, m или x внутри круглых скобок
(?-imx:..) Отключает опции i, m или x внутри круглых скобок
(?ix-ix: ) Включает (или выключает) опции i и x внутри этой неохвачен-
ной группы

Версия 1.9 и выше


В последующих версиях Ruby в класс String, вероятно:
 будут добавлены методы start__with? и end_with?, которые возвращают
true, если строка начинается с заданного префикса или заканчивается за-
данным суффиксом;
 будет добавлен метод clear, который преобразует строку с длиной более
1 в пустую строку;
 будет добавлен метод ord, который будет возвращать код символа;
 будут добавлены методы partition и rpartition для разбивки строки
заданным разделителем;
 будет добавлен метод bytes, который возвращает байты строки, один за
другим;
 при индексировании строки с помощью [] вместо кода символа будет
возвращаться строка из одного символа;
 рассматриваемые символы будут более одного байта длиной.
Строки 105

Вопросы для самопроверки


1. Чем отличаются chop и chomp?
2. Назовите два способа конкатенации строк.
3. Что происходит, когда вы переворачиваете палиндром?
4. Как вы выполняете итерации над строкой?
5. Назовите не менее двух методов преобразования регистра.
6. Какие методы вы будете использовать для выравнивания пробелов в строке?
7. Опишите чередование в шаблоне регулярного выражения.
8. Чему соответствует /\d{3}/?
9. Как вы преобразуете строку в массив?
10. Какой, по-вашему, самый простой способ создания строки?
106 Глава 4
Глава 5

Математика

В некоторых языках программирования числа являются примитивами или


основными компоновочными блоками, которые служат другим объектам для
создания логики. В Ruby (почти) все является объектом, даже числа. Вот
несколько примеров чисел, которые в других языках считаются примитива-
ми. Из каких классов они пришли?
2.class # => Fixnum
2.0.class # => Float
2_000_000_000.class # => Bignum

Доказательство в живом коде: Ruby почти все превращает в объекты. (Сим-


волы подчеркивания в последнем примере, между прочим, добавлены ис-
ключительно для читабельности; интерпретатор Ruby их игнорирует.)
В Ruby множество классов и модулей, связанных с числами. Вот наиболее
важные из них:
 Numeric — элементарный класс для чисел;
 Integer — элементарный класс целых чисел и базис для класса Fixnum;
 Float — класс для действительных чисел или чисел с плавающей точкой,
основанный на свойственной компьютеру возможности представлять чис-
ла с двойной точностью;
 Fixnum — главный класс целых чисел, основанный на том, что может хра-
ниться в собственном машинном слове компьютера, например, в 32-х или
64-х битах, минус 1;
 Bignum — класс целых чисел за пределами диапазона базового машинного
слова;
 Math — модуль, в котором содержатся математические функции (в виде
методов);
108 Глава 5

 Precision — модуль для аппроксимации точности действительных


чисел;
 Rational — класс, который представляет дробные числа;
 Complex — класс, который представляет комплексные числа, он расши-
ряет действительные числа с помощью мнимой части до комплексных
(x + iy);
 Matrix — класс для создания математических матриц.
На рис. 5.1 показана иерархия математических классов и модулей.

Object

Matrix
Numeric

Integer

Rational
Fixnum Bignum
Complex
Math Precision
module module

Рис. 5.1. Иерархия математических классов и модулей

Иерархия классов и включенных


в них модулей
Между прочим, практичным средством быстрого определения места в иерар-
хии математического класса (или любого другого класса Ruby) является метод
ancestors, один из методов рефлексии (reflection) в языке Ruby. (Рефлек-
сия — это термин, который описывает способность языка программирования
наблюдать за собой и сообщать о том, что он видит. Рефлектировать Ruby уме-
ет, вы узнаете об этом в главе 10.) Вызовите метод ancestors для имени класса,
чтобы посмотреть на его иерархию наследования:
Fixnum.ancestors # => [Fixnum, Integer, Precision, Numeric,
# Comparable, Object, Kernel]
Математика 109

Имена включенных модулей Precision, Comparable и Kernel также попада-


ют в генеалогию. Кроме того, для обнаружения модулей, которые использует
класс, можно применить метод included_modules:
Object.included_modules # => [Kernel]
Numeric.included_modules # => [Comparable, Kernel]
Integer.included_modules # => [Precision, Comparable, Kernel]
Fixnum.included_modules # => [Precision, Comparable, Kernel]

Преобразуем числа
Можно преобразовать число в целое из другой формы с помощью метода
Integer из Kernel. Давайте будем вызывать его в irb.
irb(main):001:0> Integer(1.4) # преобразует число с плавающей точкой
=> 1
irb(main):002:0> Integer("256") # преобразует строку
=> 256
irb(main):002:0> Integer("Ob11110010") #преобразует двоичное число
# из строки
=> 242
irb(main):003:0> Integer(0177) # преобразует восьмеричное число
=> 127
irb(main):004:0> Integer(0x20) # преобразует шестнадцатеричное число
=> 32
irb(main):005:0> Integer(?z) # преобразует код символа
=> 122

Числа с плавающей точкой округляются в меньшую сторону; например,


1.9999 становится 1. Метод Integer принимает на обработку префиксы: 0
(восьмеричное), 0b (двоичное) и 0x (шестнадцатеричное), независимо от того,
помещены ли они в строку или нет.
Можно также создавать или преобразовывать числа с плавающей точкой при
помощи метода Float из Kernel. Снова воспользуйтесь irb, чтобы посмот-
реть, как он работает.
irb(main):001:0> Float(167) # преобразует целое
=> 167.0
irb(main):002:0> Float("77") # преобразует строку
=> 77.0
irb(main):003:0> Float(?a) # преобразует код символа
=> 97.0
110 Глава 5

Элементарные математические операции


Самый простой способ показать вам элементарные математические опера-
ции — это снова воспользоваться irb. Запустите irb и наберите несколько
элементарных выражений, например, таких:
irb(main):001:0> 7 + 5 # сложение
=> 12
irb(main):002:0> 20 - 8 # вычитание
=> 12
irb(main):003:0> 2 * 6 # умножение
=> 12
irb(main):004:0> 144 / 12 # деление
=> 12
irb(main):005:0> 12**2 # возведение в степень
=> 144
irb(main):006:0> 12 % 5 # деление по модулю (остаток от деления)
=> 2

Не забудьте об унарных операторах, + и -, которые обозначают положитель-


ные и отрицательные числа:
irb(main):007:0> +7 + -5
=> 2
irb(main):008:0> -20 + 32
=> 12
irb(main):009:0> -20 - +32
=> -52
irb(main):010:0> 20 * -8
=> -160

Если непосредственно перед числом знака нет, значит, оно положительное.


Можно проделать некоторые из этих операций с помощью именованных ме-
тодов, таких как div, modulo, divmod, quo и remainder. Вызовы методов при-
ведены для целых чисел, чисел с плавающей точкой и круглых скобок, чтобы
вы увидели разницу в результатах.
irb(main):011:0> 24.div 2 # деление
=> 12
irb(main):012:0> (25.0).div (2.0) # результат — целое число
=> 12
irb(main):013:0> 12.modulo 5 # деление по модулю
=> 2
Математика 111

irb(main):014:0> 12.modulo (5.0) # деление по модулю с плавающей точкой


=> 2.0
irb(main):015:0> 12.divmod 5 # возвращает массив: частное, остаток
=> [2, 2]
irb(main):016:0> 12.0.divmod 5.0 # с плавающей точкой
=> [2, 2.0]
irb(main):017:0> 12.quo 5 # возвращает частное
=> 2.4
irb(main):018:0> 12.remainder 5 # возвращает остаток
=> 2

Многие из этих методов родились, как методы класса Numeric, но были под-
менены или переопределены в других классах. Например, вы найдете версии
div в классах Numeric, Fixnum и Bignum.

Деление и округление
Деление влечет небольшую проблему. При выполнении целочисленного де-
ления в Ruby любая дробная часть результата округляется, а вы можете не
осознать этого.
irb(main):019:0> 24 / 2 # нет проблем
=> 12
irb(main):020:0> 25 / 2 # о-о, округление
=> 12
irb(main):021:0> 25.0 / 2 # используется плавающая точка, т. к.,
# по крайней мере, один операнд разрешает это
=> 12.5
irb(main):022:0> 25.0 / 2.0 # то же самое, когда оба операнда
# с плавающей точкой
=> 12.5

Просто запомните: для того чтобы получить дробный результат, вы должны


использовать в качестве операнда, по крайней мере, одно число с плаваю-
щей точкой. О дробных числах читайте в разд. "Рациональные числа" далее
в этой главе.
А также будьте аккуратны при использовании метода div:
irb(main):005:0> 24.div 2 # деление с использованием метода
=> 12
irb(main):006:0> (25.0).div(2.0) # возвращает результат, как целое число;
# округляет
=> 12
112 Глава 5

Метод div в качестве результата возвращает только целую часть, округляя


дробную, даже если один или более операндов являются числами с плаваю-
щей точкой.

Равно, меньше чем или больше чем


Проверьте два числа на равенство при помощи ==, eql? и <=>:
irb(main):007:0> 12 == 24/2
=> true
irb(main):008:0> 24.eql?(12*2)
=> true
irb(main):009:0> 12 == 14
=> false
irb(main):010:0> 12 <=> 12
=> 0
irb(main):011:0> 12 <=> 10
=> 1
irb(main):012:0> 12 <=> 14
=> -1

== и eql? возвращают true или false; <=> (оператор "космический челнок")


возвращает -1, 0 или 1, в зависимости от того, равно ли первое значение вто-
рому (0), меньше, чем второе (-1), или больше, чем второе ( 1).
Проверьте, равны ли два числа, меньше они или больше друг друга:
irb(main):013:0> 12 < 14 # меньше
=> true
irb(main):014:0> 12 < 12
=> false
irb(main):015:0> 12 <= 12 # меньше или равно
=> true
irb(main):016:0> 12.0 > 11.9
=> true
irb(main):017:0> 12.0 >= 12 # больше или равно
=> true

Операторы сокращенного присваивания


Ruby предлагает операторы сокращенного присваивания, которые выполня-
ют операции над переменными без дополнительного операнда. Я покажу вам,
Математика 113

что это означает. Дано, что x равен 5, вы можете добавить значение 1 к x


обычным способом:
x = x + 1

или сокращенным способом:


x += 1

Какой способ вы предпочтете? Вероятно, как и я, тот, в котором ударов


по клавишам на 33% меньше. В результате каждой операции получается 6.
Далее приведены операторы сокращенного присваивания в действии, в irb:
irb(main):001:0> x = 12 # обычное присваивание
=> 12
irb(main):002:0> x += 6 # сложение
=> 18
irb(main):003:0> x -= 12 # вычитание
=> 6
irb(main):004:0> x *= 4 # умножение
=> 24
irb(main):005:0> x /= 8 # деление
=> 3
irb(main):006:0> x **= 2 # степень (возведение в степень)
=> 9
irb(main):007:0> x %= 3 # деление по модулю
=> 0
irb(main):008:0> x # возврат значения переменной
=> 0

ЗАМЕЧАНИЕ
В Ruby нет операторов инкремента (++) или декремента (--), как в С
или других языках.

В Ruby можно также выполнять побитовые операции. Побитовая операция


выполняется над каждым битом, бит за битом, скорее, на представлении чис-
ла, чем на едином элементе. Побитовые операции часто превосходят по ско-
рости обычные арифметические операции. Вот несколько примеров в irb:
irb(main):001:0> ~1011 # побитовое отрицание или дополнение
=> -1012
irb(main):002:0> 1011 | 1010 # побитовое или
=> 1011
114 Глава 5

irb(main):003:0> 1011 & 1010 # побитовое и


=> 1010
irb(main):004:0> 1011 ^ 1010 # побитовое исключающее или
=> 1
irb(main):005:0> 1011 << 1 # сдвиг влево
=> 2022
irb(main):006:0> 1011 >> 1 # сдвиг вправо
=> 505

В перечень побитовых операторов также входят операторы сокращенного


присваивания, приведем в качестве примера &=, ^= или ||=.

Операторы
В табл. 5.1 перечислены математические операторы языка Ruby по старшин-
ству операций. Если оператор определен как метод, это указывается в колон-
ке "Метод", и этот метод может быть заменен.
Таблица 5.1. Математические операторы языка Ruby

Оператор Описание Метод


:: Разрешение границ видимости
[] []= Ссылка, множество
** Возведение в степень
+ - ! ~ Унарный плюс, унарный минус, логическое (но не !)
отрицание, дополнение
* / % Умножение, деление, деление по модулю
(остаток)
+ - Сложение, вычитание
<< >> Сдвиг влево, сдвиг вправо
& Побитовое "И"
| ^ Побитовое "ИЛИ", побитовое исключающее
"ИЛИ"
> >= < <= Больше, больше или равно, меньше, мень-
ше или равно
<=> == === != =~ Сравнение на равенство, равенство, ра- (но не !=
!~ венство (например, в диапазоне), неравен- или !~)
ство, совпадение, несовпадение
&& Логическое "И" (также ключевое слово and,
которое имеет более низкий приоритет)
Математика 115

Таблица 5.1 (окончание)

Оператор Описание Метод


|| Логическое "ИЛИ" (также ключевое слово
or, которое имеет более низкий приоритет)
.. ... Диапазон включающий; диапазон исклю- (но не ...)
чающий
?: Трехместный оператор
= += -= *= /= %= Присваивание, сокращенное присваивание
**= <<= >>= &=
|= ^= &&= ||=
not Логическое отрицание
and or Логическая композиция
defined? Специальный оператор (без приоритета)

Диапазоны
Как было рассмотрено ранее, в Ruby есть диапазоны, операторы диапазона
и класс Range. Диапазоны — это интервалы с начальным и конечным значе-
ниями, отделенными друг от друга оператором диапазона. Существуют два
оператора диапазона: .. (две точки) и ... (три точки). Оператор диапазона ..
означает включающий диапазон чисел. Например, 1..10 означает последова-
тельность чисел от 1 до 10, включая 10 (1, 2, 3, 4, 5, 6, 7, 8, 9, 10). Оператор
диапазона ... означает исключающий диапазон чисел, который исключает
последнее число в последовательности; другими словами, 1...10 означает
последовательность чисел от 1 до 9, т. к. 10 в конце диапазона исключается
(1, 2, 3, 4, 5, 6, 7, 8, 9).
Как видно из приведенных далее строк кода, метод === определяет, является
ли значение членом диапазона или включено ли оно в диапазон:
(1..25) === 14 # => true, в диапазоне
(1..25) === 26 # => false, вне диапазона
(1...25) === 25 # => false, вне диапазона, для оператора диапазона ...

Когда диапазон используется как итератор, возвращается каждое значение


последовательности. Поэтому можно использовать диапазон для таких ве-
щей, как создание массива цифр:
(1..9).to_a # => [1, 2, 3, 4, 5, 6, 7, 8, 9]

Диапазон создается при помощи класса Range:


digits = Range.new(1, 9)
digits.to_a # => [1, 2, 3, 4, 5, 6, 7, 8, 9]
116 Глава 5

Запросы, касающиеся чисел


Временами необходимо узнать что-либо о числе или переменной. Это целое
число? Ноль? Число ли это, вообще? Математические методы языка Ruby
справляются с этим. Эти методы пришли из различных классов.
Давайте начнем с простых вещей. Спросим, является ли число нулем или нет:
op = 0
op.zero? # => true
op.nonzero? # => false

Слишком очевидно. (Но именно это мне нравится в Ruby.) Попробуем что-
нибудь более содержательное:
op = 0
if !op.zero? # не ноль?
puts 12 / op
else
puts "Can't divide by zero."
# (Не могу делить на ноль)
end
op = 2
if op.nonzero? # это не ноль?
puts 12 / op
else
puts "Can't divide by zero."
end

Оба оператора if, по существу, означают одно и то же: разделить 12 на op,


если это не ноль.
Метод integer? пришел из класса Numeric:
12.integer? # => true
12.0.integer? # => false
-1.integer? # => true
-12.integer? # => true

Необходимо придать ему немного смысла.


num = 4 # => 4
if num.integer?
puts "Invited guests: " + num.to_s
# (Званые гости:)
Математика 117

else
puts "Only whole persons can come to this party."
# (Только целый субъект может прийти на этот прием.)
end

Проверить, является ли число конечным или бесконечным, можно при по-


мощи методов finite? и infinite? из Float (фактически, эти методы рабо-
тают только для чисел с плавающей точкой):
0.0.finite? # => true
(-1.0/0.0).finite? # => false
(+1.0/0.0).finite? # => false

0.0.infinite? # => nil


(-1.0/0.0).infinite? # => -1
(+1.0/0.0).infinite? # => 1

Проверьте, в конце концов, является ли значение с плавающей точкой чис-


лом, с помощью метода nan? из Float:
val = 1.0
val.nan? # => false (val not a number? — не число?)
val = 0.0/0.0
val.inspect # => "NaN"
val.nan? # => true

Итеративное вычисление через блоки


Начиная с нуля, метод times выполняет итерации value раз. Здесь value
равно 10:
10.times { |i| print i, " "} #=> 0 1 2 3 4 5 6 7 8 9

Вы также получаете возможность сделать что-то вроде этого:


10.times { |i| print 5*i, " " } # => 0 5 10 15 20 25 30 35 40 45

Можно переписать блок вот так:


10.times do |i|
puts 5*i
end

или так:
10.times do |i| print 5*i, " " end
118 Глава 5

Блок можно открыть и закрыть с помощью do/end или { и }. Фигурные скоб-


ки немного короче и более привычны.
В классе Integer также есть методы downto и upto, которые уже были про-
демонстрированы и сравнивались с циклом в главе 3, но я покажу их здесь
еще раз, чтобы немного освежить вашу память. Прежде всего, метод downto:
100.downto(1) { |c| print c, " "; sleep 1 }

Этот метод печатает числа от 100 до 1, засыпая на 1 секунду перед печатью


каждого числа. Метод upto движется в противоположном направлении:
1.upto(100) { |с| print c, " "; sleep 1 }

Еще больше математических методов


Далее представлено несколько общих математических методов экземпляра
класса. Получите абсолютное значение числа (Bignum, Complex, Fixnum,
Float, Numeric, Rational):
-40.abs # => 40
40.abs # => 40

Получите наименьшее целое, превосходящее число, и наибольшее целое, не


превосходящее число (из Float, Integer и Numeric):
4.65.ceil # => 5
4.65.floor # => 4

Или округлите число в большую или меньшую сторону (Float, Integer


и Numeric):
100.45.round # => 100
100.49.round # => 100
100.5.round # => 101
100.6.round # => 101

Получите следующее целое число при помощи next (или его псевдонима
succ):
-24.next # => -23
1.next # => 2
999.next # => 1000

Получите символьное значение целого числа с помощью chr:


97.chr # => "a"
98.chr # => "b"
Математика 119

125.chr # => "}"


126.chr # => "~"
127.chr # => "\177"

Для непечатаемых символов chr выводит восьмеричное представление сим-


вола (например, \177 — восьмеричное представление DEL).

Математические функции
Модуль Math поставляет многие математические функции (через методы
класса). Я покажу вам, как применять некоторые из них, чтобы можно было
начать работать.
В Math есть также две константы с соответствующими методами. Чтобы ус-
тановить, какие константы определены в Math (или любом другом модуле
или классе), воспользуйтесь рефлексией, вызвав метод constants:
Math.constants # => ["E", "PI"]

Давайте проверим, что за значения у этих констант, Эйлеровой и .


print Math::E # => 2.71828182845905
print Math::PI # => 3.14159265358979

Функция Math.exp из Math возвращает постоянную Эйлера (e) в степени x.


Math.exp(1) # => 2.71828182845905
Math.exp(11) # => 59874.1417151978

Метод Math.sqrt возвращает квадратный корень из x.


Math.sqrt(4) # => 2.0
Math.sqrt(16) # => 4.0
Math.sqrt(144) # => 12.0

Можно брать натуральные логарифмы (по основанию e) и десятичные лога-


рифмы.
Math.log(Math::E) # => 1.0
Math.log(1) # => 0.0
Math.log(0) # => -Infinity
Math.log10(100.0) # => 2.0

В табл. 5.2 показаны все математические функции (все методы класса), до-
ступные из модуля Math. Запомните, что по договоренности, методы Ruby,
заканчивающиеся !, производят изменения по месту (или с разрушением)
объекта, а не его копии.
120 Глава 5

Таблица 5.2. Математические функции (методы)

Метод Описание

Math.acos, Math.acos! Арккосинус


Math.acosh, Math.acosh! Гиперболический арккосинус
Math.asin, Math.asin! Арксинус
Math.asinh, Math.asinh Гиперболический арксинус
Math.atan, Math.atan!, Арктангенс; atan принимает параметр x; atan2
Math.atan2, Math.atan2! принимает x и y
Math.atanh, Math.atanh! Гиперболический арктангенс
Math.cos, Math.cos! Косинус
Math.cosh, Math.cosh! Гиперболический косинус
Math.sin, Math.sin! Синус
Math.erf Функция ошибок
Match.erfc Дополнительная функция ошибок
Math.exp, Math.exp! e в степени x
Math.frexp Нормализованная дробная часть и экспонента
Math.hypot Гипотенуза
Math.ldexp Значение с плавающей точкой, соответствующее
заданной мантиссе и экспоненте
Math.sinh, Math.sinh! Гиперболический синус
Math.sqrt, Math.sqrt! Квадратный корень
Math.tan, Math.tan! Тангенс
Math.tanh, Math.tanh! Гиперболический тангенс

Рациональные числа
Рациональное число — это число, которое может быть выражено в виде дро-
би, числитель и знаменатель которой являются целыми числами. Ruby под-
держивает применение рациональных чисел посредством класса Rational.
Чтобы воспользоваться классом Rational, вы должны затребовать его в про-
грамме. Если к тому же затребовать библиотеку mathn, библиотека Rational
будет работать лучше. Теперь я расскажу вам вкратце, как в Ruby обрабаты-
ваются дроби.
Математика 121

Обычно рациональное число создается при помощи метода Rational. Он


приводит дробь, указанную в параметре, к несократимому виду. (Можно
взять также Rational.new!, но он не сокращает дробь.)
Кстати, Rational ожидает от вас целых чисел. Он выдаст ошибку, если уви-
дит числа с плавающей точкой.
В примере 5.1 демонстрируется, как в Ruby следует обращаться с дробями:
как их создать; как сложить (+), вычесть (-), умножить (*) и разделить (/)
дроби; как выполнить деление по модулю (%), возведение в степень (**)
и сравнить на равенство (== или <=>); и как породить строковое представле-
ние дроби или ее представление с плавающей точкой (inspect).

Пример 5.1. fractions. rb

require 'rational'
require 'mathn'

rat = Rational(25/100) # => 1/4 –- несократимая дробь

rat + Rational(1/4) # => 1/2 —- сложение


rat + 1/4 # => 1/2

rat - Rational(1/8) # => 1/8 -- вычитание


rat - 1/8 # => 1/8

rat * 3 # => 3/4 –- умножение


rat / 2 # => 1/8 -- деление
rat % Rational(1/2) # => 1/4 -- деление по модулю или остаток

rat**2 # => 1/16 -- возведение в степень

rat == 1/8 # => false -- сравнение на равенство


rat == 1/4 # => true
rat <=> 1/4 # => 0
rat <=> 1/8 # => 1
rat <=> 1/2 # => -1

rat.inspect # => "1/4"


rat.to_s # => "1/4"
rat.to_f # => 0.25
p rat # => 1/4
122 Глава 5

ЗАМЕЧАНИЕ
Когда вы используете Rational, все операции над числами в програм-
ме приводят к созданию рациональных результатов.

Простые числа
В библиотеке mathn, которая оказывает содействие работе математических
классов, имеется класс Prime, который позволит вам последовательно гене-
рировать простые числа, начиная с 2. В действительности в качестве началь-
ного числа он выбирает 1, но вычисляет первое простое как 2, как и должно
быть. В Prime есть четыре метода: new, который создает новый объект Prime;
next и succ (синонимы), которые производят следующее простое число;
и each, который перечисляет простые числа до тех пор, пока что-нибудь его
не остановит.
Программа в примере 5.2 покажет вам, как генерировать простые числа, одно
за другим.

Пример 5.2. prime.rb

require 'mathn'

prime_number = Prime.new # производит объект класса Prime


prime_number.next # => 2 # возвращает следующее простое число
# (начальное значение = 1)
prime_number.succ # => 3 # succ тоже работает

# напечатаем следующее простое число как строку


puts "The next prime number is " + prime_number.next.to_s + "."
# => The next prime number is 5.

Код в примере 5.3 генерирует 25 простых чисел — все простые числа от 2 до 97.

Пример 5.3. prime_each.rb

require 'mathn'

list_primes = Prime.new

list_primes.each { |prime| print prime, " "; break unless prime < 90 }
# => 2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73
# 79 83 89 97
Математика 123

Шутки ради
Вот предложение, которое поможет вам запомнить первые семь простых чи-
сел: "In the early morning astronomers spiritualized nonmathematicians".
(см. http://mathworld. wolfram.com/PrimeNumber.html). Число букв в каж-
дом слове предложения соответствует очередному простому числу.
Приведенная далее строка кода Ruby анализирует предложение и возвращает
длину каждого слова, так что вы сможете увидеть подразумеваемое простое
число (пунктуация была удалена для обеспечения правильного подсчета):
"In the early morning astronomers spiritualized
nonmathematicians".split.each { |p| print p.length, ""}
# => 2 3 5 7 11 13 17

Метод split происходит из класса String. Он разбивает строку по знакам


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

Вопросы для самопроверки


1. В Ruby числа являются примитивами или объектами?
2. Каким методом необходимо воспользоваться, чтобы определить, какие
модули включает класс языка Ruby?
3. Каков возможный диапазон чисел, представленных классом Fixnum?
4. Как можно избежать округления результатов деления?
5. Рациональные числа — это другое название для __________________.
6. Если унарный оператор отсутствует, каков знак числа?
7. Какие две константы имеются в модуле Math?
8. Каким методом вы пользуетесь для преобразования целого числа в сим-
вольное представление?
124 Глава 5
Глава 6

Массивы

Класс Array — один из встроенных классов в Ruby. Массивы — это ком-


пактные упорядоченные совокупности объектов. Массивы в Ruby могут со-
держать объекты таких классов, как String, Integer, Fixnum, Hash, Symbol
и даже другие объекты класса Array, если вы дадите им имя. Любой объект,
который создает Ruby, может храниться в массиве.
Любой элемент в массиве связан с индексом (index), также известным в дру-
гих языках, как subscript, и к нему можно обращаться по индексу. Элементы
массива автоматически индексированы (пронумерованы) целыми числами
(Fixnum), начиная с 0, пронумерованы последовательно, с добавлением 1 для
каждого последующего элемента. В определенных случаях можно ссылаться
на последний элемент массива с помощью –1, на второй от конца с –2 и т. д.
Это практично.
Массивы в Ruby не такие негибкие, как в других языках. В статических ком-
пилируемых языках программирования вы должны угадать окончательный
размер массива на момент его создания. Если окажется, что массив перерас-
тает этот размер, вам придется скопировать его во временный массив, а по-
том создать новый, большего размера и переписать в него временный массив.
Ruby является динамическим языком — как среди прочих Perl, Python и PHP, —
и поэтому в нем можно добавлять в массив элементы, причем массив будет
увеличивать свой размер автоматически. Еще одна интересная особенность
Ruby состоит в том, что он может хранить массивы с объектами различного,
а не какого-то одного типа, как это принято в статических языках. Вы увиди-
те такие массивы в данной главе.
Запомните, что по договоренности, любой метод в Ruby, имя которого закан-
чивается восклицательным знаком (!), как sort!, изменяет объект по месту.
Он не делает копию. Другими словами, это средство разрушения. Не на-
столько разрушительное, как Калигула, но может изменить массив навсегда.
126 Глава 6

А также любой метод с вопросительным знаком в конце имени, такой как


eql?, возвращает или true, или false.
В этой главе вы увидите на примерах, как создавать и обрабатывать массивы.
Вернемся к старому доброму способу. Набираете примеры в irb или в файлах,
а затем выполняете как программы, а обучаетесь по ходу дела. В этой главе
вам будут представлены многие методы из класса Array — не все, но многие.

Создаем массивы
Существует много средств для создания или инициализации массива. Одно
из них — метода new этого класса:
months = Array.new

Здесь создан пустой массив, представленный как [], с именем months. Чего-
то не хватает, не так ли? Фактически можно проверить, пуст массив или нет,
методом empty? (он возвращает true, если массив, несомненно и совершен-
но, пуст, false — в противном случае):
months.empty? # => true

Не слишком захватывает. Давайте немного его усовершенствуем. Вы можете


установить размер массива (число элементов в массиве) вот так:
months = Array.new(12)

или так:
months = Array.new 12

Теперь у массива months есть размер (или длина), он состоит из 12 элемен-


тов. Можно проверить размер массива с помощью методов size или length:
months.size # => 12

или:
months.length # => 12

Но что за элементы были до сих пор в months? Все они были nil, потому что
никто (а это должен был быть я) не позаботился определить, что они собой
представляют. На этот момент массив months содержит 12 значений nil.
Чтобы проинспектировать массив, т. е. взглянуть на массив, как на массив,
воспользуйтесь:
puts months.inspect

или:
p months
Массивы 127

Обычно я использую p — вероятно, вы уже можете догадаться почему. Лю-


бой из этих методов возвращает:
[nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil]

Не увлекает, откровенно говоря. Но мы можем поправить дело. Другая форма


new позволит вам присвоить каждому элементу массива объект (например,
строку):
month = Array.new(12, "month")

Теперь month предстает в таком виде:


["month", "month", "month", "month", "month", "month", "month",
"month", "month", "month", "month", "month"]

Драим палубу
Чуть лучше, но еще не то. Знайте, если вам не нравится то, что вы получили,
вы всегда можете очистить массив с помощью clear:
month.clear # => []
month.empty? # => true

Не используйте clear в припадке гнева. Можете пожалеть.

Создаем массивы с помощью блока


В методе new можно также указывать блок для заполнения каждого элемента
тем, что блок вычисляет:
num = Array.new(10) { |e| e = e * 2 }

Получается такой массив:


[0, 2, 4, 6, 8, 10, 12, 14, 16, 18]

Немного лучше. Теперь мы получили нечто более управляемое.

Существует более простой способ


В Array есть еще один метод — []. Он работает так:
month_abbrv = Array.[]( "jan", "feb", "mar", "apr", "may", "jun", "jul",
"aug", "sep", "oct", "nov", "dec" )

Или вот так, если опустить точку (.) и круглые скобки (()), что возможно
благодаря гибкому синтаксису методов Ruby:
month_abbrv = Array[ "jan", "feb", "mar", "apr", "may", "jun", "jul",
"aug", "sep", "oct", "nov", "dec" ]
128 Глава 6

Так проще. Но еще более простой метод создания массива — непосредствен-


но использовать квадратные скобки:
months = [ nil, "January", "February", "March", "April", "May", June",
"July", "August", "September", "October", "November", "December" ]

ЗАМЕЧАНИЕ
Почему этот массив начинается с nil? Я воспользовался искусст-
венным заполнителем. Это первый элемент в массиве months, и, как
таковой, он связан с индексом 0. Я хочу связать первый месяц года
с индексом 1, а не 0, поэтому я и вставил nil в качестве первого
элемента. Таково мое предпочтение, но оно не обязано быть вашим.

Еще более простой способ


Вот еще более простой способ создать массив. В модуле Kernel, включенном
в Object, есть метод Array, который принимает единственный параметр.
В этом примере метод для создания массива цифр в качестве параметра при-
нимает диапазон.
digits = Array(0..9) # => [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

Но если вы предложите набор строк, Array примет их как единственный сце-


пленный элемент.
donald_duck_nephews = Array( "Huey" "Dewey" "Louie" )
=> ["HueyDeweyLouie"]

Вы не этого хотели, да? Ну, хорошо, есть способ даже еще проще определить
массив строк — воспользоваться нотацией %w. Этот способ подразумевает,
что все элементы являются строками (даже nil), но он определенно экономит
удары по клавишам (не надо набирать кавычки и запятые):
months = %w[ nil January February March April May June July August Sep-
tember October November December]

Получится такой массив months:


["nil", "January", "February", "March", "April", "May", "June", "July",
"August", "September", "October", "November", "December"]

Правда, я не хочу, чтобы nil был представлен как строка. Как мне восполь-
зоваться своей любимой нотацией (%w) и одновременно решить эту пробле-
му? Да вот так:
months[0] = nil;
Массивы 129

Я получил доступ к массиву при помощи [0] и присвоил новое значение


элементу с помощью =. Посмотрите на массив и обратите внимание на изме-
нение:
[nil, "January", "February", "March", "April", "May", "June", "July",
"August", "September", "October", "November", "December"]

Теперь очередная головоломка. Если при использовании %w я наполню мас-


сив числами, как указано далее:
year = %w[ 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009]

то эти числа будут трактоваться как строки:


["2000", "2001", "2002", "2003", "2004", "2005", "2006", "2007", "2008",
"2009"]

Можно проверить, какому классу принадлежит элемент этого массива:


year[0].class # => String

Возможно, вы не хотели таких последствий. Чтобы элементы получились


числами, избегайте %w и пользуйтесь другими методами создания массива:
year = [2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009]

Снова проверьте класс элемента и убедитесь, что все у вас в порядке:


year[0].class # => Fixnum

У вас даже может быть массив, который содержит объекты из других клас-
сов, т. е. не все одного типа. Например, вот массив, в котором содержатся
четыре элемента, все — объекты различных типов:
hodge_podge = ["January", 1, :year, [2006,01,01]]

Воспользуйтесь each, чтобы выполнить итерации по всему массиву, и class,


чтобы определить, каким типом объекта является каждый элемент:
hodge_podge.each {|e| print e.class, " "}
# => String Fixnum Symbol Array

Получаем доступ к элементам


Вы только что видели, что можно получить доступ к элементам методом [].
Пусть дан массив ql:
q1 = %w[ January February March ]

Можно получить доступ к первому элементу массива, элементу 0, с помощью


индекса 0:
q1[0] # => January
130 Глава 6

Получите доступ к последнему элементу массива, элементу 2:


q1[2] # => March

Можно также воспользоваться методом at, вот так:


q1.at(0) # => January

Предполагается, что метод at немного быстрее, чем [], согласно документа-


ции Ruby для at. Я буду использовать впредь [], но at тоже будет работать.
Можно получить доступ к элементам для применения их в строке таким спо-
собом:
print "The event is scheduled for " + months[3] + " " + years[8] + "."
# => The event is scheduled for March 2008.

Хорошая работа. Индекс 3 соответствует марту, третьему месяцу года, а ин-


декс 8 соответствует 2008.
Можно получить доступ к последнему элементу в массиве так:
q1[-1] # => March

-1 открывает вам доступ к последнему элементу в массиве, путем возвраще-


ния к началу цикла с отрицательным шагом. Как насчет второго элемента
(1)? Как получить его? Можно было бы использовать такой индекс:
q1[1]

или такой:
q1[-2]

Другой способ добраться до первого и последнего элементов массива состоит


в привлечении методов first и last:
q1.first # => January
q1.last # => March

Оба метода, и first, и last, принимают целочисленные параметры, указы-


вающие на количество элементов, которые необходимо возвратить:
q1.first 2 # => ["January", "February"]
q1.last 0 # => [] не особенно практично

Можно увидеть обратную сторону с помощью метода index. Этот метод воз-
вращает индекс, а не элемент, основываясь на параметре (объекте). Он вер-
нет индекс первого элемента, соответствующего объекту:
q1.index "March" # => 2

Подобным же образом, rindex отбирает последний элемент, соответствую-


щий объекту.
Массивы 131

Для демонстрации следующих нескольких методов я возьму массив по-


длиннее:
year = [2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009]

На этот раз укажите, откуда начинать отсчитывать элементы и сколько


элементов вы хотите:
year[0, 3] # => [2000, 2001, 2002]

0 — стартовый параметр. Он велит начинать с 0 или начала массива. Второй


параметр, длина, сообщает, сколько элементов вы хотите получить. (Вы не
сможете сделать этого методом at.) Можно также использовать диапазон:
year[7..9] # => [2007, 2008, 2009]

Напомню, что две точки означают "включить оба элемента", а три точки —
"не включать последний элемент". (Между прочим, вы не сможете указать
диапазоны в методе at.)
Вместо [] вы можете применить метод slice, это его псевдоним:
year.slice(1) # => 2001
year.slice(0,4) # => [2000, 2001, 2002, 2003]
year.slice(0..2) # => [2000, 2001, 2002]
year.slice(0...2) # => [2000, 2001]

Дело вкуса, но я привязался к нотации [].


Я покажу вам еще один, последний метод — include?. Он проверяет, вклю-
чает ли массив элемент с заданным значением, и возвращает true или false:
year.include? 2004 # => true
year.include?( 2010 ) # => false

Конкатенация
Давайте немного поиграем с приведенными далее массивами:
q1 = %w[ January February March ]
q2 = %w[ April May June ]
q3 = %w[ July August September ]
q4 = %w[ October November December ]

Эти массивы можно соединить несколькими способами. Один из них — при


помощи оператора или метода +:
half1 = q1 + q2
half2 = q3 + q4
yr = half1 + half2
132 Глава 6

Инспектирование этих новых массивов даст, соответственно, следующие ре-


зультаты:
["January", "February", "March", "April", "May", "June"]
["July", "August", "September", "October", "November", "December"]
["January", "February", "March", "April", "May", "June",
"July", "August", "September", "October", "November", "December"]

Другое средство соединения массивов — это метод <<:


yrs = [1999]
yrs << 2000 # => [1999, 2000]

Можно также образовать цепочку:


yrs << 2001 << 2002 << 2003 # => [1999, 2000, 2001, 2002, 2003]

Статические языки, такие как Java и C, чтобы добавить в массив элементы,


потребуют от вас увеличить его размер. В Java коллекция ArrayList устраня-
ет такую необходимость, но если вы попытаетесь добавить 11-й элемент
в обычный старый 10-элементный массив, то получите исключение. Про-
граммисты обычно копируют массивы и создают новые с большим индексом.
Мне нравится, как Ruby улучшил дело.
Аналогично +, вы можете подцепить один массив к другому с помощью
concat:
last_part = q3.concat( q4 )

q3 и q4 соединяются, образуя новый массив, last_part. Метод concat всегда


возвращает новый массив; он не добавляет элементы к существующему, как
это делает <<.

Операции над множествами


Ruby может выполнить несколько операций над множествами, например:
 пересечение с помощью &;
 разность с помощью -;
 объединение с помощью |.
Пересечение (&) создает новый массив, объединяя общие элементы двух мас-
сивов и удаляя разные элементы и дубликаты.
tue = [ "shop", "make pie", "sleep" ]
wed = [ "shop", "make pie", "read", "sleep" ]
tue & wed # => ["shop", "make pie", "sleep"]
Массивы 133

Результат говорит о том, что я планирую делать в оба этих дня (я не буду
читать).
Разность (-) создает новый массив, удаляя элементы, которые обнаружились
в обоих массивах:
wed - tue # => ["read"]

Объединение (|) соединяет два массива вместе, удаляя дубликаты:


tue | wed # => ["shop", "make pie", "read", "sleep"]

В Ruby можно проделывать эти операции над массивами и другими объектами


с помощью класса Sets (см. http://www.ruby-doc.org/core/classes/Set.html
или наберите ri Set).

Уникальные элементы
Метод uniq, отдаленно связанный с операциями над множествами, создав
новый массив, также удаляет из него дубликаты. Его ближайший сосед uniq!
изменяет сам массив, по месту.
shopping_list = %w[ cheese bread crackers potatoes carrots cheese ]
=> ["cheese", "bread", "crackers", "potatoes", "carrots", "cheese"]
shopping_list.uniq!
=> ["cheese", "bread", "crackers", "potatoes", "carrots"]

Очищаем стек
Если вы когда-нибудь ели в кафетерии, то можете припомнить стопку нагре-
тых тарелок, которые хранятся на стойке с пружиной внизу. Первая тарелка
была последней, которую доставали.
Это подобно стековой структуре в теории вычислительных систем. Стек —
это структура LIFO (last in, first out; "последним пришел — первым обслу-
жен"). Вы можете использовать массив подобно стеку, применяя методы
push и pop из класса Array. Здесь показано как:
fruit = %w[ apple orange banana ]
fruit.pop # => "banana"
p fruit # => ["apple", "orange" ]
fruit.push "mango"
p fruit # => ["apple", "orange", "mango"]
134 Глава 6

Сравниваем массивы
Сравнить массивы, чтобы посмотреть, равны ли они, вам позволят три мето-
да. Это ==, <=> и eql?. Рассмотрите эти массивы. Каждый назван по имени
служащего и содержит ответы на вопросы, работают ли они полный или
неполный рабочий день (full или part), сколько часов в неделю они рабо-
тают, есть ли у них пенсия (yes или no).
bob = ["full", 40, "yes"]
lou = ["part", 23, "no"]
schlomo = ["full", 40, "yes"]

Метод == сравнивает два массива на равенство. Два массива считаются рав-


ными, если, во-первых, они содержат одно и то же количество элементов и,
во-вторых, каждый элемент равен соответствующему элементу в другом мас-
сиве (сравните с == из Object).
Сравните эти массивы методом ==:
lou == lou # => true
bob == schlomo # => true
schlomo == lou # => false

С этим методом близко связан метод eql?. Он возвращает true, если объекты
одинаковы, или если их содержимое одинаково. В чем разница между ==
и eql?. Метод eql? проверяет, равны ли значения (как ==), но он также про-
веряет, имеют ли значения один и тот же тип.
bob == schlomo # => true
bob.eql?( "full, 40, yes" ) # => false, bob — не строка

Еще можно сравнить массивы с помощью оператора <=>. Когда он сравнива-


ет два массива, сравнение выполняется для каждого объекта в массивах. Два
массива считаются равными, если они имеют одинаковую длину и если зна-
чение каждого элемента равно значению соответствующего элемента в дру-
гом массиве. Когда сравнение выполнено, оператор определяет, больше,
меньше или равны друг другу значения сравниваемых элементов. Вместо
true или false возвращается целое число: -1 — для "меньше", 0 — для "рав-
но" и 1 — для "больше".
lou <=> lou # => 0
bob <=> lou # => -1
lou <=> schlomo # => 1
Массивы 135

Изменяем элементы
Ruby предоставляет массу способов воздействия на элементы массивов,
например, способы изменения их значений, способы их представления.
Начнем с самых простых изменений. Давайте вернемся к нашему масси-
ву months:
months = %w[ nil January February March April May June July August Sep-
tember October November December ]

Создался массив, который выглядит так:


["nil", "January", "February", "March", "April", "May", "Dune",
"July", "August", "September", "October", "November", "December"]

Знакомо? Опять здесь по индексу 0 элемент со значением nil показан как


строка. Это не то, чего мы хотим. Давайте изменим его при помощи insert:
months.insert( 0, nil )

Это решает проблему:


[nil, "January", "February", "March", "April", "May", "June", "July",
"August", "September", "October", "November", "December"]

Предположим, что вы хотели бы изменить три элемента так, чтобы названия


были написаны по-немецки, а не по-английски. Вы могли бы сделать это не-
сколькими способами. В этом примере в элементах с 5 по 7 для замены строк
May, June и July на строки Mai, Juni и Juli применяется диапазон.
months[5..7] = "Mai", "Juni", "Juli"
# => [nil, "January", "February", "March", "April",
# "Mai", "Juni", "Juli", "August", "September", "October",
# "November", "December"]

Можно проделать то же самое при помощи параметров начала и длины


(и вернуться к английскому языку):
months[5, 3] = "May", "June", "July"
# => [nil, "January", "February", "March", "April", "May",
# "June", "July", "August", "September", "October",
# "November", "December"]

Как строка
С помощью метода to_s можно извлечь элементы массива как отдельные
строки. Метод to_s является общим для многих классов.
greeting = [ "Hello! ", "Bonjour! ", "Guten Tag!" ]
puts greeting.to_s # => Hello! Bonjour! Guten Tag!
136 Глава 6

Воспользуйтесь join, чтобы сбить все элементы в единую строку:


months.join # =>
"JanuaryFebruaryMarchAprilMayJuneJulyAugustSeptemberOctoberNovember
December"

Не совсем то, что вы имели в виду? Давайте вставим между элементами запя-
тую и пробел:
months.join ", "
# => " , January, February, March, April, May, June,
# July, August, September, October, November, December"

Выглядит лучше, но что это там за запятая в начале? Тьфу. Как избавиться от
нее? Например, можно применить метод compact, который удаляет все nil из
массива.
months.compact.join( ", " )
# => "January, February, March, April, May, June, July, August,
# September, October, November, December"

Пожалуйста. Намного лучше.

Применяем shift и unshift


Другой способ удалить элемент из массива — применить метод shift. Этот
метод возвращает первый элемент массива (nil, если массив пустой), а затем
удаляет элемент, сдвигая все остальные элементы, один за другим. Это что-то
вроде метода pop, за исключением того, что он работает на начале массива,
а не на конце (FIFO — first in, first out; "первым пришел — первым обслужен").
dates = [ 4, 5, 6, 7 ] # => [4, 5, 6, 7]
dates.shift # => 4
p dates # => [5, 6, 7]

С shift связан метод unshift, который добавляет объекты (один или несколь-
ко) в массив. Он подобен puqsh, но работает на начале массива, а не на конце.
dates.unshift 4 # => [4, 5, 6, 7]
dates.unshift(2,3) # => [2, 3, 4, 5, 6, 7]

Удаляем элементы
Метод delete удаляет соответствующий объект из массива, возвращая уда-
ленный объект, если тот найден. Пусть дан массив:
month_a = %w[ nil jan feb mar apr may jun jul aug sep oct nov dec ]
# => ["nil", "jan", "feb", "mar", "apr", "may", "jun", "jul", "aug",
# "sep", "oct", "nov", "dec"]
Массивы 137

Следующий вызов удаляет из month_a строку nil:


month_a.delete "nil"

Этот метод может также принимать блок. Если объект не найден, возвраща-
ется результат выполнения блока:
month_a.delete("noon") {"noon wasn't found. What are you going to do
about it?"}

С помощью delete_at можно удалить элемент на основе его индекса (в при-


мере предполагается, что вы работаете с исходным массивом):
month_a.delete_at( 12 ) # => "dec"
p month_a # ["nil", "jan", "feb", "mar", "apr", "may",
# "jun", "jul", "aug", "sep", "oct", "nov"]

Массивы и блоки
В классе Array тоже есть метод each — как и во множестве других классов
Ruby. Метод each позволяет перебрать все элементы в массиве и сделать что-
нибудь с ними. Приведенный далее вызов меняет в month_a (без nil) в со-
кращенных названиях месяцев первую букву на заглавную:
month_a.each { |e| print e.capitalize + " " }
Он вырабатывает строку, а не массив:
Jan Feb Mar Apr May Dun Jul Aug Sep Oct Nov Dec

Метод map (и его двойник collect) подобен each, но вместо строки он воз-
вращает новый массив.
month_a_2007 = month_a.map { |e| e.capitalize + " 2007" }
Это даст вам:
p month_a_2007 # => ["Jan 2007", "Feb 2007", "Mar 2007", "Apr 2007",
# "May 2007", "Jun 2007", "Jul 2007", "Aug 2007",
# "Sep 2007", "Oct 2007", "Nov 2007", "Dec 2007"]

Прямая и обратная сортировки


Вы как попало добавили в массив числовые объекты. Теперь настало время
привести все в порядок. Дан массив x:
x = [ 2, 5, 1, 7, 23, 99, 14, 27 ]

Примените к нему sort (или sort! для изменений по месту), и ваш сбивший-
ся с пути массив выстроит свои элементы по порядку:
x.sort! # => [1, 2, 5, 7, 14, 23, 27, 99]
138 Глава 6

ЗАМЕЧАНИЕ
Для сортировки массива необходимо, чтобы его элементы были срав-
нимы (больше, меньше или равны). Это легко проделать со строками
и числами. Но т. к. массивы в Ruby могут хранить объекты любого типа,
те могут оказаться несравнимыми, и, в этом случае, вы не сможете
отсортировать элементы при помощи sort или sort!.

Метод reverse изменяет порядок расположения элементов в массиве на об-


ратный, возвращая новый перевернутый массив:
%w[ one two three four five six seven eight nine ten ].reverse
# => ["ten", "nine", "eight", "seven", "six", "five", "four", "three",
# "two", "one"]

Многомерные массивы
Многомерный массив — это массив массивов. Вы создаете такой мас-
сив, задавая элементы, которые сами являются массивами. Вот двумерный
массив:
d2 = [ ["January", 2007],
["February", 2007],
["March", 2007] ]

Элементы массива d2 сами являются массивами. А здесь приведен пример


того, как сформировать трехмерный массив:
yrs = [ 2007, 2008, 2009 ]
days = [ 31, [28, 29], 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 ]
months = [ "Jn", "Fb", "Mr", "Ap", "Ma", "Ju", "Jl", "Au", "Sp", "0c",
"Nv", "Dc" ]
d3 = [ yrs, days, months ]
# => => [[2007, 2008, 2009], [31, [28, 29],
# 31, 30, 31, 30, 31, 31, 30, 31, 30, 31],
# ["Jn", "Fb", "Mr", "Ap", "Ma", "Ju", "Jl", "Au", "Sp", "0c",
# "Nv", "Dc"]]

Размышляя здраво, давайте при помощи flatten превратим d2 в одномерный


массив.
d2.flatten # => ["January", 2007, "February", 2007, "March", 2007]

Славно! Сэкономил на наборе.


Массивы 139

Двумерный массив подобен таблице со строками и столбцами. Давайте по-


пробуем методом transpose преобразовать d2:
d2 = [ ["January", 2007], ["February", 2007], ["March", 2007] ]

в:
d2.transpose
# => => [["January", "February", "March"], [2007, 2007, 2007]]

Версия 1.9 и выше


Возможно, это будет добавлено в версию 1.9:
 в классе Array появится новый метод — nitems. Этот метод будет воз-
вращать размер результирующего массива, после того как будут выполне-
ны условия в блоке;
 методы index и rindex будут принимать блок;
 метод pop будет принимать параметр, который позволит ему выталкивать
из массива более одного элемента за раз;
 вы сможете присвоить nil существующему элементу массива, таким об-
разом, он будет удален;
 по аналогии с классом Hash, метод to_s будет выдавать такой же резуль-
тат, как метод inspect.

Другие методы работы с массивами


Чтобы получить список всех методов в Array, наберите:
ri Array

Чтобы узнать подробности о каком-нибудь методе через ri, наберите в команд-


ной строке что-нибудь подобное:
ri Array#map

или
ri Array.map

или
ri "Array.&"

Любой из этих методов можно отыскать в электронной документации по


языку Ruby на http://www.ruby-doc.org/core/classes/Array.html.
140 Глава 6

Вопросы для самопроверки


1. Назовите методы класса для Array. Есть только два таких.
2. Продемонстрируйте три способа создания массива
3. Воспользуйтесь двумя методами получения доступа к последнему элемен-
ту в массиве.
4. Да или нет: shift и unshift выполняют операции переворачивания стека.
5. В чем разница между delete и delete_at?
6. Вам необходимо добавить объект в каждый элемент массива. Выберите
вариант:
value_at;
length;
map;
[]=.
7. Какие методы сравнивают массивы на равенство?
8. Каким методом можно воспользоваться для удаления из массива nil?
Глава 7

Хэши

Хэш — это неупорядоченная коллекция пар "ключ-значение", которые вы-


глядят таким образом: "storm" => "tornado". Хэш подобен массиву (см.
главу 6), но вместо целочисленного индекса, по умолчанию начинающегося
с 0, индексирование производится по ключам, которые могут быть составле-
ны из любых объектов Ruby. Другими словами, вы можете применять цело-
численные ключи просто как в Array, но у вас есть также возможность ука-
зать в качестве ключа любой объект Ruby, даже массив! (В Ruby хэши
фактически реализованы как массивы.)
К хэшам можно получать доступ и по ключам, и по значениям, обычно его
получают по ключам, которые должны быть уникальными. Если вы попытае-
тесь получить доступ к хэшу с несуществующим ключом, метод вернет nil
(если только у хэша нет значения по умолчанию). Пары "ключ-значение" не
хранятся в хэше в том порядке, в котором они были вставлены (порядке,
в котором вы поместили их в хэш), так что не удивляйтесь, если содержимое
хэша выглядит отличным от того, что вы вводили — содержимое здесь не
упорядочивается так, как в массиве.

Создаем хэш
Как и в случае с массивами, создать хэш можно различными способами. Пус-
той хэш вы можете создать с помощью метода new класса:
months = Hash.new
Можно проверить, пустой ли хэш, при помощи empty?:
months.empty? # => true
Или насколько он велик, при помощи length или size:
months.length
months.size # => 0
142 Глава 7

Можно также методом new создать хэш со значением по умолчанию, которое


в противном случае будет просто nil, вот так:
months = Hash.new( "month" )

или так:
months = Hash.new "month"

Если вы с любым ключом пытаетесь получить доступ в хэш, у которого оп-


ределено значение по умолчанию, то при несуществующем ключе или значе-
нии вы получите значение по умолчанию:
months[0]

или:
months[72]

или:
months[234] # => "month"

В классе Hash есть также метод [], который вызывается одним из двух спо-
собов: или с помощью разделяющей запятой, вот так:
christmas_carol = Hash[ :name, "Ebenezer Scrooge", :partner, "Jacob Mar-
ley", : employee, "Bob Cratchit", :location, "London", :year, 1843]
# => {:name => "Ebenezer Scrooge", :employee => "Bob Cratchit", :year =>
1843, :partner => "Jacob Marley", : locations => "London"}

Или с помощью =>:


christmas_carol = Hash[ :name => "Ebenezer Scrooge", :partner => "Jacob
Marley", : employee => "Bob Cratchit" => :location, "London",
:year => 1843 ] # => {:name => "Ebenezer Scrooge",
:employee => "Bob Cratchit", :year => 1843, :partner => "Jacob Marley",
:location => "London"}

Самое простое средство создания хэша, как мне кажется, — это фигурные
скобки:
months = { 1 => "January", 2 => "February", 3 => "March", 4 => "April",
5 => "May", 6 => "June", 7 => "Duly", 8 => "August", 9 => "September",
10 => "October", 11 => "November", 12 => "December" }

Но выглядит это почти как массив, который мы создавали в предыдущей гла-


ве. Что еще вы могли бы сделать? Вместо целых чисел вы могли бы исполь-
зовать для ключей строки:
month_a = { "jan" => "January", "feb" => "February", "mar" => "March",
"apr" => "April", "may" => "May", "jun" => "June", "jul" => "July",
"aug" => "August", "sep" => "September", "oct" => "October",
"nov" => "November", "dec" => "December" }
Хэши 143

До сих пор я указывал в качестве ключей символы, целые числа (Fixnum)


и строки. Но ключом или значением может служить любой объект Ruby, да-
же массив. Например, вот такое будет работать:
[1,"jan"] => "January"

Получаем доступ к хэшам


Пусть дан хэш, связывающий почтовый индекс с названиями городов
в Вайоминге, которые начинаются на букву "Т" (надо же как-то ограничить
список):
zip = { 82442 => "Ten Sleep", 83025 => "Teton Village",
83127 => "Thayne", 82443 => "Thermopolis", 82084 => "Tie Siding",
82336 => "Tipton", 82240 => "Torrington", 83110 => "Turnerville",
83112 => "Turnerville" }

Существует уйма способов получить доступ к ключам и/или значениям


в этом хэше. Вы можете выбрать то, что понравится вам — что подойдет для
решения очередной задачи.
Имеется ли в хэше почтовый индекс с заданным ключом, можно проверить
любым из следующих методов, которые все друг для друга являются сино-
нимами: key?, has_key?, member? или include?:
zip.has_key? 82442 # => true

Или можно, наоборот, посмотреть, имеется ли заданное значение, при помо-


щи value? или has_value?:
zip.has_value? "Ten Sleep" # => true

Давайте вытащим что-нибудь из zip. Вот простой способ ухватить значение —


метод [ ]. Он извлекает из хэша единичное значение на основе ключа:
zip[82442] # => "Ten Sleep"

Далее у нас есть методы keys и values. При помощи keys вернем массив, со-
держащий все ключи, имеющиеся в хэше:
zip.keys
# => [83110, 83127, 82336, 83112, 82084, 83025, 82442, 82443, 82240]

При помощи values получим все значения, хранящиеся в хэше:


zip.values
# => ["Turnerville", "Thayne", "Tipton", "Turnerville", "Tie Siding",
# "Teton Village", "Ten Sleep", "Thermopolis", "Torrington"]
144 Глава 7

Извлечем из хэша значения на основе одного или нескольких ключей при


помощи values_at, также помещающего значение или значения в массив:
zip.values_at 82084 # => ["Tie Siding"]
zip.values_at 82442, 82443, 82240
# => ["Ten Sleep", "Thermopolis", "Torrington"]

Теперь вернем значение ключа (только одного ключа) методом index:


zip.index "Thayne" # => 83127

Метод select использует блок и возвращает новый, многомерный массив


пар "ключ-значение":
zip.select { |key,val| key > 83000 }
# => [[83110, "Turnerville"], [83127, "Thayne"], [83112, "Turnerville"],
# [83025, "Teton Village"]]

Выполняем итерации
Как вы уже видели, Ruby проделал отличную работу, предоставив средства
для "перемалывания" объекта. Выполнять итерации в хэше можно при по-
мощи each, each_key, each_value или each_ pair. Вот в чем разница.
Метод each вызывает блок для каждого ключа в хэше, и вы получаете удар
от каждой пары:
zip.each {|k,v| puts "#{k}/#{v}" } # =>
83110/Turnerville
83127/Thayne
82336/Tipton
83112/Turnerville
82084/Tie Siding
83025/Teton Village
82442/Ten Sleep
82443/Thermopolis
82240/Torrington

Метод each может принимать один или два параметра, которые передаются
блоку, как двухэлементные массивы. Метод each_pair подобен each, за ис-
ключением того, что он должен принимать два параметра и действует эффек-
тивнее, чем each, в котором указаны оба параметра.
Метод each_key передает блоку только ключи:
zip.each_key { |key| print key, " " }
# => 83110 83127 82336 83112 82084 83025 82442 82443 82240
Хэши 145

Сравните это с методом keys, который возвращает все ключи в массиве.


Метод each_value передает блоку все значения:
zip.each_value { |value| print value, " " }
# => Turnerville Thayne Tipton Turnerville Tie Siding Ten Sleep
# Teton Village Thermopolis Torrington

Изменяем хэши
Метод []= из Hash замещает или добавляет пары "ключ-значение" в сущест-
вующий хэш. Например:
rhode__island = { 1 => "Bristol", 2 => "Kent", 3 => "Newport",
4 => "Providence", 5 => "Washington" }

Между прочим, в этом хэше в качестве ключей указаны целые числа, подоб-
но тому, как индексируется массив, но в нем не используется 0, который
в массиве является первым индексом.
Для добавления пары можно применить метод []=:
rhode_island[6]= "Dunthorpe"

Добавилось значение "Dunthorpe" с ключом 6. Или методом []= можно


пользоваться для изменения значения:
rhode_island[2]= "Bent"

Значение, связанное с ключом 2, изменилось на "Bent". Аналогично, чтобы


добавить в rhode_island пару, можно применить метод store:
rhode_island.store(6, "Dunthorpe")

Объединяем хэши
В дополнение к rhode_island у нас есть хэш, перечисляющий графства
в Делавэре. Их только три:
delaware = { 1 => "Kent", 2 => "New Castle", 3 => "Sussex" }
Взгляните еще раз на хэш Род-Айленда:
rhode_island = { 1 => "Bristol", 2 => "Kent", 3 => "Newport",
4 => "Providence", 5 => "Washington" }

Метод merge объединяет два хэша вместе, производя копию, из которой уда-
лены двойные ключи путем перезаписи пар "ключ-значение" в принимающем
хэше. Чтобы понять, о чем я тут говорил, выполните пример:
rhode_island.merge delaware
# => { 5 => "Washington", 1 => "Kent", 2 => "New Castle",
# 3 => "Sussex", 4 => "Providence"}
146 Глава 7

Видите, что получилось в результате? Ключи и значения из delaware пере-


хватили пары с такими же ключами в rhode_island, заставив Bristol, Kent
и Newport исчезнуть.
Можно улучшить отбор, применяя merge с блоком:
rhode_island.merge( delaware ){|key,old,new| new = old + "_new" }
# => { 5 => "Washington", 1 => "Bristol_new", 2 => "Kent_new",
# 3 => "Newport_new", 4 => "Providence" }

Метод merge! выполняет изменения по месту для хэша, указанного в первом


параметре. Он также работает с блоком; и у него есть синоним — update.

Сортируем хэш
Если вы сортируете хэш методом sort, то получаете взамен многомерный
массив двухэлементных массивов. Помните, что когда вы создаете хэш, пары
"ключ-значение" хранятся не в том порядке, в котором они были добавлены.
Ruby, скорее всего, упорядочит их по-своему, потому что он обращается
к значениям и извлекает их по ключам, а не последовательно, как это делает-
ся с массивами. Так что порядок не важен для хэша. Но, возможно, важен для
вас. Если это так, попробуйте sort:
rhode_island = { 1 => "Bristol", 2 => "Kent", 3 => "Newport",
4 => "Providence", 5 => "Washington" }
p rhode_island # => {5 => "Washington", 1 => "Bristol", 2 => "Kent",
# 3 => "Newport", 4 => "Providence"}
rhode_island.sort # => [[1, "Bristol"], [2, "Kent"], [3, "Newport"],
# [4, "Providence"], [5, "Washington"]]

В классе Hash метода sort! для замены содержимого хэша по месту не суще-
ствует.

Удаляем и очищаем хэш


Уничтожить пару "ключ-значение" в хэше можно при помощи метода
delete. Метод delete использует ключ для поиска пары, а затем уничтожает
ее. Вернемся к нашему хэшу для Род-Айленда:
rhode_island = { 1 => "Bristol", 2 => "Kent", 3 => "Newport",
4 => "Providence", 5 => "Washington" }

Я уничтожу пару, обозначенную ключом 5:


rhode_island.delete( 5 ) # => "Washington"
Хэши 147

Теперь, если вы снова посмотрите на хэш, то увидите, что уничтожавшейся


пары в нем больше нет.
p rhode_island
# => { 1 => "Bristol", 2 => "Kent", 3 => "Newport", 4 => "Providence"}

При вызове delete можно передать блок. Если ключ, который вы хотите
уничтожить, не найден, то выполняется блок, и его значение возвращается
методом delete.
rhode_island.delete( 6 ) { |key| puts "not found, bubba" }

Метод delete_if также использует блок, но по-другому. Он удаляет из хэша


пары "ключ-значение", для которых блок вычисляет значение true. Восста-
новим хэш Род-Айленд:
rhode_island = { 1 => "Bristol", 2 => "Kent", 3 => "Newport",
4 => "Providence", 5 => "Washington" }

С помощью delete_if я удалю все пары "ключ-значение", ключ у которых


меньше 3:
rhode_island.delete_if { |key, value| key < 3 }
# => {5 => "Washington", 3 => "Newport", 4 => "Providence"}

Метод delete_if передает в блок всю пару, так что вы можете выполнить
уничтожение, основываясь или на ключе, или на значении. Вот пример унич-
тожения, основанного на значении:
rhode_island.delete_if { |key, value| value == "Kent" }
# => { 5 => "Washington", 1 => "Bristol", 3 => "Newport",
# 4 => Providence"}

Из хэша была удалена пара "ключ-значение" 2 => "Kent".


Метод reject из Hash работает совсем как delete_if, но возвращает копию
хэша без указанной пары и в действительности не меняет оригинал. Метод
reject! выполняет свои изменения по месту и является эквивалентом
delete_if.
Может быть, вы хотите почувствовать себя безжалостным. Вам поможет ме-
тод clear. Он удаляет из хэша все пары "ключ-значение", оставляя его пус-
тым:
counties = { "Delaware" => 3, "Rhode Island" => 5 }
counties.clear # bye-bye
counties.empty? # => true

Используйте clear на свой собственный страх и риск!


148 Глава 7

Замещаем хэш
Для того чтобы полностью заменить содержимое хэша, применяйте метод
replace. В этом примере содержимое хэша counties замещается содержи-
мым temp:
temp = {"Delaware" => 3 }
counties.replace( temp )

Можно проделать это, так сказать, анонимно:


counties.replace( { "Delaware" => 3 } )

Преобразуем хэш в другие классы


Можно преобразовать хэш в массив при помощи to_a. Предположим, что
у вас есть хэш, в котором содержится несколько романов, написанных Скот-
том Фитцджеральдом (F. Scott Fitzgerald, не имею никакого отношения):
fitzgerald = { 1920 => "This Side of Paradise",
1925 => "The Great Gatsby", 1934 => "Tender Is the Night" }

Вы можете преобразовать его в массив методом to_a, вот так:


fitzgerald.to_a
# => [[1925, "The Great Gatsby"],
# [1920, "This Side of Paradise"], [1934, "Tender Is the Night"]]

Метод to_a преобразовал хэш в многомерный массив, где каждая пара


"ключ-значение" является двухэлементным массивом внутри массива.
Вы также можете преобразовать этот хэш в строку методом to_s:
novels = fitzgerald.to_s
# => "1925The Great Gatsby1920This Side of
# Paradisel934Tender Is the Night"

Н-да. Это безобразие. Давайте почистим ее немного при помощи функции


gsub:
novels.gsub(/\d{4}/, " " ) { |token] print token }
# => " The Great Gatsby This Side of Paradise Tender Is the Night"

Когда вы преобразуете хэш в хэш (сам в себя) с помощью to_hash, вам мо-
жет показаться, что не произошло ничего особенного, но вы получите свою
выгоду.
fitz = fitzgerald.to_hash
# => { 1925 => "The Great Gatsby",
Хэши 149

# 1920 => "This Side of Paradise", 1934 => "Tender Is the Night"}
fitz.object_id # => 1745050
fitzgerald.object_id # => 1745050

Обратите внимание на то, что и fitz и fitzgerald имеют один и тот же


идентификатор объекта, равный 1745050, но с разными именами.

Версия 1.9 и выше


В версии 1.9 в классе Hash произойдут следующие изменения:
 результаты работы inspect и to_s в Hash будут одинаковы;
 будут добавлены два метода экземпляра класса — compare_by_identity
и compare_by_identity?. С помощью compare_by_identity класс Hash
сможет сравнивать ключи на идентичность — другими словами, с помо-
щью equal? вместо eql?; метод compare_by_identity? возвращает true,
если хэш сравнивает свои ключи на идентичность.

Другие методы класса Hash


Для получения дополнительной информации по классу Hash наберите в команд-
ной строке:
ri Hash

Для получения информации по методам класса наберите:


ri Hash::new

или:
ri Hash::[]

Для получения дополнительной информации по методам экземпляра класса


наберите нечто вроде этого:
ri Hash.keys

или:
ri Hash#keys

ri работает только в том случае, если при инсталляции Ruby вы установили


также документацию (см. разд. "Установка Ruby" главы 1). Если документа-
ция по Ruby не установлена локально на вашем компьютере, то вы сможете
отыскать любые методы класса Hash в онлайн-режиме на http://ruby-
doc.org/core/classes/Hash.html.
150 Глава 7

Вопросы для самопроверки


1. В чем разница между хэшем и массивом?
2. Когда хэш более предпочтителен, чем массив?
3. Как бы вы проверили, есть ли в хэше заданный ключ или заданное зна-
чение?
4. На каком другом классе основывается класс Hash?
5. Чем выгодно преобразование хэша в хэш?
6. В чем разница между has_key? и key??
7. Покажите, как создать хэш с помощью метода [] из Hash.
8. Что получается в результате сортировки хэша?
Глава 8

Работа с файлами

Из программ, написанных на Ruby, можно управлять каталогами файлов


(папками) при помощи методов классов Dir и File. Существуют и другие
родственные классы, такие как FileUtils, с множеством интересных мето-
дов, но мы сфокусируем свое внимание на методах из Dir и File.
Большая часть методов, которые я собираюсь вам показать, это методы класса,
т. е. имени метода предшествует имя класса, как в File.open и File::open
(для разделения имен класса и метода можно использовать или . или ::).
В Ruby существует множество глобальных констант (полный список см. в при-
ложении 1). Глобальные константы, наиважнейшие при работе с файлами, —
это ARGV (или $*) и ARGF (или $<). Подобно @ARGV из языка Perl, ARGV из Ruby
является массивом, в котором содержатся все параметры командной строки,
передаваемые программе. ARGF обеспечивает схожий с вводом/выводом поток,
организующий санкционированный доступ к виртуальной конкатенации всех
файлов, представленных в командной строке, или к стандартному вводу, если
файлы не указаны. Далее в этой главе я продемонстрирую и ARGV и ARGF.
Начнем работу с каталогов.

Каталоги
Перемещаться по структуре каталогов своего компьютера вы сможете с по-
мощью методов из класса Dir. Здесь я выделю три метода: Dir.pwd,
Dir.chdir (или Dir.getwd) и Dir.mkdir.
Прежде всего, я сменю каталог (использую абсолютный путь доступа), а за-
тем сохраню в переменной значение пути к каталогу.
Dir.chdir( "/Users/mikejfz" )
home = Dir.pwd # => "/Users/mikejfz/"
p home # => "/Users/mikejfz"
152 Глава 8

Сравним переменную, хранящую путь к каталогу, с текущим каталогом:


ruby_progs = "/Users/mikejfz/Desktop/Ruby"
if not Dir.pwd == ruby_progs
Dir.chdir ruby_progs
end

Если вам необходим каталог, создайте его при помощи mkdir; впоследствии
удалите его при помощи rmdir (или delete, это тезка rmdir):
Dir.mkdir( "/Users/mikejfz/sandbox" )
Dir.rmdlr( "/Users/mikejfz/sandbox" )

С помощью mkdir можно установить права доступа на новый каталог (но не


на существующий каталог):
Dir.mkdir( "/Users/mikejfz/sandbox", 755 )

755 означает, что владелец или пользователь каталога может читать из него,
писать в него и исполнять программы; группа может читать из каталога
и исполнять программы; и все остальные могут читать и исполнять програм-
мы (см. табл. 8.2).

Заглянем в каталог
Метод entries класса Dir возвращает массив, который содержит все элемен-
ты, найденные в каталоге, включая файлы, скрытые файлы и другие катало-
ги, по одному элементу массива на элемент каталога. Я применил метод each
из Array к результату работы entries:
Dir.entries( "/usr/local/src/ruby-1.8.6" ).each { |e| puts e }

Начало вывода данных этой команды выглядит вот так:


.
..
.cvsignore
.document
.ext
.rbconfig.time
array.с
array.о
bcc32
bignum.c
bignum.o
...
Работа с файлами 153

То же самое можно проделать при помощи foreach из Dir:


Dir.foreach( "/usr/local/src/ruby-1.8.6" ) { |e| puts e }

Поток каталога
Можно открыть поток каталога и оглядеться в нем с помощью некоторых
методов экземпляра класса Dir. Метод класса open (или new) открывает поток
каталога на заданном каталоге. path сообщает путь потока. tell возвращает
текущий элемент. read читает из dir следующий доступный элемент. rewind
возвращает вас к началу потока. each выполняет итерирование по каждому
элементу в dir.
dir = Dir.open( "/usr/local/src/ruby-1.8.6" ) # => #<Dir:0x1cd784>
dir.path # => "/usr/local/src/ruby-1.8.6"
dir.tell # => "."
dir.read # => 1
dir.tell # => ".."
dir.rewind # => перемотка в начало
dir.each { |e| puts e } # печатает каждый элемент dir
dir.close # => закрывает поток

Создаем новый файл


Чтобы создать новый файл и одновременно открыть его, примените метод
new из класса File:
file = File.new( "file.rb", "w" ) # => # <File:file.rb>

Первый параметр дает имя первому файлу, а второй параметр определяет


режимный код файла: r — файл предназначен для чтения, w — перезаписы-
ваемый файл, а x — исполняемый файл.
В табл. 8.1 дано описание различных режимов.

Таблица 8.1. Режимный код файла

Режим Описание
r Только для чтения. Стартует с начала файла (режим по умолчанию)
r+ Чтение/запись. Стартует с начала файла
w Только для записи. Усекает существующий файл до нулевой длины или
создает новый файл для записи
w+ Чтение/запись. Усекает существующий файл до нулевой длины или соз-
дает новый файл для чтения и записи
154 Глава 8

Таблица 8.1 (окончание)

Режим Описание
a Только для записи. Стартует с конца файла, если файл существует;
в противном случае, создает новый файл для записи
a+ Чтение/запись. Стартует с конца файла, если файл существует;
в противном случае, создает новый файл для чтения и записи
b (Только для DOS/Windows.) Режим двоичного файла. Может появляться
с любыми ключевыми символами, перечисленными выше

ЗАМЕЧАНИЕ
Можно также создавать файлы при помощи new с флажками и битами
полномочий. Дополнительную информацию ищите на
http://www.ruby-doc.org/core/classes/File.html.

Открываем существующий файл


Существующий файл открывают с помощью метода open. В примере 8.1 от-
крывается файл sonnet_129.txt (он поступает вместе с архивом кода), каждая
его строка печатается методом each с блоком, затем файл закрывается мето-
дом close. (Кстати, можно воспользоваться методом file.closed?, чтобы
проверить, закрыт ли файл. Метод возвращает true или false.)

Пример 8.1. open.rb

file = File.open( "sonnet_129.txt" )


file.each { |line| print "#{file.lineno}. ", line }
file.close

С помощью синтаксиса подстановки выражений, т. е. #{file.lineno}, в вы-


ходные данные вставляется номер строки, за которым следует сама строка
из файла.

ЗАМЕЧАНИЕ
Методы open, each и close все из класса IO, а не File. См. разд.
"Класс IO" далее в этой главе.

Выходные данные:
1. The expense of spirit in a waste of shame
2. Is lust in action: and till action, lust
Работа с файлами 155

3. Is perjured, murderous, bloody, full of blame,


4. Savage, extreme, rude, cruel, not to trust;
5. Enjoyed no sooner but despised straight;
6. Past reason hunted; and no sooner had,
7. Past reason hated, as a swallowed bait,
8. On purpose laid to make the taker mad.
9. Mad in pursuit and in possession so;
10. Had, having, and in quest to have extreme;
11. A bliss in proof and proved, a very woe;
12. Before, a joy proposed; behind a dream.
13. All this the world well knows; yet none knows well
14. To shun the heaven that leads men to this hell.

В open.rb я воспользовался методом print, т. к. символ конца строки уже


присутствует в конце каждой строки файла.

ARGV и ARGF
Другой интересный способ организовать то же самое мероприятие состоит
в применении ARGV и всего лишь двух строк кода (пример 8.2).

Пример 8.2. argv.rb

ARGV << "sonnet_129.txt"


print while gets

Как это работает? Напомню, что ARGV (или $*) — это массив, и каждый его
элемент является именем файла, представленного в командной строке —
обычно. Но в этом случае мы добавили имя файла непосредственно к ARGV при
помощи <<, метода из Array. Ловко. Вы можете применять к ARGV любой метод,
который можно применить к любому другому массиву. Попробуйте вот это:
p ARGV # => ["sonnet_119.txt"]

или это:
ARGV#[0] # => ["sonnet_119.txt"]

Метод gets из Kernel извлекает строки из ARGV и до тех пор, пока gets воз-
вращает строку, эта строка печатается методом print. Таким образом, код
в примере выводит:
Let me not to the marriage of true minds
Admit impediments. Love is not love
Which alters when it alteration finds,
156 Глава 8

Or bends with the remover to remove:


O no! it is an ever-fixed mark,
That looks on tempests and is never shaken;
It is the star to every wandering bark,
Whose worth's unknown, although his height be taken.
Love's not Time's fool, though rosy lips and cheeks
Within his bending sickle's compass come;
Love alters not with his brief hours and weeks,
But bears it out even to the edge of doom.
If this be error and upon me proved,
I never writ, nor no man ever loved.

ARGF ($<) является, еще раз напомню, виртуальной конкатенацией всех фай-
лов, появившихся в командной строке. Сравните программу argf.rb из приме-
ра 8.3 с argv.rb.

Пример 8.3. argf.rb

while line = ARGF.gets


print line
end

Пока есть строка, которую можно извлечь из файлов, указанных в командной


строке, программа argf.rb печатает эту строку через стандартное устройство
вывода. Чтобы посмотреть, как программа работает, выполните ее, указав
в командной строке три файла:
$ argf.rb sonnet_29.txt sonnet_119.txt sonnet_129.txt

Все файлы будут распечатаны на дисплее, по одной строке.

Открываем URI
Этот вопрос напрямую не связан с классом File, но я думаю, что и такой
связи достаточно, и он вызовет неподдельный интерес у некоторых из вас.
(Я должен поблагодарить Райана Уолдрона (Ryan Waldron) за то, что он об-
ратил на него мое внимание. Спасибо, Райан.)
Питер Сцинек (Peter Szinek) написал блог, где использовал Ruby для выпол-
нения "зачистки" (scraping — анализ и обработка экранных данных для из-
влечения интерфейсной информации) экрана. Он — создатель scRubyt, на-
бора инструментальных средств (web scraping toolkit), написанного на Ruby
(см. http://www.scrubyt.org). Я позаимствовал его самый простой пример
(пример 8.4), чтобы дать вам некоторое представление о том, как это работает.
Работа с файлами 157

Пример 8.4. scrape.rb

require 'open-uri'
url = "http://www.google.com/search?q=ruby"
open(url) { |page| page_content = page.read()
links = page_content.scan(/<a class=l.*?href=\"(.*?)\"/).flatten
links.each {|link| puts link}
}

Не вникая во множество деталей, сообщу, что scrape.rb использует встроен-


ный класс OpenURI (http:// www.ruby-doc.org/core/classes/OpenURI.html),
чтобы открыть URI запроса по Ruby в Google. URI читается и сканируется
при помощи регулярного выражения в поиске значения атрибута href по
элементам a (якоря). Эти совпавшие элементы сохраняются в переменной
links, и для итерирования по ним используется метод each. Вот выходные
данные, группа ссылок на ресурсы Ruby:
http://www.ruby-lang.org/
http://www.rubyonrails.org/
http://www.rubycentral.com/
http://www.rubycentral.com/book/
http://en.wikipedia.org/wiki/Ruby_programming_language
http://en.wikipedia.org/wiki/Ruby
http://www.w3.org/TR/ruby/
http://poignantguide.net/
http://www.zenspider.com/Languages/Ruby/OuickRef.html
http://www.rubys.com/

Попробуйте изменить значение ruby в q=ruby на какое-нибудь другое инте-


ресующее вас значение и посмотрите, что получится. Полную информацию
о "зачистке" экрана при помощи Ruby ищите в блоге Питера Сцинека на
http://www.rubyrailways.com/data-extraction-for-web-20-screen-scraping-
in-rubyrails.

Удаляем и переименовываем файлы


При помощи Ruby можно переименовывать и удалять файлы программно,
применяя методы rename и delete. Наберите эти строки в irb:
File.new( "books.txt", "w" )
File.rename( "books.txt", "chaps.txt" )
File.delete( "chaps.txt" )
158 Глава 8

Файловые запросы
С помощью методов из File можно выполнять любые файловые запросы.
Проверки такого типа часто выполняются перед другими файловыми про-
цедурами. Например, приведенная далее команда проверяет, существует ли
файл, перед тем, как открывать его:
File::open("file.rb") if File::exists?( "file.rb" )

Вы также можете проверить, существует ли файл, с помощью exist? (один


файл), синонима exists?. Запросите, является ли файл действительно фай-
лом с помощью file?:
File.file?( "sonnet_29.txt" ) # => true

Или выясните, каталог ли это, методом directory?:


# попробуйте с каталогом
File::directory?( "/usr/local/bin" ) # => true
# попробуйте с файлом... Опа
File::directory?( "file.rb" ) # => false

Проверьте, предназначен ли файл для чтения при помощи readable?, можно


ли его перезаписать при помощи writable?, и исполняемый ли он при помо-
щи executable?:
File.readable?( "sonnet_119.txt" ) # => true
File.writable?( "sonnet_119.txt" ) # => true
File.executable?( "sonnet_119.txt" ) # => false

Можно выяснить, имеет ли файл нулевую длину (0) при помощи zero?:
system("touch chap.txt") # Создайте файл нулевой длины с помощью
# команды system
File.zero?( "chap.txt" ) # => true

Получите длину файла в байтах с помощью size? или size:


File.size?( "sonnet_129.txt" ) # => 594
File.size( "sonnet_l29.txt" ) # => 594

И, наконец, запросите тип файла с помощью ftype:


File::ftype( "file.rb" ) # => "file"

Метод ftype определяет тип файла, возвращая один из следующих ответов:


file, directory, characterSpecial, blockSpecial, fifo, link, socket или
unknown.
Работа с файлами 159

Узнайте, когда файл был создан, модифицирован или когда к нему послед-
ний раз обращались, при помощи методов ctime, mtime и atime, соответст-
венно:
File::ctime( "file.rb" ) # => Wed Nov 08 10:06:37 -0700 2006
File::mtime( "file.rb" ) # => Wed Nov 08 10:44:44 -0700 2006
File::atime( "file.rb" ) # => Wed Nov 08 10:45:01 -0700 2006

Изменяем режимный код файла


и владельца
Чтобы изменить режимный код файла (права доступа или список доступа),
воспользуйтесь методом chmod с маской (список масок см. в табл. 8.2):
file = File.new( "books.txt", "w" )
file.chmod( 0755 )

или:
file = File.new( "books.txt", "w" ).chmod( 0755 )
system "ls -l books.txt"
# => -rwxr-xr-x 1 mikejfz mikejfz 0 Nov 8 22:13 books.txt

В предыдущем примере только владелец может записывать в файл, а все ос-


тальные могут читать или исполнять его. Сравните вот с этим:
file = File.new( "books.txt", "w" ).chmod( 0644 )
system "ls -l books.txt"
# => -rw-r--r-- 1 mikejfz tnikejfz 0 Nov 8 22:13 books.txt

Все могут читать файл, но только владелец может записывать в него, и никто
не может исполнять его.
Документацию по работе команды chmod в Mac OS X ищите на
http://www.hmug.org/man/2/chmod.php.

Таблица 8.2. Маски для chmod

Маска Описание
0700 Маска rwx для владельца
0400 r для владельца
0200 w для владельца
0100 x для владельца
160 Глава 8

Таблица 8.2 (окончание)

Маска Описание

0070 Маска rwx для группы


0040 r для группы
0020 w для группы
0010 x для группы
0007 Маска rwx для других
0004 r для других
0002 w для других
0001 x для других
4000 Установить идентификатор пользователя на исполнение
2000 Установить идентификатор группы на исполнение
1000 Сохранять подкачанный текст даже после использования

Можно изменить владельца или группу для файла методом chown, который
подобен команде chown в UNIX/Linux. Чтобы воспользоваться этим методом,
необходимы права привилегированного пользователя или root.
file = File.new( "books.txt", "r" )
file.chown( 109, 3333 )

или:
file = File.new( "books.txt", "r" ).chown( 109, 3333 )

Теперь выполним эту команду system (работает только в UNIX-подобных


системах), чтобы посмотреть на результат:
system "ls -l books.txt"
# => -rw-r--r-- 1 109 3333 0 Nov 8 11:38 books.txt

Класс IO
В Ruby основным классом для всего ввода и вывода является класс IO, кото-
рый представляет входные/выходные (I/O) потоки данных в форме байтов.
В стандартные потоки входят: стандартный входной поток ($stdin) с клавиа-
туры, стандартный выходной поток ($stdout) на дисплей и стандартный
Работа с файлами 161

выходной поток сообщений об ошибках ($stderr), который тоже выводится


по умолчанию на дисплей. IO тесно связан с классом File, и File является
единственным стандартным подклассом IO в Ruby. Я покажу вам образец
кода для организации ввода/вывода.
Чтобы создать новый поток ввода/вывода с именем ios, воспользуемся мето-
дом new. Первый параметр 1 — это числовой дескриптор файла для стан-
дартного ввода. Стандартный ввод может быть также представлен предопре-
деленной в языке Ruby переменной $stdin (табл. 8.3). Необязательный
второй параметр w является строкой режима и означает "write" (запись).
ios = IO.new( 1, "w" )
ios.puts "IO, IO, it's off to the computer lab I go."
$stdout.puts "Do you copy?"

Таблица 8.3. Стандартные потоки

Описание потока Дескриптор Предопределенная Переменная


файла переменная окружения
Ruby

Стандартный входной поток 0 $stdin STDIN


Стандартный выходной поток 1 $stdout STDOUT
Стандартный поток сообще- 2 $stderr STDERR
ний об ошибках

Другие строки режима включают: r — только для чтения (по умолчанию),


r+ — для чтения/записи и w — только для записи. Подробное описание всех
возможных режимов см. в табл. 8.4.

Таблица 8.4. Режимы ввода/вывода

Режим Описание
r Только для чтения. Стартует с начала файла (режим по умолчанию)
r+ Чтение/запись. Стартует с начала файла
w Только для записи. Усекает существующий файл до нулевой длины
или создает новый файл для записи
w+ Чтение/запись. Усекает существующий файл до нулевой длины или
создает новый файл для чтения и записи
a Только для записи. Стартует с конца файла, если файл существует,
в противном случае создает новый файл для записи
162 Глава 8

Таблица 8.4 (окончание)

Режим Описание
a+ Чтение/запись. Стартует с конца файла, если файл существует,
в противном случае создает новый файл для чтения и записи
b (Только для DOS/Windows.) Режим двоичного файла. Может появ-
ляться с любым из режимов, перечисленных в этой таблице

С помощью метода экземпляра класса fileno вы можете проверить, какой


числовой дескриптор файла установлен для вашего потока ввода/вывода
(to_i тоже работает).
ios.fileno # => 1
ios.to_i # => 1

$stdout.fileno # => 1

Вы можете также записать строки в поток (буфер) при помощи метода <<,
затем сбросить буфер методом flush.
ios << "Ask not " << "for whom the bells toll." << " -John Donne"
ios.flush # => Ask not for whom the bells toll. -John Donne

Теперь закройте поток с помощью close. При этом также сбрасываются лю-
бые ожидающие записи.
ios.close

Запишите символы в поток ввода-вывода с помощью putc и извлеките их


с помощью getc.
ios = IO.new( 1 )
ios.putc "M"
ios.putc "a"
ios.putc "t"
ios.putc "z"
ios.getc => Matz

Откройте поток файла, а затем извлеките каждую строку по очереди при


помощи метода gets из класса IO.
file = File.new( "sonnet_29.txt" )
file.gets # => "When in disgrace with fortune and men's eyes\n"
file.gets # => "I all alone beweep my outcast state,\n"
Работа с файлами 163

Или сделайте это методом readline. Метод readline слегка отличается от


gets, т. к. выставляет EOFError (End Of File Error; ошибка конца файла),
когда достигает конца файла.
file = File.new{ "sonnet_119.txt" )
file.readline # => "Let me not to the marriage of true minds\n"
file.readline # => "Admit impediments. Love is not love\n"
file.readline # => "Which alters when it alteration finds,\n"

Вопросы для самопроверки


1. Для чего пригодна константа ARGV?
2. Как бы вы с помощью Ruby получили тип файла для файла на диске?
3. Что маска 0700 делает с правами доступа к файлу?
4. Как бы вы получили доступ к дате и времени создания файла?
5. Какой тип объекта возвращает метод entries класса Dir?
164 Глава 8
Глава 9

Классы

А теперь я собираюсь довольно обстоятельно заняться классами. К этому


времени вы, конечно, знаете, что Ruby является языком объектно-
ориентированного программирования (ООП) и что центральным понятием
ООП является класс. Класс — это своеобразный контейнер, в котором со-
держатся методы и такая собственность, как переменные и константы (в со-
бирательном значении известные как члены класса). Одним из самых важных
моментов, касающихся классов, является их повторное применение, реали-
зующееся посредством механизма наследования.
Класс может унаследовать или породить характеристики другого класса. Это
значит, что дочерний класс или подкласс может унаследовать методы и дан-
ные родительского класса. Этот родительский класс также именуется супер-
классом. Цепь типа "родитель — потомок" формирует иерархию классов,
с базовым классом в корне, на вершине или в основании иерархии. В Ruby
базовым классом иерархии является класс Object.
Ruby поддерживает одиночное наследование, как в Java, не множественное
наследование, как в C++. В чем разница? При одиночном наследовании класс
может наследовать только от одного другого класса; при множественном на-
следовании класс может наследовать более чем от одного класса. Проблема
с множественным наследованием заключается в том, что оно поднимает во-
просы управления, такие как коллизия имен, т. е. когда классы, методы и пе-
ременные имеют одинаковые имена, но разное содержание. Многие про-
граммисты согласятся, что одиночное наследование менее склонно вызывать
головную боль и позволяет избежать коллизий и других проблем, связанных
с множественным наследованием; с другой стороны, они были бы не прочь
воспользоваться мощью множественного наследования.
Java реагирует на дилемму множественного наследования при помощи
интерфейса. Интерфейс в Java может определять абстрактные методы,
166 Глава 9

но не может реализовывать их; класс в Java может унаследовать интерфейс,


и затем реализовать его абстрактные методы. В Java также имеются абст-
рактные классы и абстрактные методы, которые могут быть унаследованы
и позднее реализованы.
Ruby также предлагает компромисс между одиночным и множественным на-
следованием — модули. Модули позволяют определять переменные, кон-
станты и методы, но вы не сможете применить их до тех пор, пока они не бу-
дут включены в класс. Вы можете включить в класс столько модулей,
сколько захотите, и когда Ruby столкнется с коллизией имен, то он будет ис-
пользовать самый свежий метод или переменную, определение которых было
сделано последним. Другими словами, в Ruby вы можете подменять методы
и переменные экземпляра.
Теперь, шаг за шагом, я покажу вам, как определять классы, методы и пере-
менные экземпляра класса, методы и переменные класса и как определять
модули и включать их в класс. Я также объясню, что значит "подменить ме-
тод" и что такое одноэлементный (singleton) метод.

Определяем класс
Класс определяется при помощи ключевого слова class, за которым следует
end. Идентификатор класса является константой, поэтому он должен начи-
наться с заглавной буквы (в норме), но он также может быть целиком состав-
лен из заглавных букв — Hello или HELLO вместо hello.
В примере 9.1 показан класс Hello, который вы видели в главе 1, теперь я
расскажу о нем подробнее.

Пример 9.1. hello.rb

class Hello
def initialize( name )
@name = name
end

def hello_matz
puts "Hello, " + @name + "!"
end

end

hi = Hello.new( "Matz" )
hi.hello_matz # => Hello, Matz!
Классы 167

Класс Hello определяется ключевым словом class с последующим end.


Метод initialize определяет переменную экземпляра класса @name путем
сохранения копии параметра name, передаваемого в метод initialize.
Метод initialize относится к соглашениям языка Ruby и действует подобно
конструктору классов других языков, но с некоторыми отличиями. К этому
моменту, экземпляр объекта класса уже полностью создан. Метод initialize
является первым кодом, который выполняется после того, как создан объект;
в initialize вы можете выполнить едва ли не любой код Ruby. Метод
initialize всегда частный; т. е. его область видимости относится только
к текущему объекту, не далее того.
Доступ к переменной экземпляра @name получают с помощью метода
hello_matz. Вопросы, касающиеся методов экземпляра класса, поднимаются
в следующих разделах.
Класс сам по себе является объектом, даже если вы непосредственно не соз-
давали его. Классы всегда открыты, поэтому вы можете дополнять любой
класс, даже встроенные классы, такие как String и Array. Можно открыть
класс Array и добавить в него метод, например, array_of_ten, как показано
в примере 9.2. Это свойство придает языку невероятную гибкость.

Пример 9.2. array_of_ten.rb

class Array
def array_of_ten
(1..10).to_a
end
end

arr = Array.new
ten = arr.array_of_ten
p ten # => [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

Переменные экземпляра
В Rubyland переменная экземпляра — это переменная, которая доступна из-
нутри экземпляра класса и ограничена областью видимости, потому что при-
надлежит данному объекту. Как уже упоминалось, имя переменной экземп-
ляра начинается с одного символа "коммерческое at" (@), как в:
@name = "Easy Jet"
168 Глава 9

Вы можете определить переменную экземпляра внутри метода или вне его.


Вы можете получить доступ к переменной экземпляра снаружи объекта толь-
ко через метод. (Вы можете, однако, получить доступ к переменной экземп-
ляра внутри объекта без метода.) Например, вы можете определить перемен-
ную экземпляра в классе вот так:
class Horse
@name = "Easy Jet"
end

Это работает, пока вы хотите обращаться к @name только изнутри объекта, но


этого, безусловно, недостаточно, если вы хотите получить доступ к ней сна-
ружи объекта. У вас не будет способа непосредственно извлечь значение
@name снаружи. Если вы попытаетесь получить доступ к @name через экземп-
ляр класса Horse — что-нибудь вроде horse.name — ваша попытка вызовет
генерацию ошибки. Чтобы извлечь значение, вы должны определить метод.
class Horse
def name
@name = "Easy Jet"
end
end

h = Horse.new
h.name # => "Easy Jet"

Метод name относится к тому виду методов, которые называют метод-


аксессор (accessor — средство доступа) или геттер (getter). Он получает
значение переменной из экземпляра класса.
Обычно, когда у вас есть геттер, вам хочется также иметь сеттер (setter) —
метод-аксессор, который устанавливает значение переменной. В этой версии
класса Horse добавляется такой метод и вам преподносится еще одно согла-
шение:
class Horse
def name
@name
end
def name=( value )
@name = value
end
Классы 169

end

h = Horse.new
h.name= "Poco Bueno"
h.name # => "Poco Bueno"

Сеттер name= следует принятому в Ruby соглашению: имя такого метода за-
канчивается знаком равенства (=). (Это соглашение не является требовани-
ем.) Вы можете назвать name= все, что угодно, раз уж используются допусти-
мые символы. Но это удобное соглашение, приятное на вид, потому что name
и name= выглядят, как бизнес-партнеры.
Вот еще одна версия класса Horse, которая инициализирует переменную эк-
земпляра @name с помощью стандартного метода initialize. Далее про-
грамма создает переменную экземпляра класса посредством вызова new и за-
тем получает доступ к переменной экземпляра при помощи метода-аксессора
horse_name, через экземпляр класса horse.
class Horse
def initialize( name )
@name = name
end

def horse_name
@name
end
end

horse = Horse.new( "Doc Bar" )


puts horse.horse_name # => Doc Bar

Как вы увидите далее, существует гораздо более простой способ написания


методов-аксессоров.

Аксессоры
Если вы знакомы с созданием классов в других языках программирования,
вы, без сомнения, создавали также методы-геттеры и методы-сеттеры. Эти
методы устанавливают и получают (возвращают) для класса значения. Ruby
упрощает создание геттеров и сеттеров с помощью капельки метапрограм-
мирования и методов attr, attr_reader, attr_writer и attr_accessor из
класса Module. Метапрограммирование — это условное обозначение способа
170 Глава 9

писать программу или часть ее с помощью другой программы. Предоставив


метод attr, Ruby обеспечил возможность быстро создать эквивалент шести
строк кода из единственной строки.
Как показано в примере 9.3, метод attr создает метод-геттер, именем кото-
рого является символ, и необязательный метод-сеттер (если второй параметр
равен true).

Пример 9.3. dog.rb

#!/usr/bin/env ruby

class Dog
attr :bark, true
end

Dog.instance_methods - Object.instance_methods # => ["bark", "bark="]


dog = Dog.new
dog.bark = "Woof!"
puts dog.bark # => Woof!

При вызове attr с параметрами :bark и true класс Dog будет обладать мето-
дами экземпляра класса bark и bark=. Если бы вы вызвали attr с единствен-
ным параметром :bark, класс Dog обладал бы только методом bark. (Обрати-
те внимание на то, как вы можете вычесть методы экземпляра класса Object
при извлечении методов экземпляра класса Dog. Собственно, из-за таких ме-
леньких штучек Ruby мне и нравится.)
Единственная строка attr :bark, true является эквивалентом написания
методов bark и bark= в шести строках кода:
class Dog

def bark
@bark
end

def bark=(val)
@bark = val
end

end
Классы 171

Дополнительные сведения о метапрограммировании вы получите в разд.


"Метапрограммирование" главы 10.
Метод attr_reader автоматически создает одну или несколько переменных
экземпляра с соответствующими методами, которые возвращают (берут) зна-
чения каждого метода. Метод attr_writer автоматически создает одну или
несколько переменных экземпляра с соответствующими методами, которые
устанавливают значения каждого метода. Указанные методы вызываются
в примере 9.4. В нем создается геттер и соответствующий ему сеттер.

Пример 9.4. dogs.rb

class Dog
attr_reader :bark
attr_writer :bark
end

dog = Dog.new

dog.bark="Woof!"
puts dog.bark # => Woof!

dog.instance_variables.sort # => ["@bark"]


Dog.instance_methods.sort - Object.instance_methods
# => [ "bark", "bark=" ]

Как показано в примере 9.5, метод attr_accessor выполняет для одного или
более методов экземпляра класса ту же самую работу, что и методы
attr_reader и attr_writer вместе взятые.

Пример 9.5. gaits.rb

#!/usr/bin/env ruby
class Gaits
attr_accessor :walk, :trot, :canter
end

Gaits.instance_methods.sort - Object.instance_methods
# => ["canter", "canter=", "trot", "trot=", "walk", "walk="]

Метапрограммирование в Ruby при создании геттеров и сеттеров сильно об-


легчает жизнь.
172 Глава 9

Переменные класса
В Ruby переменная класса поделена между всеми экземплярами класса, так
что для данного класса существует только одна копия переменной класса.
В Ruby имя переменной класса начинается двумя "коммерческими at" (@@).
Вы обязаны проинициализировать атрибут класса перед использованием:
@@times = 0

Класс Repeat, показанный в примере 9.6, использует переменную класса


@@total. Программа три раза создает экземпляр класса, вызывает метод
repeat для каждого экземпляра и получает доступ к значению @@total также
для каждого экземпляра. Обратите внимание на то, как значение, хранящееся
в @@total, распределялось между экземплярами.

Пример 9.6. repeat.rb

class Repeat
@@total = 0
def initialize( string, times )
@string = string
@times = times
end
def repeat
@@total += @times
return @string * @times
end
def total
"Total times, so far: " + @@total.to_s
end
end

data = Repeat.new( "ack ", 8 )


ditto = Repeat.new( "Again! ", 5 )
ditty = Repeat.new( "Rinse. Lather. Repeat. ", 2 )

puts data.repeat # => ack ack ack ack ack ack ack ack
puts data.total # => Total times, so far: 8

puts ditto.repeat # => Again! Again! Again! Again! Again!


Классы 173

puts ditto.total # => Total times, so far: 13

puts ditty.repeat # => Rinse. Lather. Repeat. Rinse. Lather. Repeat.


puts ditty.total # => Total times, so far: 15

Методы класса
Метод класса — это метод, который ассоциируется с классом (а в Ruby
и с модулем), а не с экземпляром класса. Активизировать методы класса
можно, указав имя метода вместе с именем класса, которому он принадле-
жит. Методы класса известны также как статические методы.
В Ruby вы можете к тому же связать с именем метода имя модуля, как в слу-
чае класса, но чтобы воспользоваться таким методом, вы обязаны включить
модуль в класс. В этой строке имени метода sqrt предшествует имя модуля
Math, о котором вы читали в главе 5.
Math.sqrt(36) # => 6.0

Чтобы определить метод класса, надо попросту писать в определении метода


перед именем метода имя класса или модуля. В примере 9.7 площадь прямо-
угольника вычисляется при помощи Area.rect, метода класса.

Пример 9.7. area.rb

class Area
def Area.rect( length, width, units="inches" )
area = length*width
printf( "The area of this rectangle is %.2f %s.", area, units )
sprintf( "%.2f", area )
end
end

Area.rect(12.5, 16) # The area of this rectangle is 200.00 inches.


=> "200.00"

Одноэлементные классы
Можно также определять методы класса путем использования класса внутри
класса — одноэлементного (singleton) класса — как в коде примера 9.8.
174 Глава 9

Пример 9.8. area_singleton.rb

class Area

class << self

def rect( length, width, units="inches" )


area = length*width
printf( "The area of this rectangle is %.2f %s.", area, units )
sprintf( "%.2f", area )
end

end

end

Area.rect(10, 10) # The area of this rectangle is 100.00 inches.


=> "100.00"

В этой форме вам не нужно в определении указывать перед именем метода


имя класса. Одноэлементный класс привязан к отдельному объекту, его эк-
земпляр может быть создан единственный раз, и он не отличается префиксом
имени.
Метод rect, в сущности, также является методом одноэлементного класса,
потому что он связан с одноэлементным классом. Далее приведен способ оп-
ределения метода одноэлементного класса — в этом случае метод связан
с единственным объектом:
class Singleton
end

s = Singleton.new
def s.handle
puts "I'm a singleton method!"
end

s.handle # => I'm a singleton method!

Одноэлементные шаблоны проектирования пришли из книги "Design Patterns:


Elements of Reusable Object-Oriented Software", которую написали Эрих Гамма
Классы 175

(Erich Gamma), Ричард Хелм (Richard Helm), Ральф Джонсон (Ralph Johnson)
и Джон Влисайдс (John Vlissides), известные как "Gang of Four" (Addison-
Wesley). В общем, одноэлементный класс спроектирован таким образом,
чтобы процесс создания экземпляра для него мог осуществляться один-
единственный раз. Такой класс часто используется как глобальная пере-
менная. В Ruby также имеется класс для определения одноэлементных объ-
ектов (см. http://www.ruby-doc.org/core/classes/Singleton.html).

Наследование
В Ruby поддерживается одиночное наследование, что означает, что класс мо-
жет наследовать только от одного класса — родительского класса или супер-
класса. Когда дочерний класс становится наследником или порождается из
родительского класса, он получает доступ к методам и собственности роди-
теля. Наследование совершается с помощью оператора <.
Как упоминалось ранее, в Ruby не поддерживается множественное наследо-
вание, которое позволяет классу наследовать более чем от одного класса и,
следовательно, иметь доступ к функциональным возможностям нескольких
классов. Одна из проблем множественного наследования состоит в том, что
некоторые описания классов, методов и собственности могут конфликтовать
между собой; например, два класса могут иметь одно и то же имя, но нести
совершенно разное содержание. Существуют простые причины, по которым
множественное наследование может быть удобным, но есть и более сложные
причины, по которым оно может стать головной болью. Ruby управляется
с такой проблемой при помощи модулей и смешивания (mixins), о которых
вы прочтете в следующем разделе.
Пример 9.9 является демонстрацией простого единичного наследования. До-
черний класс Address наследует (<) методы и собственность (переменные
экземпляра) от класса Name, родителя. Метод respond_to? проверяет, имеет
ли экземпляр класса Address доступ к переменной :given_name, унаследо-
ванной от класса Name. И получает ответ "да" (true).

Пример 9.9. inherit.rb

#!/usr/bin/env ruby

class Name
attr_accessor :given_name, :family_name
176 Глава 9

end

class Address < Name


attr_accessor :street, :city, :state, :country
end

a = Address.new
puts a.respond_to?(:given_name) # => true

Если бы класс Name находился в отдельном файле, вам пришлось бы сначала


затребовать (require) этот файл, и тогда операция наследования сработала
бы правильно, как можно видеть в примерах 9.10 и 9.11. (Метод require
в address.rb подразумевает, что name.rb можно найти по пути загрузки.)

Пример 9.10. name.rb

class Name
attr_accessor :given_name, :family_name
end

Пример 9.11. address.rb

#!/usr/bin/env ruby
require 'name'

class Address < Name


attr_accessor :street, :city, :state, :country
end

a = Address.new
puts a.respond_to?(:given_name)

ЗАМЕЧАНИЕ
Что такое путь загрузки? Системный путь — это не совсем то же самое,
что путь Ruby или путь загрузки. В чем разница? Вот несколько подска-
зок. В Ruby есть предопределенная переменная с именем $LOAD_PATH
(у которой также есть синоним $:, как в языке Perl). $LOAD_PATH пред-
ставляет собой массив, в котором содержатся имена каталогов и в
котором при загрузке файлов производят поиск методы load и require.
Наберите $LOAD_PATH в irb, чтобы посмотреть на содержимое масси-
ва. Ruby может также задействовать переменные окружения PATH
и RUBYPATH (если последняя установлена). PATH является системным
Классы 177

путем и среди прочего действует для программ Ruby как траектория


поиска; RUBYPATH может быть такой же самой, как PATH, но т. к. она
имеет более высокий приоритет, чем PATH, то она, вероятно, содержит
и дру-гие каталоги, помимо тех, что в PATH (см. табл. П1.4 и П1.5).

Модули
В дополнение к классам в Ruby имеются также модули. Модуль подобен
классу, но для него нельзя создать экземпляр, как для класса. Чем он удобен?
Итак, класс может включать модуль, так что когда для класса создается эк-
земпляр, он получает собственность включенного модуля. Методы из вклю-
ченного модуля становятся методами экземпляра класса в классе, который
включает модуль. Это называется смешиванием, а на модуль ссылаются как
на mixin. Смешивание помогает преодолеть проблемы, проистекающие из
множественного наследования.
Модуль в Ruby является формой пространства имен. Пространство имен —
это множество имен, таких как имена методов, которые имеют область види-
мости или контекст. Модуль в Ruby связывает одно имя с набором имен ме-
тодов и констант. Имя модуля можно использовать в классах в других моду-
лях. Обычно областью видимости или контекстом такого пространства имен
является класс или модуль, в который включено пространство имен (имя мо-
дуля). Класс в Ruby тоже может рассматриваться как пространство имен.
Имя модуля должно быть константой, т. е. оно должно начинаться с заглав-
ной буквы. Модуль может содержать методы, константы, другие модули
и даже классы. Модуль может наследовать от другого модуля, но он не мо-
жет наследовать от класса. Так как класс может включать модуль, он может
также включать модули, которые унаследовали другие модули.
В коде примера 9.12 демонстрируется, как создать модуль (Dice), а затем
включить его в класс (Game). Метод roll доступен из экземпляра класса Game,
который называется g. (Метод rand из модуля Kernel генерирует псевдослу-
чайное число — между 0.0 и 1.0, если параметра нет, или между 0
и argument. Метод roll использует rand с небольшим коленцем, обеспечи-
вающим уверенность, что тот не вернет 0. Надо отметить, это не самый эф-
фективный способ гарантировать ненулевой результат, но он работает.)

Пример 9.12. mixin.rb

#!/usr/bin/env ruby

module Dice
178 Глава 9

# virtual roll of a pair of dice


def roll
r_1 = rand(6); r_2 = rand(6)
r1 = r_1>0?r_1:1; r2 = r_2>0?r_2:6
total = r1+r2
printf( "You rolled %d and %d (%d).\n", r1, r2, total )
total
end

end

class Game
include Dice
end

g = Game.new
g.roll

Если бы модуль был в отдельном файле (см. пример 9.13), аналогично слу-
чаю с классом, вам пришлось бы просто затребовать (require) файл, содер-
жащий модуль, чтобы он смог работать (и снова require ожидает, что имя
находится по пути загрузки).

Пример 9.13. dice.rb

module Dice

# virtual roll of a pair of dice


def roll
r_1 = rand(6); r_2 = rand(6)
r1 = r_1>0?r_1:1; r2 = r_2>0?r_2:6
total = r1+r2
printf( "You rolled %d and %d (%d).\n\ r1, r2, total )
total
end

end
Классы 179

Пример 9.14. game.rb

#!/usr/bin/env ruby

require 'dice'

class Game
include Dice
end

g = Game.new
g.roll

Когда вы определяете методы модуля, как делали это с методами класса, т. е.


указываете в качестве префикса имя модуля, вы можете вызвать метод отку-
да угодно, как в случае с модулем Math. В примере 9.15 показано, как при-
соединить префикс к методу модуля и как затем вызвать этот метод.

Пример 9.15. binary.rb

#!/usr/bin/env ruby
module Binary

def Binary.to_bin( num )


bin = sprintf("%08b", num)
end

end

Binary.to_bin( 123 ) # => "01111011"

Методы public, private и protected


Видимость или тип доступа методов и констант может быть установлен при
помощи методов public, private или protected.
 Член класса, отмеченный как public, доступен всем и отовсюду; это зна-
чение устанавливается по умолчанию.
 private означает, что получателем метода всегда является текущий объ-
ект или self, так что его областью видимости всегда является текущий
180 Глава 9

объект (часто это вспомогательные методы, т. е. методы, которые вызы-


ваются другими методами для выполнения некоторой работы).
 Метод, помеченный protected, может использоваться только экземпля-
рами класса, в котором он был определен, или порожденными классами.
Как показано в примере 9.16, методы можно пометить. Методы, следующие
за ключевыми словами private или protected, будут иметь указанную ви-
димость до тех пор, пока она не будет изменена или пока не закончится оп-
ределение.

Пример 9.16. access.rb

class Names

def initialize( given, family, nick, pet )


@given = given
@family = family
@nick = nick
@pet = pet
end

# эти методы по умолчанию имеют тип доступа public


def given
@given
end

def family
@family
end

# все нижеследующие методы имеют тип доступа private до тех пор,


# пока он не будет изменен
private
def nick
@nick
end

# все нижеследующие методы имеют тип доступа protected до тех пор,


# пока он не будет изменен
protected
def pet
Классы 181

@pet
end

end

name = Names.new( "Klyde", "Kimball", "Abner", "Teddy Bear" )

name.given # => "Klyde"


name.family # => "Kimball"

# посмотрите, что произойдет, когда вы вызовете nick или pet


name.nick
name.pet

При изменении доступа к методам, как в примере 9.16, вам придется опреде-
лить эти методы после применения методов public, private или protected.
Вы можете также вызвать методы после определения (для имени метода не-
обходимо использовать символ):
def pet
@pet
end

protected :pet

Вопросы для самопроверки


1. Да или нет: вы не можете добавлять методы или переменные во встроен-
ные классы.
2. Имени переменной экземпляра предшествует символ ______.
3. Что является отличительной характеристикой метода класса?
4. Да или нет: в Ruby даже класс является объектом.
5. Что такое одноэлементный метод, как его создать?
6. Можно ли создать экземпляр модуля?
7. В чем состоит основное различие между единичным и множественным
наследованием?
8. Какой класс в Ruby является базовым?
9. Какая видимость установлена по умолчанию для членов класса?
182 Глава 9
Глава 10

С Ruby не соскучишься

Настало время выйти за пределы основ и заняться исследованием некоторых


других пространств Ruby. Здесь вы узнаете, как пользоваться методом
sprintf для форматирования выходных данных, как обрабатывать или гене-
рировать XML с помощью REXML или XML Builder, как использовать ме-
тоды рефлексии, RubyGems, создавать документацию с помощью RDoc
и выполнять обработку некоторых ошибок. Вам даже придется заняться ме-
тапрограммированием и встраиваемым Ruby (ERB). Цель этой главы — уве-
личить в объеме ваши знания и расширить ваш опыт перед тем, как выпус-
тить вас на волю. После этой останется только глава 11.

Форматирование вывода с помощью sprintf


В модуле Kernel для создания отформатированных строк есть метод с име-
нем sprintf (у которого также есть синоним format). Если в вашей ДНК за-
ложено программирование на С, как у многих программистов, вы, вероятно,
захотите добраться до sprintf, чтобы он выполнял за вас всю рутинную ра-
боту по форматированию строки. Метод sprintf основывается на формати-
рующей строке, — включающей спецификаторы формата, каждому из кото-
рых предшествует % — которая указывает ему, как выполнить
форматирование строки. Предположим, что вы хотите вывести на печать
число 237 в двоичном формате. Введите вот это:
sprintf( "%b", 237 ) # => "11101101"

Спецификатор формата %b указывает, что вы хотите получить двоичный ре-


зультат. b — это тип поля для представления в двоичной системе счисления,
а параметр 237 — это число, которое вы хотите преобразовать в двоичное,
что sprintf делает весьма любезно. В действительности sprintf не выводит
возвращаемое значение на стандартное устройство вывода (экран); чтобы
184 Глава 10

увидеть результат, вам следует воспользоваться printf, еще одним методом


из модуля Kernel:
printf("%b", 237 ) # => 11101101

который почти идентичен:


$stdout.write(sprintf( "%b", 237 )) # => 11101101

write — метод класса IO, записывающий строку в открытый поток вво-


да/вывода, который по случаю задает $stdout, предопределенная переменная
для стандартного вывода (по умолчанию это ваш дисплей). Вы даже можете
воспользоваться puts (или print):
puts sprintf( "%b", 237 ) # => 11101101

Но я не буду. Я предпочитаю printf, а не $stdout.write или puts sprintf, —


он более элегантен.
Вы также можете присвоить возвращаемое значение переменной:
bin = sprintf("%b", 237)

Или могли бы указать переменную в качестве параметра:


to_bin = 237
sprintf("%b", to_bin) # => "11101101"

Результатом преобразования является симпатичная строка из восьми двоич-


ных цифр. А что, если вы переведете в двоичную систему счисления число
поменьше — скажем, 14:
sprintf("%b", 14) # => "1110"

Если вам нужны восемь цифр, вы должны это указать, плюс дополнить ре-
зультат нулями:
sprintf("%08b", 14) # => "00001110"

Выглядит лучше. К сведению, спецификатор формата всегда начинается со


знака процента (%), и за ним может следовать необязательный флажок, моди-
фицирующий выходные данные (см. в табл. 10.1 полный список флажков).
Флажок в этом спецификаторе формата, 0, указывает, что вы хотите запол-
нить или дополнить результат нулями вместо пробелов (задаваемых по умол-
чанию). Число 8 обозначает ширину результата (восемь цифр). (Вслед за ши-
риной может следовать индикатор точности. Подробнее о нем будет
рассказано дальше.) Строка заканчивается символом типа поля, например, b.
Символы типа поля управляют тем, как соответствующий параметр будет
представлен в выходных данных. Все символы типа поля см. в табл. 10.2.
С Ruby не соскучишься 185

Таблица 10.1. Флажки для sprintf

Флажок Для типов полей Описание


[пробел] bdeEfgGiouxX Помещает пробел в начало положительного числа
[1-9]$ Все типы полей Абсолютный номер параметра для этого поля
# beEfgGoxX Для поля b результату предшествует 0b; для o —
0; для x — 0x; для X — 0X; для e, E, f, g и G до-
бавляется десятичная точка; для g и G не удаля-
ются хвостовые пробелы
+ bdeEfgGiouxX Добавляет перед положительными числами знак
"плюс" (+)
- Все типы полей Выравнивает результат влево
0 bdeEfgGiouxX Дополняет результаты нулями (0) вместо пробелов
* Все типы полей Использует следующий параметр как ширину по-
ля. Если он отрицательный, выравнивает резуль-
тат влево. Если за звездочкой (*) следует число и
знак доллара ($), использует параметр как ширину

Таблица 10.2. Типы полей для sprintf

Поле Описание

b Преобразует числовой параметр в двоичное число


с Преобразует числовой параметр (код символа) в символ
d Преобразует числовой параметр в десятичное число. То же самое, что i
e Преобразует параметр с плавающей точкой в экспоненциальное пред-
ставление, с использованием одной цифры перед десятичной точкой. По
умолчанию в дробной части устанавливается шесть цифр (ср. с g)
E То же самое, что e, но в результате используется E
f Преобразует числовой параметр в число с плавающей точкой. По умолча-
нию в дробной части устанавливается шесть цифр. Количество цифр
дробной части определяется точностью

g Преобразует числовой параметр в число с плавающей точкой, использует


экспоненциальную форму, если экспонента меньше, чем –4, или больше
или равна точности, в противном случае использует форму d.dddd (ср. с e)
G То же самое, что g, но в результате используется E
i Преобразует числовой параметр в десятичное число. То же самое, что d
о Преобразует числовой параметр в восьмеричное число
186 Глава 10

Таблица 10.2 (окончание)

Поле Описание
p То же самое, что argument.inspect, где inspect предоставляет печа-
таемую версию параметра, с удаленными специальными символами
s Подставляет параметр как строку. Если форматирующая строка содержит
точность, то в подстановку копируется не менее указанного количества
символов
u Трактует параметр как десятичное число без знака. Отрицательные числа
для базовой архитектуры показываются как 32-битовое дополнение до
двух плюс единица (например, 2**32+n). Так как в Ruby нет собственного
лимита на количество битов, используемых для представления целого
числа, отрицательным значениям предшествуют две точки, обозначающие
бесконечное количество лидирующих знаковых битов
x Преобразует числовой параметр в шестнадцатеричное число со строчными
буквами от a до f. Отрицательные числа показываются с двумя предшест-
вующими точками, обозначающими бесконечную строку лидирующих ff

X То же самое, что x, но в результате используются заглавные буквы от A


до F. Отрицательные числа показываются с двумя предшествующими точ-
ками, обозначающими бесконечную строку лидирующих FF

Давайте сделаем из строки предложение и внедрим несколько спецификато-


ров формата.
sprintf("The integer %d is %08b in binary format.", 72, 72)
# => "The integer 72 is 01001000 in binary format."

Копируются все символы, которые не являются спецификаторами формата.


%d определяет в выходных данных десятичное число. Вызов sprintf включа-
ет два параметра (72, 72). Ожидаются два параметра, т. к. здесь имеются две
форматирующие строки, но эта информация избыточна. OK, удалим второй
параметр:
sprintf("The integer %d is %08b in binary format.", 72)
ArgumentError: too few arguments
# (Ошибка в параметрах: слишком мало параметров)
from (irb):25:in `sprintf'
from (irb):25
from :0

Не сработало. Мы должны дать знать методу sprintf, какие параметры хо-


тим использовать, тогда он будет счастлив.
sprintf("The integer %l$d is %1$08b in binary format.", 72)
# => "The integer 72 is 01001000 in binary format."
С Ruby не соскучишься 187

1$ дает методу понять, что вы хотите, чтобы он искал только первый пара-
метр.
Для числа с плавающей точкой используйте тип поля f. Приведенная далее
строка показывает сумму в долларах:
sprintf( "$%.2f", 100 ) # => "$100.00"

Индикатор точности состоит из точки, за которой следует число (.2 в этом


примере). Он следует за индикатором ширины, если тот используется (здесь
не используется). Индикатор точности контролирует число десятичных раз-
рядов после точки, показываемое в результате (два). Знак доллара в начале
форматирующей строки копируется беспрепятственно, и, таким образом, вы
получаете $100.00.
Тип поля x преобразует параметр в шестнадцатеричное значение.
sprintf( "%x", 30 ) # => "1e"

Для символов верхнего регистра в шестнадцатеричном значении укажите X.


sprintf( "%X", 30 ) # => "1E"

Чтобы шестнадцатеричному результату предшествовало 0x, добавьте символ


фунта или диез (#).
sprintf( "%#x", 256 ) # => "0x100"

Тип поля %o возвращает восьмеричное число. Чтобы восьмеричному резуль-


тату предшествовал 0, укажите символ фунта, как вы делали для шестнадца-
теричного числа.
sprintf( "%#o", 100 ) # => "0144"

Для подстановки в форматируемую строку строкового параметра, восполь-


зуйтесь %s.
sprintf( "Hello, %s", "Matz!" ) # => "Hello, Matz!"

Это все равно, что применять метод % из класса String, который был показан
в главе 1.
"Hello, %s" % "Matz!" # => "Hello, Matz!"

Можно также снабдить этот метод массивом:


birthdate = [ "November", 8, 2007 ]
p "He was born %s %d, %d." % birthdate

Можно вместо sprintf указывать % везде, где вам необходима форматирую-


щая строка.
188 Глава 10

Для строки индикатор точности устанавливает максимальное количество


символов, которые будут скопированы из строкового параметра. Здесь из
подставляемой строки разрешено выбрать только два символа:
sprintf( "Hello, %.2s", "Matz!" ) # => "Hello, Ma"

Обработка XML
Ruby отличается растущим количеством средств обработки XML (Extensible
Markup Language, расширяемый язык разметки гипертекста). Ruby Electric
XML (REXML) Шона Рассела (Sean Russell) встроен в Ruby и является оче-
видным выбором для обсуждения (http://www.germane-software.com/software/
rexml). А в Rails встроен Builder, так что мы обратим внимание и на него
(http://rubyforge.org/projects/builder).
Вот еще пара средств, которые я не буду вам показывать. Libxml-Ruby,
C-язычный Ruby, связанный с библиотекой libxml2 из GNOME, является ско-
ростным вариантом (см. http://libxml.rubyforge.org). Существует также
XmlSimple, трансляция средствами Ruby модуля XML::Simple для Perl
(http://xml-simple.rubyforge.org). XmlSimple требует REXML.
При последующем обсуждении предполагается, что вы уже знакомы с XML,
так что я не буду объяснять, что такое элементы, атрибуты и т. д. Я мог бы
рассказать вам многое, но я должен быть краток. Вы узнаете об обработке
XML достаточно, чтобы приподняться над толпой.

REXML
Так как REXML уже является частью Ruby, вы получаете его бесплатно.
В примере 10.1 показана небольшая программа, которая создает из докумен-
та "здесь и сейчас" документ на языке XML, а затем записывает его на стан-
дартное устройство вывода.

Пример 10.1. mondo.rb

#!/usr/bin/env ruby
require 'rexml/document'
include REXML
address = <<XML
<address>
<name><given>Mondo</given><family>Mangrove</family></name>
<street>9876 Trekker St.</street>
С Ruby не соскучишься 189

<city>Granola</city>
<state>Colorado</state>
<code>81000</code>
<country>USA</country>
</address>
XML

document = Document.new( address )


puts document

Вы должны затребовать rexml/document. Если вы включите пространство


имен REXML, то вам не придется указывать перед именем класса REXML (как
в REXML::Document). В строке address хранится документ "здесь и сейчас",
в котором содержится документ XML — адрес нашего хорошего друга
Mondo Mangrove. Класс Document из REXML представляет документ XML.
Я воспользовался puts, чтобы записать document на стандартное устройство
вывода.
<address>
<name><given>Mondo</given><family>Mangrove</family></name>
<street>9876 Trekker St.</street>
<city>Granola</city>
<state>Colorado</state>
<code>81000</code>
<country>USA</country>
</address>

Программа, показанная в примере 10.2, собирает документ XML из воздуха


и затем выводит на экран.

Пример 10.2. mangrove.rb

#!/usr/bin/env ruby

require 'rexml/document'
include REXML

document = Document.new
document << XMLDecl.new( "1.0", "UTF-8" )
document << Comment.new( "our good friend Mondo" )
190 Глава 10

document.add_element( "name", { "lang" => "en"})

given = document.root.add_element( "given" )


family = document.root.add_element( "family" )

given.add_attribute("nickname", "false")

given.text = "Mondo"
family.text = "Mangrove"

document.write( $stdout, 0 )

Document.new вызывается без каких бы то ни было параметров, т. к. эта про-


грамма создает файл XML по ходу дела. XMLDecl.new добавляет в документ
декларацию XML, которая появится вверху. Первый параметр представляет
собой информацию о версии (1.0); второй является описанием кодировки
(UTF-8). Без параметров XMLDecl.new создает по умолчанию базовую декла-
рацию XML (<?xml version='1.0' ?>).
Comment.new создает для вставки в документ комментарий с текстом "our
good friend Mondo".
Первый вызов метода add_element добавляет к документу имя корневого
элемента с атрибутом lang. Добавляются также элементы given и family,
и given с помощью add_attribute придается атрибут nickname. Метод text
добавляет к этим элементам текстовое содержание.
Метод write структурно распечатывает документ на стандартном устройстве
вывода (структурирование задается вторым параметром метода write). Бла-
годаря write, выходные данные выглядят так:
<?xml version='1.0' encoding='UTF-8'?>
<!--our good friend Mondo
-->
<name lang='en'>
<given nickname='false'>Mondo</given>
<family>Mangrove</family>
</name>

Я не хочу, чтобы у вас сложилось неправильное представление. То, как я


управлялся с делами в этих примерах, — не единственный способ манипули-
рования ими. Эта небольшая выборка должна помочь вам при старте. Есть
масса вещей, о которых я не рассказал, таких как удаление элементов и атри-
бутов, синтаксический анализ потока и многое другое.
С Ruby не соскучишься 191

Если хотите узнать больше, загляните в обучающую программу по


REXML Шона Рассела на http://www.germane-software.com/software/rexml/
docs/tutorial.html, а также возьмите почитать статью Коэна Верфлосема
(Koen Vervloesem) "REXML: Processing XML in Ruby" на http://www.xml.com/
pub/a/2005/11/09/rexml-processing-xml-in-ruby.html. Электронную доку-
ментацию по REXML вы найдете на http://www.ruby-doc.org/core/classes/
REXML.html.

Builder
XML Builder Джима Вейриха (Jim Weirich) (http://rubyforge.org/projects/
builder) — еще одно средство создания XML. В настоящее время оно по-
ставляется в версии 2.0.0. Впервые оно привлекло мое внимание, когда я об-
наружил его упакованным в Rails. Лично я считаю, что пользоваться им про-
ще, чем REXML, и вы, возможно, тоже будете так думать.
Сравните пример 10.2 с примером 10.3, составленным в Builder.

Пример 10.3. mondo_b.rb

#!/usr/bin/env ruby

require 'rubygems'
require_gem 'builder'

address = <<XML
<address>
<name><given>Mondo</given><family>Mangrove</family></name>
<street>9876 Trekker St.</street> .<city>Granola</city>
<state>Colorado</state>
<code>81000</code>
<country>USA</country>
</address>
XML

document = Builder::XmlMarkup.new( :target => address, :indent => 1 )


puts document.to_xs

В этом примере, прежде всего, затребован rubygems, а затем builder с по-


мощью require_gem. Метод require_gem происходит из пакета rubygems.
192 Глава 10

Он может принимать еще один параметр, позволяющий указать, какой вер-


сией пакета вы хотите воспользоваться (см. http:/Idocs.rubygems.org/read/
chapter/4#page71).
Документ "здесь и сейчас" сохраняется в строке address, которая является
целью для объекта XmlMarkup (аналогично объекту Document в REXML).
Здесь также можно установить структурирование выходных данных. Метод
puts выводит документ на стандартное устройство вывода с помощью мето-
да to_xs — на первый взгляд не так, чтобы это сильно отличалось от
REXML.
Вот результаты. Небольшой тег to_xs следует за завершающим тегом корне-
вого элемента:
<address>
<name><given>Mondo</given><family>Mangrove</familyx/name>
<street>9876 Trekker St.</street>
<city>Granola</city>
<state>Colorado</state>
<code>8l000</code>
<country>USA</country>
</address>
<to_xs/>

Теперь сравните пример 10.2 с примером 10.4.

Пример 10.4. mangrove_b.rb

#!/usr/bin/env ruby

require 'rubygems'
require_gem 'builder'
include Builder

document = XmlMarkup.new(:target => $stdout, :indent => 1)


document.instruct!
document.comment! "our good friend Mondo"

document.name( :lang => "en" ) {


document.given "Mondo", :nickname => "false"
document.family "Mangrove"
}
С Ruby не соскучишься 193

Целевое устройство — стандартный вывод ($stdout). Описания XML фор-


мируются с помощью метода instruct!, а комментарии — с помощью
comment!. Обратите внимание на то, как вместо методов используются имена
элементов. (Вы догадались о чудесах метапрограммирования, происходящих
на заднем плане?)
Мне нравится, как можно представить отношение "родитель — потомок",
заключив дочерние элементы в фигурные скобки ({}). Выходные данные от-
сылаются на стандартное устройство вывода.
<?xml version="1.0" encoding="UTF-8"?>
<!-- our good friend Mondo -->
<name lang="en">
<given nickname="false">Mondo</given>
<family>Mangrove</family>
</name>

У REXML больше функциональных возможностей, чем в Builder, и он встро-


ен в Ruby, но в Builder есть дух Ruby (Rubyness), так что мне трудно устоять.
Вы найдете электронное руководство по Builder (написанное вашим покор-
ным слугой) на http://www.xml.com/pub/a/2006/01/04/creating-xml-with-ruby-
and-builder.html, а полную документацию — на http://builder.rubyforge.org.

Date и Time
Подсчет дней и времени важен и в повседневной жизни, и в обработке дан-
ных на компьютере, поэтому вполне естественно, что в Ruby предлагаются
для этого соответствующие средства. В этом разделе я расскажу о классах
Date и Time в языке Ruby.

Класс Time
Здесь я охватил наиболее широко используемые методы класса Time. Доку-
ментацию по всем методам Time см. на http://ruby-doc.org/core/classes/
Time.html.
Для определения текущего времени служит метод now (или его синоним new)
из класса Time. Два вызова метода могут помочь вам определить, сколько
времени прошло между ними.
start = Time.now # => Tue Jan 30 04:12:50 -0700 2007
stop = Time.now # => Tue Jan 30 04:13:00 -0700 2007
194 Глава 10

Чтобы установить заданное время, примените метод local (его синоним


mktime):
local_time = Time.local( 2007, "jan", 30, 1, 15, 20 )
# => Tue Jan 30 01:15:20 -0700 2007

Параметры (по порядку) к этому вызову local: год, месяц, день, час, минуты,
секунды. Можно вызвать local и с такими параметрами:
my_time = Time.local( 20, 15, 1, 30, "jan", 2007, 2, false, "MST")
# => Tue Jan 30 01:15:20 -0700 2007

Параметры (по порядку) в этом вызове: секунды, минуты, час, день, месяц,
год, день недели, признак "это летнее время?" и часовой пояс.
От объекта Time вы можете получить все виды подробностей, таких как день,
день года и день недели:
stop.day # день месяца => 30
stop.yday # как много дней прошло в этом году => 30
stop.wday # день недели => 2, or Tue (Sun == 0)

Можно извлечь год, месяц и часовой пояс:


stop.year # => 2007
stop.month # => 1 (January)
stop.zone # timezone => "MST" or Mountain Standard Time

Вы можете выяснить час дня и количество минут и секунд этого часа:


stop.hour # => 4
stop.min # => 13
stop.sec # => 0

Каноническая форма ссылается на стандарт, установленный набором правил.


Ruby использует для определения форматирования времени такие стандарты,
как ISO 8601, "Data elements and interchange formats—Information interchange—
Representation of dates and times" (Элементы данных и форматы обмена
данными — Обмен информацией — Представление дат и времени)
(http://www.iso.ch/iso/en/CatalogueDetailPage.
CatalogueDetail?CSNUMBER=40874) и RFC 2822, "Internet Message Format"
(Формат интернет-сообщений) (http://www.ietf.org/rfc/rfc2822.txt), хотя я не
могу утверждать, что Ruby соответствует этим спецификациям до мельчай-
ших деталей. Вы можете получить для заданного времени каноническую
строку при помощи ctime (или asctime). Она выглядит так же, как формат
времени в сообщениях электронной почты.
local_time.ctime # => "Tue Dan 30 01:15:20 2007"
С Ruby не соскучишься 195

Сделайте запрос для объекта класса Time при помощи utc? (или gmt?), чтобы
определить, представляет ли он собой Coordinated Universal Time (UTC; уни-
версальное (глобальное) время по Гринвичу), также известное как Greenwich
Mean Time (GMT; Гринвичское время):
local_time.utc? # => false

Проверьте при помощи dst? или isdst, установлено ли летнее время:


my_time.dst? # => false

Проверьте, равны ли два объекта Time, при помощи eql? или оператора <=>:
# создайте еще один новый объект temp класса Time
temp = stop # => Tue Jan 30 04:13:00 -0700 2007
stop.object_id # => 1667650
temp.object_id # => 1667650

# true или false


start.eql? stop # => false

# тот же самый объект, поэтому true


temp.eql? stop # => true

# start меньше, чем stop


start <=> stop # => -1

# stop больше, чем start


stop <=> start # => 1

# тот же самый объект, поэтому 0


temp <=> stop # => 0

Можно увидеть разницу между двумя объектами Time посредством вычитания:


stop - start # => 10.112668 (в секундах)

Между stop и start разница больше 10 секунд.


Добавим ко времени секунды, минуты, часы при помощи +:
stop.inspect # => "Tue Dan 30 04:13:00 -0700 2007"

# Добавим минуту (60 секунд)


stop + 60 # => Tue Dan 30 04:14:00 -0700 2007

# Добавим час (60*60)


196 Глава 10

stop + 60*60 # => Tue Dan 30 05:13:00 -0700 2007

# Добавим три часа (60*60*3)


stop + 60*60*3 # => Tue Jan 30 07:13:00 -0700 2007

# Добавим день (60*60*24)


stop + 60*60*24 # => Wed Dan 31 04:13:00 -0700 2007

Класс Date
В этом разделе я представлю несколько методов Date, но, конечно, не все.
За документацией по всем методам Date отправляйтесь на страницу
http://ruby-doc.org/core/dasses/Date.html.
Для создания объекта Date служит метод new (или его синоним — civil).
Перед тем как воспользоваться им, вы должны затребовать класс Date.
Метод to_s возвращает дату в виде строки.
require 'date'
date = Date.new( 2006, 11, 8 )
date.to_s # => "2006-11-08"

При помощи метода класса today можно создать дату на основе сегодняшней
даты:
today = Date.today
today.to_s # => "2007-01-30"

Чтобы показать дату в формате, определенном пользователем, воспользуй-


тесь подстановкой выражений. В этой строке кода используются методы
month, day и year из Date.
puts "The date was #{date.month}/#{date.day}/#{date.year}."
# => The date was 11/8/2006.

Какой следующий день?


date.next.to_s # => "2006-11-09"

Метод next определяет следующий день, но не меняет дату по месту. (Сино-


нимом для next является succ.)
Добавьте 61 день к дате:
(date + 61).to_s # => "2007-01-08"

Вычтите 61 день из даты:


(date - 61).to_s # => "2006-09-08"
С Ruby не соскучишься 197

Добавьте и вычтите шесть месяцев при помощи методов >> и <<.


(date >> 6).to_s # => "2007-05-08"
(date << 6).to_s # => "2006-05-08"

С помощью метода downto из Date отсчитайте в обратном направлении пять


дней, выводя по ходу дела каждую дату (изменения даты здесь производятся
по месту):
date.downto( date - 5 ) { |date| puts date }
2006-11-08
2006-11-07
2006-11-06
2006-11-05
2006-11-04
2006-11-03
# дата изменилась
date.to_s # => "2007-11-03"

Теперь методом upto добавьте такое же количество дней обратно, показывая


даты по мере продвижения:
date.upto( date + 5 ) { |date| puts date }
2006-11-03
2006-11-04
2006-11-05
2006-11-06
2006-11-07
2006-11-08
date.to_s # => "2006-11-08"

Как и в классе Time, можно сравнить два объекта класса Date на равенство
при помощи eql? или оператора <=>:
# создайте новый объект temp класса Date
temp = date
temp.object_id # => 2708130
date.object_id # => 2708130

# true или false


date.eql? today # => false

# тот же самый объект, поэтому true


198 Глава 10

temp.eql? date # => true

# date меньше, чем today


date <=> today # => -1

# today больше, чем date


today <=> date # => 1

# тот же самый объект, поэтому 0


temp <=> date # => 0

Календарные формы
Григорианский календарь (с 1582 г.) почти совершенно заменил юлианский
календарь (45 г. до н. э.), хотя юлианский календарь до сих пор используется
православной церковью. Одной из основных причин реформы XVI столетия
был сдвиг таких событий, как равноденствие. (Сравните http://en.wikipedia.org/
wiki/Gregorian_calendar с http://en.wikipedia.org/wiki/Julian_calendar.)
Можно согласовать дату с григорианским или юлианским календарем, доба-
вив четвертый параметр к new:
gdate = Date.new( 2006, 11, 8, "Gregorian" )
jdate = Date.new( 2006, 11, 8, "Julian" )

Чтобы увидеть разницу между датами по юлианскому и григорианскому ка-


лендарю (а она более 10 дней), возьмите юлианскую дату методом julian:
date.julian.to_s # => "2006-10-26"

Таким же образом можно увидеть григорианскую дату при помощи метода


gregorian.
date.gregorian.to_s # => "2006-11-08"

Можно получить юлианский день (день с 1 января 4713 года до н. э., начиная
с 0) с помощью метода экземпляра класса jd:
date.jd # => 2454048

Можно даже на основе юлианского дня создать год при помощи метода клас-
са jd:
nd = Date.jd( 2454048 )
nd.to_s # => "2006-11-08"

Приведенный юлианский день (день с 17 ноября 1858 года) можно вычис-


лить при помощи mjd:
date.mjd # => 54047
С Ruby не соскучишься 199

Астрономический юлианский день можно вычислить посредством ajd:


date.ajd # => 4908095/2

Можно многое рассказать о различных календарных формах и преобразова-


ниях между ними, но в этом разделе предлагается вполне достаточное введе-
ние в тему. Дополнительную информацию о классах Date и Time ищите в до-
кументации на http://www.ruby-doc.org/core. Интересен также класс
DateTime, который представляет и дату и время; см. http:// ruby-doc.org/
core/classes/DateTime.html.

Рефлексия
Ruby с легкостью может рассказать вам о себе — о своих программах и объ-
ектах — с помощью методов, которые в совокупности составляют свойство,
называемое рефлексией. В предыдущих главах этой книги вам уже приходи-
лось видеть несколько таких методов в действии. Я пройдусь по некоторым
наиболее часто вызываемым методам и укажу другие, которые вы, возможно,
посчитаете нелишними.
При помощи документа "здесь и сейчас" (см. главу 4) я определю строку,
часть стихотворения Уолта Уитмена, а затем покажу на ней рефлексию.
asiponder = <<whitman
As I ponder'd in silence,
Returning upon my poems, considering, lingering long,
A Phantom arose before me, with distrustful aspect,
Terrible in beauty, age, and power,
The genius of poets of old lands
whitman # => "As I ponder'd in silence, \nReturning upon my poems,
considering, lingering long, \nA Phantom arose before me, with
distrustful aspect, \nTerrible in beauty, age, and power, \nThe
genius of poets of old lands\n"

asiponder является экземпляром класса String. В классе Object есть метод


class, который возвращает имя класса экземпляра класса:
asiponder.class # => String

Метод class вытесняет из Object осуждаемый метод type и получает имя


класса в виде строки с помощью метода name:
asiponder.class.name # => "String"
200 Глава 10

Чтобы определить имя суперкласса — родительского класса, который в иерар-


хии классов стоит на одну ступень выше, — воспользуйтесь методом superclass
из класса Class.
asiponder.class.superclass # => Object
String.superclass # => Object

Выяснить имена всех включенных модулей экземпляра класса или его класса
можно при помощи метода included_modules из Module.
asiponder.class.included_modules # => [Enumerable, Comparable, Kernel]
asiponder.class.superclass.included_modules # => [Kernel]

String.included_modules # => [Enumerable, Comparable, Kernel]


Object.included_modules # => [Kernel]

У каждого объекта есть свой собственный числовой идентификатор (ID). Его


можно узнать с помощью метода object_id из Object.
whitman = asiponder # копируем один строковый объект в другой
whitman == asiponder # => true
asiponder.object_id # => 968680
whitman.object_id # => 968680

Эти объекты идентичны и имеют один и тот же ID, намек на то, что Ruby бе-
режно расходует ресурсы. (Метод id из Object был резко осужден; приме-
няйте вместо него object_id.)
Вы можете также удостовериться, является ли объект экземпляром данного
класса, с помощью метода instance_of? из Object:
asiponder.instance_of? String # => true
asiponder.instance_of? Fixnum # => false

instance_of? служит для надежности. Другими словами, не выполняйте блок


(do |t|...end), если переменная asiponder не является строкой.
if asiponder.instance_of?( String )
asiponder.split.each do |t|
puts t
end
end

Или применяйте методы is_a? и kind_of? из Object (они синонимы):


asiponder.is_a? String # => true
asiponder.kind_of? String # => true
С Ruby не соскучишься 201

В отличие от instance_of?, методы is_of? и kind_of? работают и в том слу-


чае, если параметром является суперкласс или модуль.
asiponder.is_a? Object # => true
asiponder.kind_of? Kernel # => true
asiponder.instance_of? Object # => false

Познакомьтесь с предками объекта при помощи метода ancestors из Module,


который возвращает список и классов и модулей:
asiponder.class.ancestors
# => [String, Enumerable, Comparable, Object, Kernel]
String.ancestors # => [String, Enumerable, Comparable, Object, Kernel]

Рефлексия для переменных и констант


Давайте теперь рассмотрим переменные и константы. Сделаем это в irb.
Прежде всего, я определю несколько переменных на основе известных эле-
ментов из романа Джозефа Конрада (Joseph Conrad) "Лорд Джим":
irb(main):001:0> $ship = "Patna"
=> "Patna"
irb(main):002:0> @friend_1 = "Marlow"
=> "Marlow"
irb(main):003:0> @friend_2 = "Jewel"
=> "Jewel"
irb(main):004:0> bad_chap = "'Gentleman' Brown"
=> "'Gentleman' Brown"

Воспользуемся несколькими методами, чтобы раскопать информацию об


этих переменных. Есть ли среди них локальные? Чтобы выяснить это, возь-
мем метод local_variables из модуля Kernel.
irb(main):005:0> local_variables
=> ["_", "bad_chap"]

У нас есть bad_chap и _, специфический "зверь", который выдает последнее


значение в irb (совершенно конфиденциально, conf.last_value тоже воз-
вращает последнее значение).
Вернем переменные экземпляра при помощи instance_variables из Object:
irb(main):006:0> instance_variables
=> ["@friend_2", "@friend_1"]
202 Глава 10

Метод global_variables из Kernel возвращает все глобальные переменные,


включая $ship.
irb(main):007:0> global_variables
=> ["$-p", "$:", "$FILENAME", "$defout", "$,", "$`", "$binding",
"$-v", "$stdin", "$PROGRAM_NAME", "$\"", "$?", "$\\", "$=", "$-d", "$>",
"$&", "$-F", "$-а", "$VERBOSE", "$0", "$LOAD_PATH", "$$", "$-0", "$+",
"$!", "$DEBUG", "$stderr", "$~", "$;", "$SAFE", "$<", "$_", "$-K",
"$-1", "$-I", "$-i", "$deferr", "$/", "$"', "$@", "$-w", "$stdout",
"$ship", "$*", "$LOADED_FEATURES", "$.", "$KCODE"]

Хотите узнать, какие константы есть в классе Object (или каком-нибудь другом
классе)? Примените метод constants из Module (выходные данные обрезаны):
irb(main):008:0> Object.constants.sort
# => ["ARGF", "ARGV", "ArgumentError", "Array", ... ]

Я добавил в конец метод sort (из Array), чтобы результат получился удобо-
читаемым.

Рефлексия для методов


Метод methods из Object возвращает список имен методов, доступных из
объекта, включая методы, доставшиеся от предков объекта. Вот пример вы-
зова (результат обрезан):
irb(main):009:0> Object.methods.sort
=> ["<", "<=", "<=>", "==", "===", "=~", ">", ">=", " id ","__send__",
"allocate", "ancestors", "autoload", "autoload?", "class",
"class_eval", "class_variables", "clone", ... ]

После этого можно запросить методы экземпляра класса с помощью метода


instance_methods из Module:
irb(main):010:0> Object.instance_methods.sort
=> ["==", "===", "=~", "__id__", "__send__", "class", "clone", "display",
"dup","eql?", "equal?", "extend", "freeze", "frozen?", ...]

Можно делать запросы о методах с помощью методов из класса Object: pri-


vate_methods, protected_methods, public_methods и singleton_methods. В
Module также есть методы private_instance_methods, pro-
tected_instance_methods и public_instance_ methods.
Вот пример вызова private_methods из Object при помощи puts:
irb(main):010:0> puts Object.private_methods.sort
Array
С Ruby не соскучишься 203

Float
Integer
String
...

Метод respond_to? из Object позволяет проверить, соответствует ли данный


объект данному методу. Вы должны сослаться на метод, как на символ
(symbol).
Object.respond_to? :instance_methods # => true

class A
attr_accessor :x
end
a = A.new

a.respond_to? :x # => true


a.respond_to? :x= # => true
a.respond_to? :y # => false

Применение Tk
В главе 1 вы видели небольшую программу, которая создавала графическую
версию "Hello, Matz!" с помощью пакета инструментальных средств Tk, ко-
торый поставляется вместе с Ruby как часть его стандартной библиотеки
(http://www.ruby-doc.org/stdlib). Tk является библиотекой — пакетом вид-
жетов — основных элементов для создания графического интерфейса поль-
зователя. Он работает на целом ряде платформ и принадлежит миру открыто-
го программного обеспечения. Джон Остераут (John Ousterhout) разработал
Tk как расширение своего языка написания сценариев Tcl. Информацию о Tk
см. на http://www.tcl.tk.
В примере 10.5 показана еще одна программа, требующая Tk. Она манипули-
рует шрифтом, размером и цветом метки. Она также предоставляет кнопку
Quit.

Пример 10.5. tk.rb

#!/usr/bin/env ruby
require 'tk'

TkRoot.new {title "Ruby is fun!"}


204 Глава 10

TkLabel.new {
font TkFont.new( 'mistral 42' )
text "Ruby is fun, in case you didn't notice!"
width 30
height 3
fg 'blue'
pack
}

TkButton.new {
text 'Quit'
command 'exit'
pack
}

Tk.mainloop

Окно Tk помечено заголовком "Ruby is fun!" ("С Ruby не соскучишься!").


Метка, содержащая текст "Ruby is fun, in case you didn't notice!" ("С Ruby не
соскучишься, если вы не заметили!"), появляется в центре панели. Использу-
ется шрифт Mistral и размер шрифта 42. (Mistral может оказаться недоступ-
ным в вашей системе. Тогда, чтобы выполнить программу без ошибки, вам
придется изменить шрифт.)
Цвет изображения (fg), цвет текста — blue. Ширина — 30 и высота — 3.
Кнопка, помеченная Quit, выполняет команду exit. Метод mainloop обеспе-
чивает работу.
Запустите программу:
tk.rb &

Если вы работаете в системе UNIX/Linux, то & в конце команды сделает про-


цесс фоновым. Не указывайте его, если работаете в Windows.
На вашем дисплее появится окно, как на рис. 10.1. Для завершения работы
программы нажмите кнопку Quit.
Программа в примере 10.6 выводит на экран фотографию моей лошади, Ут-
ренней Зари.
С Ruby не соскучишься 205

Рис. 10.1. Ruby is fun!

Пример 10.6. photo.rb

#!/usr/bin/env ruby

require 'tk'
require "tkextlib/tkimg/jpeg"
require "open-uri"

photo = open("http://www.wyeast.net/images/sunrise.jpg", "rb") {|io|


io.read}
TkRoot.new {title "Sunrise"}
TkLabel.new {
image TkPhotoImage.new( :data => Tk::BinaryString( photo ) )
width 300
pack
}
TkLabel.new {
font TkFont.new( 'verdana 24 bold' )
text "Sunrise at sunset!"
pack
}
TkButton.new {
text 'Quit'
command 'exit'
pack
}
Tk.mainloop
206 Глава 10

Эта программа открывает URI (Uniform Resource Identifier; унифицирован-


ный идентификатор ресурса) с фотографией в формате JPEG (рис. 10.2) моей
кобылы методом open из класса OpenURI. Библиотека tkextlib/tkimg/jpeg
или Tk::Img::JPEG помогает Tk обрабатывать изображения JPEG. Информа-
ция о фотографии хранится в photo. Заголовок окна — "Sunrise" ("Утренняя
Заря"). Класс TkPhotoImage управляет изображением. Под фотографией по-
является подпись "Sunrise at sunset!" ("Утренняя Заря на закате солнца!").
Кнопка Quit позволит вам элегантно завершить работу программы.

Рис. 10.2. Утренняя Заря, моя лошадь породы quarter horse, на закате

Если вы и дальше собираетесь экспериментировать с Tk, то я порекомендую


вам галерею примеров работы Tk в Ruby на http://pubcozmixng.org/~the-
rwiki/rw-cgi.rb?cmd=view;name=%B5%D5%B0%FA%A
4%ADRuby%2FTk. Тексты там на японском, так что если вы еще недоста-
точно свободно владеете этим языком, читайте коды. Код — ключ ко всему.
С Ruby не соскучишься 207

Метапрограммирование
Метапрограммирование — это условное обозначение способа написания
программы, или части программы, с помощью другой программы. В преды-
дущей главе вы познакомились с метапрограммированием на практике, когда
вызывали семейство методов attr (attr, attr_reader, attr_writer и
attr_accessor из класса Module), чтобы создать для классов геттеры и сетте-
ры. Теперь у вас есть шанс заняться метапрограммированием самому.
Ключ к решению проблем — метод define_method из класса Module, ко-
торый позволяет создавать методы на лету. Взгляните на программу в приме-
ре 10.7, которая создает метод, выбирая имена из элементов массива.

Пример 10.7. meta.rb

#!/usr/bin/env ruby
class Meta
%w{ jane elizabeth mary kitty lydia }.each do |n|
define_method(n) { puts "My name is #{n.capitalize} Bennet." }
end
end

Meta.instance_methods - Object.instance_methods
# => ["jane", "elizabeth", "mary", "kitty", "lydia"]

meta = Meta.new

meta.elizabeth # => My name is Elizabeth Bennet.

Итак, имена в строковом массиве (%w{...}) принадлежат пяти сестрам Бен-


нет из романа "Гордость и предубеждения" Джейн Остин. Метод each подает
все элементы массива в метод define_method в виде n. Каждый метод выво-
дит (puts) строку, содержащую элемент, написанный с прописной буквы,
путем подстановки выражения (#{n.capitalize}).
Когда вы создадите экземпляр класса Meta и вызовите метод экземпляра
класса elizabeth, то получите результат: "My name is Elizabeth Bennet".
И это, дамы и господа, есть самый обыкновенный пример метапрограммиро-
вания.
Другие рефлективные методы и практические примеры могли бы сослужить
хорошую службу метапрограммированию в Ruby, но вы уже и так неплохо
208 Глава 10

стартовали с define_method. Приложение Rails полно метапрограммирова-


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

RubyGems
RubyGems — это комплект сервисных программ для Ruby (http://rubyforge.org/
projects/rubygems), написанный Джимом Вейрихом (Jim Weirich). На сего-
дняшний день этот комплект выполняет установку пакетов программного
обеспечения Ruby и поддерживает их. RubyGems прост для изучения и при-
менения — он даже проще, чем такие инструментальные программные сред-
ства, как утилита tar в UNIX/Linux (http://www.gnu.org/software/tar) или
утилита jar в Java (http://java.sun.com/j2se/1.5.0/docs/tooldocs/windows/jar.html).
Дополнительную информацию о RubyGems ищите в документации на
http://docs.rubygems.org/. RubyGems User Guide (http://docs.rubygems.org/
read/book/1) даст вам почти все, что необходимо знать об использовании
RubyGems. Есть также справочная информация по командам (Command
Reference) (http://docs.rubygems.org/read/book/2).
Вполне вероятно, что при установке Ruby в вашей системе был установлен
и RubyGems. Чтобы убедиться в этом, наберите в UNIX или Linux:
$ which gem
/usr/local/bin/gem

Или просто проверьте версию, набрав:


$ gem -v
0.9.0

или:
$ gem --version
0.9.0

СОВЕТ
Если RubyGems не был установлен, прочтите в третьей главе
"RubyGems User Guide" на http://rubygems.org/read/chapter/3 полную
инструкцию по установке.

Давайте начнем с самого начала — попросим помочь нам узнать, как выда-
вать команды для RubyGems:
$ gem
RubyGems is a sophisticated package manager for Ruby. This is a basic
С Ruby не соскучишься 209

help message containing pointers to more information.


# (RubyGems является современной управляющей программой для Ruby.
# Это базовое справочное сообщение, содержащее указатели на информацию.)

Usage: # (Применение:)
gem -h/--help
gem -v/--version
gem command [arguments...] [options...]

Examples: # (Примеры:)
gem install rake
gem list –local
gem build package.gemspec
gem help install

Further help: # (Дополнительная помощь:)


gem help commands # перечислить все команды 'gem'
gem help examples # показать некоторые примеры применения
gem help <COMMAND> # показать справку по команде COMMAND
# (например, 'gem help install')
Further information: # (Дополнительная информация:)
http://rubygems.rubyforge.org

Теперь давайте узнаем, какие команды нам доступны (некоторые выходные


данные обрезаны).
$ gem help commands
GEM commands are: # (Команды Gem:)
build Build a gem from a gemspec
# Создать gem из gemspec
...
specification Display gem specification (in yaml)
# Показать спецификацию gem(в yaml)
uninstall Uninstall a gem from the local repository
# Деинсталлировать gem из локального архива
unpack Unpack an installed gem to the current directory
# Распаковать установленный gem в текущий каталог
update Update the named gem (or all installed gems) in
the local repository
# Обновить именованный gem (или все установленные gem) в
# локальном архиве
210 Глава 10

For help on a particular command, use 'gem help COMMAND'.


Commands may be abbreviated, so long as they are unambiguous.
e.g. 'gem i rake' is short for 'gem install rake'.
(Для справки по отдельным командам используйте 'gem help COMMAND'.)
(Команды могут быть укорочены до тех пор, пока остаются однозначными.
Например, 'gem i rake' является сокращением для 'gem install rake'.)

Давайте рассмотрим справочную информацию на примерах (часть выходных


данных отброшена).
$ gem help examples
Some examples of 'gem' usage.
# (Некоторые примеры использования 'gem'.)
* Install 'rake', either from local directory or remote server:
# Установить 'rake' из локального каталога или с удаленного сервера:
gem install rake
* Install 'rake', only from remote server:
# Установить 'rake' только с удаленного сервера:
gem install rake --remote
* Install 'rake' from remote server, and run unit tests, and
generate RDocs:
# Установить 'rake' с удаленного сервера, выполнить тестирование
# составных частей и сгенерировать RDoc:
gem install --remote rake --test --rdoc --ri
* See information about RubyGems:
# См. информацию о RubyGems:
gem environment

Выберите команду — почему бы не environment — и получите по ней справ-


ку. Вам не нужно набирать все слово environment, для gem довольно решить
вопрос однозначности (env вполне достаточно).
$ gem help env
Usage: gem environment [args] [options]
Common Options:
--source URL Use URL as the remote source for gems
-p, --[no-]http-proxy [URL] Use HTTP proxy for remote operations
-h, --help Get help on this command
-v, --verbose Set the verbose level of output
--config-file FILE Use this config file instead of default
--backtrace Show stack backtrace on errors
С Ruby не соскучишься 211

--debug Turn on Ruby debugging


Arguments:
packageversion display the package version
gemdir display the path where gems are installed
gempath display path used to search for gems
version display the gem format version
remotesources display the remote gem servers
<omitted> display everything
Summary:
Display RubyGems environmental information

Вот перевод этих сведений:


$ gem help env
Применение: gem environment [args] [options]
Общие опции:
--source URL Использовать URL как удаленный источник
для gems
-p, --[no-]http-proxy [URL] Использовать прокси-сервер HTTP
для удаленных операций
-h, --help Получить справку по этой команде
-v, --verbose Установить подробный уровень
выходных данных
--config-file FILE Использовать этот файл config
вместо файла по умолчанию
--backtrace Показывать при ошибках обратную
трассировку стека
--debug Включить отладку Ruby
Параметры:
packageversion показать версию пакета
gemdir показать путь, по которому установлены gems
gempath показать путь, использующийся для поиска gems
version показать версию формата gem
remotesources показать удаленные серверы gem
<omitted> показать все
Резюме:
Показать информацию о среде RubyGems
212 Глава 10

Выявите всю информацию о среде RubyGems с помощью этой команды:


$ gem env
Rubygems Environment:
- VERSION: 0.9.0 (0.9.0)
- INSTALLATION DIRECTORY: /usr/local/lib/ruby/gems/1.8
- GEM PATH:
- /usr/local/lib/ruby/gems/1.8
- REMOTE SOURCES:
- http://gems.rubyforge.org

Это результаты от Mac OS X Tiger. А теперь просто покажите каталог уста-


новки RubyGems:
$ gem env gemdir
/usr/local/lib/ruby/gems/1.8

Давайте с помощью команды list проверим, присутствует ли Ruby on Rails.


$ gem list rails
*** LOCAL GEMS ***

Кажется, его нет. Продолжим и установим его при помощи команд install
и sudo (привилегированный пользователь), для чего потребуется пароль
(в приведенном далее коде выходные данные усечены). Я выполняю эту
команду в Mac OS X. Опция --include-dependencies устанавливает Rails со
всеми его взаимосвязями. Ваш результат может выглядеть иначе; например,
в Windows не требуется быть привилегированным пользователем, если у за-
регистрированного пользователя есть соответствующие права администрато-
ра, и в этом случае вам не нужно будет вводить пароль.
$ sudo gem install rails --include-dependencies
Password:
Bulk updating Gem source index for: http://gems.rubyforge.org
...
С помощью команды dependency вы можете проверить, какие у gem есть
взаимосвязи:
$ gem dep rails
Gem rails-1.2.3
rake (>= 0.7.2)
activesupport (= 1.4.2)
activerecord (= 1.15.3)
actionpack (= 1.13.3)
actionmailer (= 1.3.3)
actionwebservice (= 1.2.3)
С Ruby не соскучишься 213

Для выделения взаимосвязей при установке пакета опустите опцию


--include-dependencies (делать так не рекомендуется; может произойти
ошибка, когда вы будете подтверждать каждую связь по отдельности).
$ sudo gem install rails

Чтобы заменить все gems в своей системе на текущие версии, воспользуйтесь


командой update. Флаг --system обновляет системное программное обеспе-
чение RubyGems (часть выходных данных отброшена).
$ sudo gem update --system
Password:
Updating RubyGems...
(Обновление RubyGems...)
Need to update 2 gems from http://gems.rubyforge.org
(Необходимо обновить 2 gems с http://gems.rubyforge.org)
..
complete
(завершено)
Attempting remote update of rubygems-update
(Попытка удаленного обновления rubygems-update)
Successfully installed rubygems-update-0.9.0
(Успешно установлен rubygems-update-0.9.0)
Updating version of RubyGems to 0.9.0
(Обновление версии RubyGems до 0.9.0)
Installing RubyGems 0.9.0
(Установка RubyGems 0.9.0)
...
Successfully built RubyGem
(Успешно создан RubyGem)
Name: sources
Version: 0.0.1
File: sources-0.0.1.gem
RubyGems system software updated
(Системное программное обеспечение RubyGems обновлено)

Для деинсталляции пакета используйте команду uninstall:


$ sudo gem uninstall rails
Password:
Successfully uninstalled rails version 1.1.6
(Успешно деинсталлирован rails version 1.1.6)
Remove executables and scripts for
214 Глава 10

'rails' in addition to the gem? [Yn]


(Удалить исполняемые файлы и сценарии для
'rails' в дополнение к gem? [ДаНет])
Removing rails
(Удаление rails)

Теперь вы знакомы с основами RubyGems. Чтобы узнать больше, обращайтесь


за справкой к RubyGems User Guide (http://docs.rubygems.Org/read/book/1).
Побывайте на
http://rubygems.rubyforge.org/wiki/wiki.pl?CreateAGemInTenMinutes
и научитесь создавать собственный пакет RubyGems.

Обработка исключений
Исключение возникает, когда программа "откалывает номер" и ее нормаль-
ное течение прерывается. Ruby подготовлен к решению таких проблем по-
средством собственных встроенных исключений, но вы можете управиться
с ними по-своему, с помощью обработки исключений.
Модель обработки исключений в Ruby подобна моделям в C++ и Java.
В табл. 10.3 показано сравнение ключевых слов или методов, используемых
для выполнения обработки исключений в этих трех языках. Если вы умуд-
ренный жизнью программист, эта таблица станет для вас пробным камнем.

Таблица 10.3. Сравнение обработки исключений в C++, Java и Ruby

C++ Java Ruby


try {} try {} begin/end
catch {} catch {} Ключевое слово rescue (или метод catch)
Не применяется finally ensure
throw throw raise (или метод throw)

Давайте, как обычно, рассмотрим пример. Если в программе на языке Ruby


вы попробуете выполнить деление на ноль, Ruby захочет выразить вам свое
недовольство. (А вы бы так не поступили?) Поэкспериментируйте в irb:
irb(main):001:0> 12/0
ZeroDivisionError: divided by 0
(Ошибка деления на ноль: деление на 0)
from (irb):l:in `/'
from (irb):l
С Ruby не соскучишься 215

Ruby умеет выражать неудовольствие, поэтому, по умолчанию, он вручает


вам ZeroDivisionError.
Вы можете принять то, что делает Ruby, а можете обработать эту ошибку са-
ми, применяя операторы rescue и ensure, как показано в примере 10.8.
Raison d'etre (назначение) этой небольшой программы состоит в том, чтобы
показать вам, как в Ruby работают исключения.

Пример 10.8. divide_by_zero.rb

begin
eval "12 / 0"
rescue ZeroDivisionError
puts "Oops. You tried to divide by zero again."
exit 1
ensure
puts "Tsk. Tsk."
end

Вывод, полученный от этой программы:


Oops. You tried to divide by zero again.
Tsk. Tsk.

Вот краткий анализ. Метод eval (из Kernel) расценивает строку как оператор
Ruby. Результат, как вы хорошо понимаете, катастрофический, но в этот мо-
мент оператор rescue перехватывает ошибку, выдает вам заказанное пользо-
вателем сообщение в форме строки "Oops..." и завершает выполнение про-
граммы. (exit — еще один метод Kernel; параметр 1 является вместилищем
для ошибок общего характера.) Вы можете вставить несколько операторов
ensure, если ваша программа требует этого.
Вместо того чтобы выдать свое сообщение по умолчанию, т. е.
"ZeroDivisionError: divided by 0", Ruby вернул сообщение, указанное
в rescue, плюс сообщение в ensure. Даже если программа заканчивается
в конце оператора rescue, оператор ensure вырабатывает свой блок, несмот-
ря ни на что.
Вам не нужно ждать, пока Ruby вызовет для вас исключение: вы можете сде-
лать это сами при помощи метода raise из Kernel (http://www.ruby-
doc.org/core/classes/Kernel.html). Если дела в программе пошли скверно (не
по вашему вкусу), вы можете вызвать исключение с помощью raise:
bad_dog = true
if bad_dog
216 Глава 10

raise StandardError, "bad doggy"


else
arf_arf
end
StandardError: bad doggy

При обращении без параметров метод raise вызывает RuntimeError, если не


было предыдущего исключения. Если указать только параметр String, то
raise вызовет RuntimeError с этим параметром в виде сообщения. Если пер-
вый параметр является исключением, например, StandardError, то вызыва-
ется это исключение с заданным сообщением, если присутствует такое сооб-
щение.
В Kernel есть также методы catch и throw. Метод catch выполняет блок,
который будет завершен должным образом, если нет сопутствующего throw.
Если throw сопровождает catch, то Ruby ищет catch с таким же знаком, как
у throw. Затем catch возвращает значение, переданное throw, если таковое
присутствует.
Программа в примере 10.9 является адаптацией примера, который поставля-
ется вместе с документацией ri (Ruby information) для catch. Метод throw
посылает сообщение catch, если n меньше или равно 0.

Пример 10.9. catch.rb

#!/usr/bin/env ruby

def limit( n )
puts n
throw :done if n <= 0
limit( n-1 )
end

catch( :done ) { limit( 5 ) }

Создание документации с помощью RDoc


RDoc — это инструмент для генерации документации из исходных файлов
Ruby, написанных на любом из двух языков, Ruby или C. Он был создан Дей-
вом Томасом (Dave Thomas) (http://www.pragmaticprogrammer.com) и по-
ставляется как часть дистрибутива Ruby. Документация по нему доступна на
http://rdoc.sourceforge.net/doc/index.html.
С Ruby не соскучишься 217

RDoc выполняет синтаксический анализ исходного текста Ruby и собирает


информацию из комментариев, а также накапливает информацию о методах,
константах и прочих вещах. Перед тем как вывести по умолчанию данные
XHTML в подкаталог doc, он использует перекрестные ссылки, если это воз-
можно. Вы тоже можете вставлять код в свои комментарии, заставляя RDoc
форматировать страницу в соответствии с вашим вкусом.

ЗАМЕЧАНИЕ
Если вы беженец из лагеря Java, то будете рады узнать, что RDoc
подобен Javadoc в Java (http://java.sun.com/j2se/javadoc).

Основы RDoc
Я представлю здесь основы RDoc, воспользовавшись файлом ratios.rb, в ко-
тором содержится класс Ratios. Методы этого класса вычисляют некоторые
финансовые коэффициенты.
Сначала я покажу файл по частям, а затем весь целиком. Я расскажу вам, как
размечать исходные файлы Ruby и как обрабатывать эти файлы, чтобы полу-
чить выходные данные XHTML или др. Конечно, я не охвачу всего, что мож-
но проделать с RDoc, а только некоторые из самых важных вещей.
Комментарий перед началом описания класса интерпретируются как общая
документация для класса и помещаются перед любой другой документацией.
В примере 10.10 показано начало ratios.rb.

Пример 10.10. Начало ratios.rb

# This class provides a few methods for calculating financial ratios.


(Этот класс предоставляет несколько методов для вычисления финансовых
коэффициентов)
# So far, three ratios are available:
(В настоящее время доступны три коэффициента:)
# 1. debt-equity ratio (_der_)
(коэффициент долг/акционерный капитал)
# 2. long-term debt ratio (_ltdr_)
(коэффициент долгосрочной задолженности)
# 3. total debt ratio (_tdr_)
(коэффициент общего долга)
#
218 Глава 10

# Author:: Mike Fitzgerald (mailto:mike@example.com)


(Автор::)
# Copyright:: Wy'east Communications
(Авторское право::)
#
# :title:Ratios

class Ratios

Параграфы в комментариях становятся параграфами документации. Нумеро-


ванные списки (1., 2., 3. и т. д.) остаются нумерованными списками. Метки,
сопровождаемые удвоенным двоеточием, представляют следующий за ними
текст в табличной форме. Директива :title: позволяет RDoc понять, какой
заголовок вы хотите присвоить документу XHTML (что должно быть внутри
<head><title></title></head>).
Далее представлена документация для метода initialize.
# The +new+ class method initializes the class.
(Метод класса +new+ инициализирует класс.)
# === Parameters
# * _debt_ = long-term debt
# * _equity_ = equity
# === Example
# ratios = Ratios.new( 2456, 9876 )

def initialize( debt, equity )


@debt = debt
@equity = equity
end

Текст, заключенный между знаками "плюс" (+new+) в XHTML будет набран


шрифтом typewriter (с постоянной шириной), а текст, заключенный между
символами подчеркивания (как _debt_) будет набран курсивом. Строки, ко-
торым предшествуют звездочки (*), в XHTML будут отмечены большими
черными точками. Слова, которым предшествуют знаки равенства (напри-
мер, === Example) в выходных данных окажутся заголовками с различным
размером шрифта в зависимости от количества знаков равенства (чем больше
знаков, тем меньше шрифт заголовка; один знак = — для заголовка первого
уровня, два == — для второго уровня и т. д.). Текст с отступом в виде пробе-
лов также будет набран шрифтом typewriter.
С Ruby не соскучишься 219

Разметка в этом фрагменте немного другая:


# The <tt>ltdr</tt> method returns a long-term debt ratio.
(Метод <tt>ltdr</tt> возвращает коэффициент долгосрочной задолженности.)
# === Formula
# long-term debt
#----------------------- = long-term debt ratio .
# long-term debt/equity
# === Parameters
# The parameters are:
# * <i>debt</i> = long-term debt
# * <i>equity</i> = equity
# === Example
# ratios = Ratios.new( 2456, 9876 )
# ratios.ltdr # => The long-term debt ratio is 0.20.
# ratios.ltdr 1234, 56789 # => The long-term debt ratio is 0.02.

def ltdr( debt=@debt, equity=@equity )


ratio = debt/(debt+equity).to_f
printf( "The long-term debt ratio is %.2f.\n", ratio )
ratio
end

Размеченный тегами tt (<tt>ltdr</tt>) текст аналогичен тексту, размеченно-


му знаками "плюс" (+ltdr+). Точно так же, разметка тегами i (<i>debt</i>)
аналогична разметке символами подчеркивания (_debt_). Текст с отступом
под заголовком Formula будет в XHTML представлен шрифтом typewriter.
Оставшаяся часть файла, показанная в примере 10.11, имеет разметку, анало-
гичную той, что вы уже видели. На рис. 10.3 продемонстрировано, в каком
виде документация XHTML появляется в браузере.

Пример 10.11. Оставшаяся часть ratios.rb

# This class provides a few methods for calculating financial ratios.


# So far, three ratios are available:
# 1. debt-equity ratio (_der_)
# 2. long-term debt ratio (_ltdr_)
# 3. total debt ratio (_tdr_)
#
220 Глава 10

# Author:: Mike Fitzgerald (mailto:mike@example.com)


# Copyright:: Wy'east Communications
#
# :title:Ratios
class Ratios
# The +new+ class method initializes the class.
# === Parameters
# * _debt_ = long-term debt
# * _equity_ = equity
# === Example
# ratios = Ratios.new( 2456, 9876 )
def initialize( debt, equity)
@debt = debt
@equity = equity
end

# The <tt>ltdr</tt> method returns a long-term debt ratio.


# === Formula
# long-term debt
#---------------------------- = long-term debt ratio
# long-term debt/equity
# === Parameters
# The parameters are:
# * <i>debt</i> = long-term debt
# * <i>equity</i> = equity
# === Example
# ratios = Ratios.new( 2456, 9876 )
# ratios.ltdr # => The long-term debt ratio is 0.20.
# ratios.ltdr 1234, 56789 # => The long-term debt ratio is 0.02.

def ltdr( debt=@debt, equity=@equity )


ratio = debt/(debt+equity).to_f
printf( "The long-term debt ratio is %.2f.\n", ratio )
ratio
end

# The <tt>der</tt> method returns a debt-equity ratio.


С Ruby не соскучишься 221

# === Formula
# long-term debt
# -------------------- = debt-equity ratio
# equity
# === Parameters
# The parameters are:
# * <i>debt</i> = long-term debt
# * <i>equity</i> = equity
# === Example
# ratios = Ratios.new( 2456, 9876 )
# ratios.der # => The debt-equity ratio is 0.25.
# ratios.der( 1301, 7690 ) # => The debt-equity ratio is 0.17.
def der( debt=@debt, equity=(@equity )
ratio = debt/equity.to_f
printf( "The debt-equity ratio is %.2f.\n", ratio )
ratio
end

# The class method +tdr+ returns total debt ratio.


# === Formula
# total liabilities
# ------------------------ = total debt ratio
# total assets
# === Parameters
# The parameters are:
# * _liabilities_ = total liabilities
# * _assets_ = total assets
# === Example
# Ratios.tdr( 14_000, 23_000 ) # => The total debt ratio is 0.61.

def Ratios.tdr( liabilities, assets )


ratio = liabilities/assets.to_f
printf( "The total debt ratio is %.2f.\n", ratio )
ratio
end
end
222 Глава 10

Рис. 10.3. Документация по классу Ratios в RDoc

Обработка файлов с помощью RDoc


Теперь, когда вы знаете, как размечать файлы, давайте поговорим о том, как
их обрабатывать. Дважды проверьте, доступна ли команда rdoc из команд-
ной строки или командной оболочки. В Mac OS X и системе Linux вы можете
просто набрать:
$ which rdoc
/usr/local/bin/rdoc

или выполнить:
$ rdoc --version
RDoc V1.0.1 - 20041108
С Ruby не соскучишься 223

или:
$ rdoc -v
RDoc V1.0.1 - 20041108

Предполагается, что существует каталог Ratios, в котором находится один


файл, ratios.rb. Вы могли бы запустить RDoc без каких-либо опций или спе-
цификаций файлов:
$ rdoc

или запустить rdoc на файле ratios.rb:


rdoc ratios.rb

В любом случае, пока в каталоге только один файл, вы увидите примерно


такой результат выполнения команды:
ratios.rb: c....
Generating HTML...

Files: 1
Classes: 1
Modules: 0
Methods: 4
Elapsed: 0.363s
(Истекло времени:)

После генерации XHTML RDoc также создает подкаталог doc, в котором со-
держится множество файлов:
$ ls doc
classes fr_class_index.html index.html
created.rid fr_file_index.html rdoc-style.css
files fr_method_index.html

Я не буду подробно рассматривать, для чего предназначен каждый файл, из-


ложу суть: index.html в примере 10.12 содержит фреймы, которые связаны со
всеми файлами, имеющими префикс fr_; файл rdoc-style.css — это каскадные
таблицы стилей (Cascading Style Sheet, CSS); файл created.rid содержит текст,
отметки времени, когда все это было создано; каталоги classes и files содер-
жат файлы, благодаря которым все это вместе работает (вот то, что вы дейст-
вительно должны знать о них к этому моменту).
224 Глава 10

Пример 10.12. index.html, сгенерированный RDoc

<html xmlns="http://www.w3.org/l999/xhtml" xml:lang="en" lang="en">


<head>
<title>Ratios</title>
<meta http-equiv="Content-Type" content="text/html;
charset=iso-8859-1" />
</head>
<frameset rows="20%, 80%">
<frameset cols="25%,35%,45%">
<frame src="fr_file_index.html" title="Files"
name="Files" />
<frame src="fr_class_index.html" name="Classes" />
<frame src="fr_method_index.html" name="Methods" />
</frameset>
<frame src="files/ratios_rb.html" name="docwin" />
</frameset>

Чтобы сгенерировать документацию ri (в командной строке), воспользуйтесь


опцией --ri (или -r):
$rdoc --ri

Если вы указываете эту опцию, документация XHTML не генерируется.


Команда помещает каталог .rdoc в ваш домашний каталог ~/.rdoc, где ~/ —
сокращение для полного пути к домашнему каталогу, в котором содержатся
все файлы ri (кстати, эти файлы в действительности имеют формат YAML).
Чтобы поместить эти файлы в системный каталог, используйте опцию
--ri-system (или -Y) с sudo, для чего потребуется пароль root или пароль
привилегированного пользователя.
$ sudo rdoc --ri-system
Password:

ratios.rb: c...
Generating RI...
Files: 1
Classes: 1
Modules: 0
Methods: 4
Elapsed: 0.342s
С Ruby не соскучишься 225

Когда файлы ri сгенерированы, их можно просмотреть с помощью коман-


ды ri:
$ ri Ratios#der
----------------------------------------------------Ratios#der
der( debt=@debt, equity=@equity )
--------------------------------------------------------------
The +der+ method returns a debt-equity ratio.

Formula
long-term debt
-------------------------- = debt-equity ratio
equity
Parameters
The parameters are:
* _debt_ = long-term debt
* _equity_ = equity
Example
ratios = Ratios.new( 2456, 9876 )
ratios.der # => The debt-equity ratio is 0.25.
ratios.der( 1301, 7690 ) # => The debt-equity ratio is 0.17.

ВНИМАНИЕ
Если файлы ri находятся у вас и в каталоге ~/.rdoc и в системном ката-
логе, то ri может споткнуться. Самое простое, хотя и неожиданное
решение этой коллизии, состоит в том, чтобы просто удалить каталог
~/.rdoc, а затем повторно сгенерировать файлы. Удаляя ~/.rdoc, вы не
удалите исходные файлы, только сгенерированные. Не удаляйте ис-
ходные файлы!

Если у вас в каталоге есть дополнительные файлы, которые вы не хотите об-


рабатывать с помощью RDoc, используйте опцию --exclude (или -x):
$ ls
ratios.rb test.rb
$ rdoc --exclude test.rb
ratios.rb: c...
Generating HTML...

Files: 1
Classes: 1
226 Глава 10

Modules: 0
Methods: 4
Elapsed: 0.387s

Если хотите, можете поместить все в один файл XHTML (но я не рекомен-
дую делать так новичкам).
rdoc --one-file >> my_rdoc.html

Embedded Ruby
Embedded Ruby (ERB или eRuby) позволяет вставлять произвольный код
Ruby в текстовые файлы. Код выполняется при обработке файла. Если вы
когда-либо использовали JavaServer Pages (JSP), то синтаксис ERB будет вам
знаком. Подобно JSP, ERB применяет для встраивания кода в теги-шаблоны.
ERB поставляется вместе с дистрибутивом Ruby. Однако существуют другие,
более быстрые механизмы встраивания Ruby, например, Erubis Макото Кува-
ты (Makoto Kuwata) (http://rubyforge.org/projects/erubis). Я сосредоточу
ваше внимание на синтаксисе страницы ERB, а не на его реализации.
Встраивание кода в HTML или XHTML или генерация на лету Web-страниц
с помощью ERB широко распространены. Однако это не единственное про-
странство, где можно встретить ERB. Как работает ERB, очень просто пока-
зано в примере 10.13.

Пример 10.13. simple_erb.rb

#!/usr/bin/env ruby
require 'erb'
person = "Matz!"
temp = ERB.new( "Hello, <%= person %>" )
puts temp.result( binding ) # => Hello, Matz!

Чтобы заставить ERB работать, вы должны затребовать библиотеку erb. Ме-


тод класса new создает экземпляр класса ERB (temp), со строкой в качестве
параметра. В строку встроена пара тегов-шаблонов, <%= и %>. Эти теги со-
держат ссылку на локальную переменную person. Когда программа выпол-
няется, теги и выражения в тегах замещаются результатом вычисления вы-
ражения. Это значит, что при выполнении программы <%= person %> будет
заменено на значение person — Matz!.
Когда вызывается метод экземпляра класса result, получателем является
temp, а параметром — binding. В результате получается "Hello, Matz!".
С Ruby не соскучишься 227

Теги <%= и %> — только одна из возможных пар тегов. Все теги-шаблоны
ERB приведены в табл. 10.4.

Таблица 10.4. Теги-шаблоны ERB

Тег Описание
<% ... %> Код на Ruby; встраивается в выходные данные
<%= ... %> Выражение на Ruby; замещается результатом вычисления
<%# ... %> Комментарий; игнорируется; удобен при тестировании
% Строка кода на Ruby; обрабатывается как <% .. %>; устанав-
ливается с помощью параметра trim_mode в ERB.new
%% Замещается %, если стоит в начале строки и если используется
обработка %
<%% ... %%> Замещается <% и %>, соответственно

В примере 10.14 шаблон XHTML используется для создания индивидуаль-


ных записей для лошадей. Эти шаблоны часто по договоренности хранятся
в файлах с расширением rhtml. Программа представляет собой упрощенную
версию программы из документации ERB (http://ruby-doc.org/core/classes/
ERB.html).

Пример 10.14. erb.rb

#!/usr/bin/env ruby

require 'erb'

document = %[
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<title><%= @name%></title>
</head>
<body>
<h1><%= @name%></h1>

<p><b>Breed:</b> <%= @breed %></p>


<p><b>Sex:</b> <%= @sex%></p>

<h2>Foals</h2>
228 Глава 10

<ul><% (afoals. each do |foals| %>


<li><%= foals %></li> <% end %>
</ul>

</body>
</html>
]
class Horse

def initialize( name, breed, sex )


@name = name
@breed = breed
@sex = sex
@foals = []
end

def foal( name )


@foals << name
end

def context
binding
end

end

output = ERB.new( document )

horse = Horse.new( "Monarch's Sunrise", "Quarter Horse", "Mare" )


horse.foal( "Dash" )
horse.foal( "Pepper" )

output.run( horse.context )

Шаблон документа XHTML формируется внутри общей строки с разделите-


лями (%[...]). Для порождения выходных данных используются переменные
экземпляра из класса Horse. В массиве @foals посредством метода foal на-
капливаются имена. Метод context возвращает binding.
С Ruby не соскучишься 229

Создается новый экземпляр класса ERB с именем output, а также новый эк-
земпляр класса Horse с соответствующими параметрами. Метод foal вызы-
вается несколько раз для добавления имен в конец массива @foals. Эти име-
на извлекаются при помощи метода each и блока. Обратите внимание на теги
<% и %>. В них содержится код Ruby, тогда как теги <%= и %> возвращают ре-
зультат вычисления выражения.
<h2>Foals</h2>
<ul><% @foals.each do |foals| %>
<li><%= foals %></li> <% end %>
</ul>

При выполнении этой программы выдается результат, показанный в приме-


ре 10.15.

Пример 10.15. Выходные данные erb.rb

<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">


<head>
<title>Monarch's Sunrise</title>
</head>
<body>
<h1>Monarch's Sunrise</h1>

<p><b>Breed:</b> Quarter Horse</p>


<p><b>Sex:</b> Mare</p>

<h2>Foals</h2>
<ul>
<li>Dash</li>
<li>Pepper</li>
</ul>

</body>
</html>

Место, где вы, несомненно, встретите такие теги, это файлы с расширением
rhml, произведенные Ruby on Rails, предметом разговора в главе 11.
230 Глава 10

Вопросы для самопроверки


1. Для чего служит поле формата b в sprintf (printf)?
2. Какой метод вы бы применили, чтобы получить структурную распечатку
документа с помощью Builder?
3. Что делает метод superclass?
4. Как можно проверить, соответствует ли данный класс методу?
5. Как затребовать пакет RubyGems в программах Ruby?
6. Как в Ruby называется ключевой метод метапрограммирования?
7. Какой командой RubyGems вы бы воспользовались для установки пакета?
8. Какой класс Tk используется для создания меток?
9. Для каких ключевых слов в Java являются синонимами ключевые слова
rescue и ensure из Ruby?
10. Как вы форматируете заголовки для обработки в RDoc?
Глава 11

Краткий курс по Ruby on Rails

Ruby on Rails (http://www.rubyonrails.org) — это каркас для разработки се-


тевых приложений, связанных с базами данных, с открытыми исходными
текстами и без всех привычных мучений. Он написан на языке Ruby, и, как я
упоминал в главе 1, Matz назвал его "захватчиком рынка" для Ruby.
Rails позволяет быстро и удобно компоновать сложные Web-сайты, посколь-
ку вы можете сплавить ему львиную долю своей работы. А с другой стороны,
то, что делает Rails, — относительно прозрачно, и вы с легкостью сможете
контролировать все, что захотите. После нескольких вступительных замеча-
ний вы найдете в конце главы обучающее руководство.

Откуда взялась среда Rails?


Частная, базирующаяся в Чикаго, компания 37signals (http://www.37signals.com)
была создана Джейсоном Фрайдом (Jason Fried) в 1999 году. Компания произво-
дит основанные на интернет-технологии приложения, например, Basecamp,
для управления проектами (http://www.basecamphq.com) и Backpack, отличное
организационное инструментальное средство (http://www.backpackit.com).
37signals попросила Дэвида Хейнемейера Хенссона (David Heinemeier
Hansson или DHH) написать Basecamp на PHP (Hypertext Preprocessor; гипер-
текстовый препроцессор — встраиваемый в HTML открытый многоплат-
форменный серверный язык сценариев для быстрого построения динамиче-
ских Web-страниц). Он и Matz встретились на конференции, когда Matz был
студентом, и ему действительно понравилось то, что мог предложить Ruby.
Он предпочел написать Basecamp на Ruby, а не на PHP, и ребята из 37signals
позволили ему сделать это. Остальное, как они говорят, — история.
Закончив писать код, DHH начал включать основной код из Basecamp в дру-
гой проект, Ta-da Lists (http://www.tadalist.com). Затем он превратил этот
232 Глава 11

код в проект с открытым исходным текстом (лицензия MIT; МТИ, Массачу-


сетский технологический институт) и назвал его Ruby on Rails.
DHH впервые представил публике Rails, версия 0.5, на RubyForge 24 июля
2004 года (http://rubyforge.org/frs/?group_id=307). Версия 1.0 была выпу-
щена 13 декабря 2005 года. Текущей версией на момент написания этой кни-
ги является версия 1.2.3, выпущенная в начале 2007 года.

Почему Rails?
Действительно ли мир нуждается в еще одном средстве разработки интернет-
приложений? Разве у нас нет Apache Struts (http://struts.apache.org), Apache
Cocoon (http://cocoon.apache.org), Horde (http://www.horde.org), Maypole
(http://maypole.perl.org), Tapestry (http://jakarta.apache.org/tapestry),
WebSphere (http://www.ibm.com/websphere) и целого букета других?
Да, все это у нас есть, но Rails — он другой. Он просто работает. Он спроек-
тирован дальновидно, и чем больше вы копаете, тем больше он вам нравится.
Это не значит, что вы не обнаружите там какие-то недостатки. Проблемы
существуют, так же, как в Ruby, но это не те вопиющие проблемы, которые
вызывают что-то вроде белой горячки, заставляя вас молотить кулаками по
стенкам. Они вызывают лишь некоторую досаду по сравнению с общей мо-
щью Rails. Поэтому я не беспокоюсь о них, и вы не должны.
Неплохо также, что люди, которым вы можете доверять — такие как
Дейв Томас (Dave Thomas) (http://blogs.pragprog.com/cgi-bin/pragdave.cgi),
Майк Кларк (Mike Clark) (http://clarkware.com/cgi/blosxom), Энди Хант
(Andy Hunt) (http://toolshed.com/blog/), Чад Фаулер (Chad Fowler)
(http://www.chadfowler.com) и Джеймс Дункан Дэвидсон (James Duncan
Davidson) (http://www.duncandavidson.com), среди многих других, — отда-
ли Rails все, от всестороннего обсуждения до пылких, завоеванных трудом
оценок. Дэвидсон (Davidson), создатель приложений Tomcat и Ant к Apache
Java, сказал: "Rails является самой продуманной средой разработки интернет-
приложений, которую я когда-либо использовал... Раньше так никто этого не
делал". Тим О'Рейлли (Tim O'Reilly) назвал ее "прорывом за опускающийся
шлагбаум у входа в программирование". Я не смог пройти мимо таких заяв-
лений (http://www.rubyonrails.com/quotes).
Разумеется, Rails подвергается некоторой критике. Вы без труда найдете эти
блоги, а я слишком занят, чтобы тратить энергию на тех, кто ругает Rails,
и это несмотря на то, что сам DHH не часто отказывается от борьбы
(http://weblog.rubyonrails.org). Мои опасения связаны с тем, что мы понем-
ногу приближаемся к кардинальным изменениям наших представлений о про-
Краткий курс по Ruby on Rails 233

граммировании. Я предлагаю вам положиться на современные языки и сред-


ства разработки и участвовать в их усовершенствовании, но из благоразумия
посоветовал бы специально изучать Ruby и Rails. Больших затрат не потре-
буется, а вы окажетесь лучше подготовлены к будущему.
Я думаю, у нас есть немало средств разработки интернет-приложений, т. к.
люди в действительности мало беспокоятся о "конкуренции", какой бы она
ни была. Они заботятся о том, чтобы сделать жизнь и работу легче для себя
и других, с этим они ничего не могут поделать и создают то, что соответству-
ет потребности. Они беспокоятся о том, чтобы среда, в которой они работа-
ют, была более продуктивной и удобной и даже более приятной. Как это
произошло в случае с DHH и другими, кто отважился на вход в креативное
пространство и создал Basecamp, прямого предшественника Rails. Различие
состоит в том, что Rails заставляет людей работать исключительно продук-
тивно, даже если они мало знают о Ruby. А если они не знают Ruby, то учат
его на лету, легко и изящно.
Теперь позвольте мне конкретизировать крутизну Rails.

Полный пакет среды разработки


Rails описывают как полный пакет среды разработки. Что это означает? По
существу, Rails предоставляет все части кода, необходимые для построения
надежных интернет-приложений, в одном аккуратно завязанном пакетике.
Другими словами, вам не нужно прикручивать код для написания XML или
кидаться искать адаптер к базе данных или неумело ощупывать после насту-
пления темноты пакет, чтобы запустить тестирование элементов. Все эти
части уже там. Синонимом к "полному пакету" среды разработки, по крайней
мере, в моей книге, является "хорошо продуманная" среда разработки.

Не повторяйтесь
Rails придерживается философии "don't repeat yourself" или DRY (не повто-
ряйся). DRY поддерживает принцип: в компьютерном программировании вы
не должны и не хотите повторять код или данные. Ruby соответствует такой
концепции.
При DRY данные, информация или код существуют в одном месте, и, следо-
вательно, в случае необходимости, изменения приходится вносить только
в одно это место. Что, естественно, позволяет уменьшить тревогу и количест-
во ошибок, сократить рабский труд и создать счастливых, не страдающих
язвительностью программистов.
234 Глава 11

Соглашение по конфигурации
Rails свободен от XML. Не то чтобы XML был плох в нем или сам по себе
(на мой взгляд), порой неудачны способы его применения — например,
в раздутых конфигурационных файлах. Rails делает это лучше: вместо того
чтобы перегружать конфигурационные файлы подробностями, он использует
"соглашение по конфигурации".
Вот пример того, что это означает. Rails использует простое соглашение для
маршрутизации по URL: имена контроллера (имя класса), операции (имя ме-
тода) и первичного ключа (ID) используются в URL единообразно и, следо-
вательно, не должны доставляться через какие-то другие механизмы. Между
прочим, это соглашение может быть пересмотрено.
Rails не избегает конфигураций полностью. Вы обнаружите файл YAML
(http://www.yaml.org) для конфигурирования базы данных (в database.yml),
ну и довольно об этом.

Хочу мою MVC


Архитектура программного обеспечения "Модель-Вид-Контроллер" (Model-
View-Controller или MVC) стряпает данные, их представление и управляю-
щую логику в трех отдельных горшках вместо одного котла, что существен-
но облегчает отслеживание того, что вы делаете и куда это вас приводит.
Вместо того чтобы смешать все три части, MVC позволяет вам манипулиро-
вать ими, управлять и отслеживать их по отдельности. При Rails схема MVC
разбивается следующим образом.
 Модель.
Архитектура модели организуется при помощи ActiveRecord
(http://api.rubyonrails.org/files/vendor/rails/activerecord/README.html),
слоя кода Rails, который обеспечивает объектно-реляционное отображе-
ние (ORM) между Rails и базой данных, например, MySQL
(http://www.mysql.com), PostgreSQL (http://www.postgresql.org), SQLite
(http://www.sqlite.org) и некоторыми другими. Вы можете использовать
Rails без базы данных, но это не принято.
 Вид.
Просмотровая часть архитектуры управляет представлением данных,
например, в Web-браузере. Файлы с расширением rhtml под Rails могут
обрабатывать HTML в неявном или явном виде, отказываться от XML
или использовать Embedded Ruby (ERB) — подобно JSP, ASP или PHP —
чтобы показать данные из модели или какие бы то ни было еще данные
Краткий курс по Ruby on Rails 235

на ваших страницах rhtml. Этот код пришел из ActionPack


(http://api.rubyonrails.org/files/vendor/rails/actionpack/README.html),
который представляет собой код Rails для управления просмотром и опе-
рациями контроллера.
 Контроллер.
Код контроллера, который, как и просмотр, является частью ActionPack,
принимает входные данные пользователя и реагирует на них функциони-
рованием на модели, а затем подготавливает для показа результат. Резуль-
тат выводится кодом просмотра.

Скрипты
Скрипты в Rails облегчают выполнение таких задач, как:
 запуск Web-сервера аналогично WEBrick, собственности Ruby;
 генерация дополнительных средств (scaffolding) для мгновенного разме-
щения в сети информации из базы данных;
 создание контроллеров и моделей для приложений Rails;
 переход (миграция) на новую схему базы данных и отмена ее для любой
предыдущей версии;
 организация консоли для исследования модели и запуска операций в кон-
троллере.
Доступны также и другие многочисленные скрипты — и это лишь пример
того, что может сделать Rails для уменьшения объема вашей работы.

Подтверждение правильности
В Rails есть методы для подтверждения правильности чего угодно — созда-
ния чего-то, наличия чего-то, размера или длины чего-то и т. д. (см.
http://api.rubyonrails.org/classes/ActiveRecord/Validations/ClassMethods.html).
Например, метод validate_presence_of подтверждает правильность того,
что указанные параметры (symbol) не являются пробелами. В приведенном
далее коде говорится, что параметр title должен быть в объекте и не должен
быть пробелом. Такое подтверждение выполняется при сохранении объекта.
class Novel < ActiveRecord::Base
validates_presence_of :title
end
236 Глава 11

Ajax
Rails поддерживает Ajax или Asynchronous JavaScript and XML. Этот термин
был придуман Джесси Джеймсом Гарреттом (Jesse James Garrett) из Adaptive
Path в начале 2005 года (http://www.adaptivepath.com/publications/essays/
archives/000385.php). Он описывает способность браузера обновить или из-
менить часть Web-страницы посредством объекта XMLHttpRequest, который
позволяет производить такие обновления в фоне (см. http://www.xml.com/
pub/a/2005/02/09/xml-http-request.html). Это всего лишь краткое описание
важной темы на сетевом ландшафте. Rails поддерживает Ajax при помощи
инфраструктуры Prototype JavaScript (http://prototype.conio.net) и библиоте-
ки эффектов Томаса Фача (Thomas Fuch) JavaScript library of effects
(http://script.aculo.us).

Миграции
Как я упоминал в предыдущем разделе, Rails обладает способностью перехо-
дить (мигрировать) с одной схемы базы данных на другую. Эти переходы
выполняются при помощи чистого кода Ruby, а не посредством SQL Data
Definition Language (DDL) или приложения. Даже если у вас есть несколько
версий таблицы, вы можете переключаться между ними, в том числе на пер-
воначальную, одной командой.

Консоль
Rails позволяет тестировать приложения Rails на консоли при помощи
Interactive Ruby (irb), как я уже говорил раньше. Это дает вам возможность
проверить и протестировать код, который существует в ваших моделях,
и вызвать операции в контроллерах. irb позволит вам пройтись по коду шаг
за шагом и понаблюдать, что происходит по дороге. Другими словами, вы
можете работать на грани риска, и если вы определите для консоли режим
"sandbox" (песочница), то все сделанные вами изменения будут отброшены,
когда вы закроете консоль.

Среда и тестирование
Лучшее, что есть в Rails, — это его встроенная среда и тестирование. По умол-
чанию Rails обеспечивает три параллельных среды: разработки, тестирования
и производства. Он позволяет вам свободно творить в одной среде (разработ-
ки), выколачивать ошибки в другой (тестирования) и оттачивать код в треть-
ей, которая спроектирована для общественного потребления (производства).
Краткий курс по Ruby on Rails 237

Среда тестирования поможет вам легко спроектировать и выполнить функ-


циональные тесты и тесты структурных элементов. В смеси также предусмотре-
ны кассеты, содержащие образцы данных в YAML, и доступны имитации (ими-
тация запросов и ответов HTTP). Когда вы готовы предъявить свое приложение
миру, многие обычные беспокойства и страхи оказываются значительно ослаб-
ленными, т. к. большая часть среды тестирования устанавливается автоматиче-
ски, пока вы работаете над своим приложением. Для тестирования структурных
элементов просто выполните rake test_units. Дополнительную информацию
по тестированию с Rails см. в "A Guide to Testing with Rails" ("Руководство по
тестированию в Rails") на http://manuals.rubyonrails.com/read/book/5.

Capistrano
Несмотря на то, что Capistrano (прежде SwitchTower) способен на большее,
в основном он служит как утилита Ruby с хорошо перестраиваемой конфигу-
рацией для безопасной инсталляции приложений одной командой на один
или несколько удаленных серверов. Это средство от головной боли было напи-
сано Джамисом Баком (Jamis Buck) (http://jamis.jamisbuck.org), который
в настоящее время работает в 37signals. Хотя Capistrano и не является частью
Rails, он его ближайший родственник. Информацию о Capistrano вы можете
найти в "Capistrano: Automating Application Deployment" ("Capistrano: автомати-
ческое внедрение приложений") на http://manuals.rubyonrails.com/read/book/17.

Rake
Этот встроенный инструмент, средство построения, поможет вам создать,
скомпилировать и иными способами обработать файлы, количество которых
в проекте иногда бывает весьма значительным. Rake — подобен make
(http://www.gnu.org/software/make) и Apache Ant (http://ant.apache.org), но
написан на Ruby. Он служит не только Rails, но и многим другим приложе-
ниям. Rails в работе часто прибегает к Rake, поэтому последний и заслужил
здесь упоминания.
Для определения того, что нужно сделать, Rake применяет Rakefile. В Rakefile
содержатся именованные задачи. Когда вы создаете в Rails проект, в помощь
вам для разнообразных заданий, таких как выполнение тестов и просмотр
статистики проекта, автоматически формируется Rakefile. (Создав в Rails
проект с помощью одного из указанных далее руководств, запустите из глав-
ного каталога проекта Rails rake --tasks или rake stats, чтобы почувство-
вать вкус того, что делает Rake.)
Rake был написан Джимом Вейрихом (Jim Weirich) (http://onestepback.org).
Документацию по Rake вы найдете на http://rake.rubyforge.org. Хоро-
шее введение в Rake предоставлено Мартином Фаулером (Martin Fowler)
238 Глава 11

на http://www.martinfowler.com/articles/rake.html. Для ознакомления с оп-


циями наберите в командной строке rake --help или прочтите приложение 1.

Что другие делают с Rails?


Rails действительно такой, как говорит вся эта назойливая реклама? Не каза-
лось ли вам, что все это слишком хорошо, чтобы быть правдой? Если так,
я вас не виню. Давайте рассмотрим реальное положение вещей. Просто бро-
сим взгляд на три сайта.
Самым первым приложением Rails является Basecamp, онлайновое, коллек-
тивное средство управления проектом от 37signals. Его 100 000 пользовате-
лей ясно дают понять, что Rails справляется с трафиком и способен в долж-
ной мере все взвесить, чтобы осилить реальную ситуацию один на один.
На рис. 11.1 показано, как это выглядит.

Рис. 11.1. Basecamp


Краткий курс по Ruby on Rails 239

43things (http://www.43things.com), список глобальных дел, — это пример


хорошо выполненного социального программного обеспечения, созданного
Robot Co-op (рис. 11.2). Оно тоже написано в Rails и имеет более 700 000
пользователей (и, вероятно, намного больше к тому времени, как вы это про-
чтете). Понаблюдайте также и за 43places (http://www.43places.com).

Рис. 11.2. 43things

Написанное в Rails приложение Blinksale от Firewheel Design, представлен-


ное на рис. 11.3, обеспечивает простое средство выставления счетов через
Интернет и их отслеживания. Вы также можете посылать напоминания
и благодарности.
240 Глава 11

Рис. 11.3. Blinksale

Basecamp, 43things и Blinksale являются примерами того, на что похож Web 2.0:
ориентированная на пользователя, готовая к сотрудничеству, децентрализо-
ванная. Они прекрасно демонстрируют, на что способны настоящие, приме-
няющие интернет-технологии приложения. В ближайшие годы вы увидите,
как настольные прикладные системы переходят в сеть и как там появляются
новые неслыханные приложения. Изменятся модели, и я предпочел бы быть
в курсе происходящих изменений, а не быть застигнутым ими врасплох, а вы?
Если хотите взглянуть на длинный и все растущий список реальных приложений
Rails, отправляйтесь на http://wiki.rubyonrails.org/rails/pages/RealWorldUsage
или http://happycodr.com и следуйте по указанным ссылкам, сколько душе
угодно. Там масса многообещающих проектов.
Краткий курс по Ruby on Rails 241

Услуги по размещению Rails


Для размещения приложений Rails в сети имеется множество возможностей.
Их растущий список ищите на http://wiki.rubyonrails.com/rails/pages/
RailsWebHosts. TextDrive (http://textdrive.com) является официальным
хостом Ruby on Rails. Мне настоятельно рекомендовали DreamHost
(http://dreamhost.com). За небольшую ежемесячную плату вы можете испы-
тать несколько сайтов и выбрать для себя лучший.

Установка Rails
Перед установкой Rails необходимо установить Ruby версии 1.8.6 или выше
(1.8.4 или 1.8.5 тоже приемлемы, но 1.8.6 лучше). Вероятно, к этому моменту
Ruby у вас уже установлен. Если нет, то я просто раздавлен. Придется воз-
вращаться к главе 1. Пожалуйста, не говорите мне, что вам придется это
сделать!

Применение RubyGems для установки Rails


RubyGems является лучшим средством установки Rails или любого другого
пакета Ruby. Вы получили сведения о RubyGems в предыдущей главе. Вот как
Rails устанавливается с помощью gem на Mac OS X 1.4. Вам необходима ко-
манда sudo, тогда вы сможете работать как привилегированный пользователь,
т. е. тот, кто кроме прочего, обладает соответствующими административными
привилегиями для установки программного обеспечения. От вас потребуется
пароль root или пароль привилегированного пользователя. Наберите:
$ sudo gem install rails --include-dependencies
Password:

На это gem ответит вам чем-то вроде:


$ sudo gem install rails --include-dependencies
Password:
Bulk updating Gem source index for: http://gems.rubyforge.org
(Большое количество обновлений для индекса источника Gem:...)
Successfully installed rails-1.2.3
(Успешно установлен...)
Successfully installed activesupport-1.4.2
Successfully installed activerecord-1.15.3
Successfully installed actionpack-1.13.3
Successfully installed actionmailer-1.3.3
242 Глава 11

Successfully installed actionwebservice-1.2.3


Installing ri documentation for activesupport-1.4.2...
(Установка документации...)
Installing ri documentation for activerecord-1.15.3...
Installing ri documentation for actionpack-1.13.3...
Installing ri documentation for actionmailer-1.3.3...
Installing ri documentation for actionwebservice-1.2.3...
Installing RDoc documentation for activesupport-1.4.2...
Installing RDoc documentation for activerecord-l.15.3...
Installing RDoc documentation for actionpack-1.13.3...
Installing RDoc documentation for actionmailer-l.3.3...
Installing RDoc documentation for actionwebservice-1.2.3...

Так просто. Gems знает, в каких каталогах что размещать. Переключатель


--include-dependencies устанавливает ActiveRecord, ActionPack, ActiveSupport,
Action-Mailer и ActionWebService, не спрашивая, нужен ли вам каждый пакет
по отдельности (это независимые пакеты, упакованные в Rails). Вы также
получаете документацию RDoc.
В Tiger (Mac OS X 1.4), перейдите в командную оболочку и наберите приве-
денную далее команду. В ответ вы получите путь к местонахождению Rails:
$ which rails
/usr/local/bin/rails

Теперь определите версию Rails:


$ rails --version
Rails 1.2.1

А теперь примите небольшую помощь от своего нового друга:


$ rails --help
Usage: /usr/local/bin/rails /path/to/your/app [options]
Options:
-r, --ruby=path Path to the Ruby binary of your choice
(Путь к двоичным файлам Ruby по вашему выбору)
(otherwise scripts use env, dispatchers current path).
(в противном случает скрипты используют env, текущий путь)
Default: /usr/local/bin/ruby
-d, --database=name Preconfigure for selected database (options:
mysql/oracle/postgresql/sqlite2/sqlite3).
(Предварительная конфигурация для выбранной базы данных)
Краткий курс по Ruby on Rails 243

Default: mysql
-f, --freeze Freeze Rails in vendor/rails from the gems
generating the skeleton
(Заморозить Rails в vendor/rails от gems, генерирующих скелет)
Default: false
General Options:
(Общие опции:)
-P, --pretend Run but do not make any changes.
(Выполнить, но не делать никаких изменений.)
--force Overwrite files that already exist.
(Переписать уже существующие файлы.)
-s, --skip Skip files that already exist.
(Пропустить уже существующие файлы.)
-q, --quiet Suppress normal output.
(Подавить нормальный вывод.)
-t, --backtrace Debugging: show backtrace on errors.
(Отладка: показывать для ошибок обратную трассировку.)
-h, --help Show this help message.
(Показывать это справочное сообщение)
-c, --svn Modify files with subversion.
(Note: svn must be in path)
(Модифицировать файлы с помощью подверсии.
(Замечание: svn должна находиться по указанному пути)
Description:
(Описание:)
The 'rails' command creates a new Rails application with a default
directory structure and configuration at the path you specify.
(Команда 'rails' создает новое приложение Rails со структурой
каталогов по умолчанию и конфигурацией по указанному вами пути.)
Example:
(Пример:)
rails ~/Code/Ruby/weblog
This generates a skeletal Rails installation in
~/Code/Ruby/weblog. See the README in the newly created
application to get going.
(Генерируется скелетная установка Rails в ~/Code/Ruby/weblog. Для
решительных действий прочтите README в только что созданном приложении.)
244 Глава 11

WARNING:
(Предупреждение:)
Only specify --without-gems if you did not use gems to install Rails.
Your application will expect to find activerecord, actionpack, and
actionmailer directories in the vendor directory. A popular way to track
the bleeding edge of Rails development is to checkout from source
control directly to the vendor directory. See http://dev.rubyonrails.com
(Только укажите --without-gems, если вы не использовали gems для
установки Rails. Ваше приложение предполагает найти каталоги
activerecord, actionpack и actionmailer в каталоге поставщика
(vendor). Популярный способ отследить передовую линию разработки
Rails состоит в контроле за всем, от управления исходными
текстами до каталога поставщика. См. http://dev.rubyonrails.com)

Дополнительная информация по установке


Лучше всего использовать gem, но есть и другие возможности. Для Mac OS X
вы можете также обратиться на сайт HiveLogic Дэна Бенджамена (Dan
Benjamin), упомянутый в главе 1 (http://hivelogic.com/articles/2005/12/01/
ruby_rails_lighttpd_mysql_tiger). Помимо Ruby и Rails, инструкции Дэна
предоставят вам MySQL и сервер lighttpd. Другой возможностью для Mac OS X
является Locomotive Райана Рауума (Ryan Rauum) (http://locomotive.raaum.org/
home/show/HomePage), который предлагает lighttpd и SQLite. Для Windows
имеется также Instant Rails (http://instantrails.rubyforge.org/wiki/wiki.pl),
который предоставляет Ruby, Rails, сервер Apache и MySQL. Для Linux
предназначен Rails Live CD Брайана Кетельсена (Brian Ketelsen) на
http://www.railslivecd.org.
Когда Ruby и Rails установлены, остается только получать удовольствие.

Изучаем Rails
Вот теперь я уверен, что вам не терпится начать изучать Rails. Я покажу вам,
где можно добыть дополнительную информацию.
Первое, что нужно сделать, — это проследить за изобразительным рядом
на http://www.rubyonrails.org/screencasts. Вы могли бы начать с презен-
тации на коллоквиуме DHH в университете города Роскильде в Дании
(Roskilde University) (http://www.ruc.dk/ruc_en/), произошедшей в 2004 году
(http://media.rubyonrails.org/video/rubyonrails.mov). Фактически это нахо-
дится под заголовком "Presentations" ("Презентации") на странице приведе-
ния экранов; это хороший базовый материал.
Краткий курс по Ruby on Rails 245

Затем посмотрите "Creating a weblog in 15 minutes" ("Создание сетевого


дневника за 15 минут") (http://media.rubyonrails.org/video/rails_take2_with_
sound.mov). Там вы узнаете, как создать из рабочей области полный сетевой
дневник при помощи 58 строк кода, и у вас еще останется время на тестирование.
Затем просмотрите "Putting Flickr on Rails" ("Поставим Flickr на Rails")
(http://media.rubyonrails.org/video/flickr-rails-ajax.mov). За пять минут вы
увидите Rails и Flickr API (http://www.flickr.com/ services/api/), применен-
ные при создании поискового механизма для Flickr, популярного сайта со-
вместного использования фотографий.

ЗАМЕЧАНИЕ
Весь изобразительный ряд выполнен в формате QuickTime Movie (mov)
для Apple.

На этом сайте есть еще одно видео по миграции и полдюжины презента-


ций, на которые стоит посмотреть.

Обучающие руководства и книги по Ruby


Если вы просмотрели указанные сайты, то уже прошли через обучающие
программы в форме видео. Они привели вас на вторую базу. Вот несколько
практичных руководств типа "обучение путем применения", которые помо-
гут вам добраться до "дома".
Билл Уолтон (Bill Walton) и Курт Хиббс (Curt Hibbs) написали великолепное ру-
ководство под названием "Rolling with Ruby on Rails Revisited" ("Прокатимся на
Ruby по переработанным Rails"). Часть I находится на http://www.onlamp.com/
pub/a/onlamp/2006/12/14/revisiting-ruby-on-rails-revisited.html, а часть II —
на http://www.onlamp.com/pub/a/onlamp/2007/01/05/revisiting-ruby-on-rails-
revisited-2.html. Они появились в конце 2006 и начале 2007 года. (Оригина-
лы, написанные Куртом Хиббсом в одиночку, вышли в конце 2005 года. Вы
найдете часть I на http://www.onlamp.com/pub/a/onlamp/2005/01/20/rails.html
и часть II на http://www.onlamp.com/pub/a/onlamp/2005/03/03/rails.html.)
Эти руководства шаг за шагом проведут вас через процесс установки и кон-
фигурирования приложения Rails и сервера MySQL, а затем воспроизведут
интерфейс. Руководства базируются на платформе Windows, поэтому, воз-
можно, вам придется по ходу дела выполнить в реальном времени некую
трансляцию для адаптации их на других платформах. Курт написал также
вместе с Брюсом Тейтом (Bruce Tate) книгу под названием "Ruby on Rails:
Up and Running" ("Ruby on Rails: Установка и эксплуатация"). Версию PDF,
а также версию для печати можно получить со страницы сайта
http://www.oreilly.com/catalog/rubyrails/index.html.
246 Глава 11

Если вы работаете на Mac, у Apple's Developer Connection также есть руково-


дство, "Using Ruby on Rails for Web Development on Mac OS X" ("Применение
Ruby on Rails для сетевых разработок на Mac OS X"), на странице
http://developer.apple.com/tools/rubyonrails.html.
Безошибочным выбором станут "Agile Web Development with Rails" ("Быст-
рые сетевые разработки с помощью Rails") и написанные Дейвом Томасом
(Dave Thomas) и др. и выпущенные издательством Pragmatic. Это необходи-
мая вещь для тех, кто программирует в Rails.

Краткое руководство
Существуют и другие обучающие руководства по Rails, но я не могу не под-
даться искушению предоставить вам еще одно. Оно будет кратким и кротким
с вами — как раз таким, которое позволит начать работу. Не перемудрите;
просто следуйте пошаговым инструкциям и позвольте процессу завершиться.
По пути я поддержу вас несколькими советами.
Я воспользуюсь Rails, чтобы создать простую адресную книгу в Mac OS X;
для UNIX/Linux действия очень похожи, но для Windows вам придется
немного преобразовать шаги. При выполнении этих команд подразумевается,
что Rails и MySQL уже установлены. Если вы пользовались инструкциями
HiveLogic или Instant Rails из разд. "Дополнительная информация по уста-
новке" ранее в этой главе, у вас все должно быть готово.
В командной строке перейдите в свой домашний каталог и просто для уве-
ренности проверьте существование Rails и MySQL. Затем создайте каталог,
в котором будете генерировать проект Rails (address), и переключитесь на
этот новый каталог.
$ cd ~/
$ rails --version
Rails 1.2.3
$ mysql --version
mysql Ver 14.12 Distrib 5.0.27, for apple- darwin8.6.0 (powerpc)
using readline 5.0
$ mkdir address
$ cd address

Пока все нормально? Теперь выполните команду rails с именем


addressbook, и Rails создаст некоторое количество каталогов и файлов.
$ rails addressbook
create
Краткий курс по Ruby on Rails 247

create app/controllers
create app/helpers
create app/models
create app/views/layouts
create config/environments
create components
create db
create doc
create lib
...

К этому моменту вы располагаете приложением Rails в скелетной форме.


Rails проделал для вас невероятный объем работы за несколько секунд. Через
пару минут вы должны понять, о чем я говорю.
Переключитесь на каталог, созданный Rails:
$ cd addressbook

Мы воспользуемся сервером WEBrick, т. к. он не требует никаких других ин-


сталляций с вашей стороны (он упакован вместе с Ruby, так что вы получили
его, когда установили Ruby). Вы могли бы запустить несколько других сер-
веров, но для простоты будем придерживаться WEBrick.

ЗАМЕЧАНИЕ
Обратите внимание на Mongrel — если вы много работаете с Rails,
вам, вероятно, вскоре захочется воспользоваться им. Mongrel — не-
большой быстрый перспективный сервер HTTP, написанный по боль-
шей части на Ruby. Он может выполнять функции сетевой среды, такой
как Rails, непосредственно с HTTP, без использования FastCGI или
SCGI. Дополнительную информацию ищите на странице проекта
Mongrel http://rubyforge.org/projects/mongrel на RubyForge.

Запустите WEBrick такой командой:


$ ./script/server webrick &
=> Booting WEBrick...
=> Rails application started on http://0.0.0.0:3000
=> Ctrl-C to shutdown server; call with --help for options
[2007-01-30 11:43:09] INFO WEBrick 1.3.1
[2007-01-30 11:43:09] INFO ruby 1.8.6 (2006-08-25) [powerpc-darwin8.8.0]
[2007-01-30 11:43:09] INFO WEBrick::HTTPServer#start: pid=863 port=3000
248 Глава 11

ЗАМЕЧАНИЕ
Символ & в конце команды переводит процесс в фоновый режим, по-
этому я могу продолжать использовать командную оболочку. Я пред-
почитаю так и делать. Но не обязываю вас. Между прочим, это не
будет работать в Windows, если только вы не установили что-то вроде
Cygwin (см. http://www.cygwin.com). Чтобы закрыть WEBrick, наберите
fg, затем нажмите комбинацию клавиш <Ctrl>+<C>.

Обычно можно просто набрать ./script/server, не указывая webrick, но


у меня установлен и другой сервер, поэтому я вынужден указать, какой
именно сервер я хочу. В Windows выдайте такую команду: ruby script/
server webrick или ruby script\server webrick.
Выделите URL http://0.0.0.0:3000 (http://127.0.0.1:3000 или
http://localhost:3000 в Windows), скопируйте его, а затем вставьте в строку
адреса или местонахождения вашего браузера. Я пользуюсь Firefox 2
(http://www.mozilla.com/en-US/firefox). На рис. 11.4 показано, что я вижу,
когда Firefox загружает этот URL. Если вы это получили, значит, вы в хоро-
шей форме — готовы "не допустить застоя".

Рис. 11.4. Приветствие Rails в Firefox 2


Краткий курс по Ruby on Rails 249

Давайте заставим MySQL поработать. Подразумевается, что вы его устано-


вили; если нет, см. разд. "Дополнительная информация по установке" ранее
в данной главе. Обычно сервер MySQL загружается, когда вы запускаете
свой компьютер, так что сервисная копия должна у вас функционир о-
вать. (Если нет, то в Mac OS X запустите System Preferences (Системные
привилегии) в меню Apple, щелкните по панели привилегий MySQL, за-
тем нажмите кнопку Start MySQL Server (Запустить сервер MySQL).)
Мы собираемся установить вручную базу данных MySQL при помощи ко-
манды SQL, не применяя сервисного средства GUI (Graphical User Interface;
графический интерфейс пользователя). Так проще, потому что не надо за-
гружать еще один инструмент или пытаться понять, как заставить работать
ваш инструмент, когда он так не похож на мой. Работа несложная — просто
следуйте указаниям и подключайте точки.
Для создания базы данных зарегистрируйтесь как root и введите команду
create database addressbook_developmentи точку с запятой в конце:
$ mysql -u root -p
Enter password:
(Введите пароль:)
Welcome to the MySQL monitor. Commands end with ; or \g.
(Представляем монитор MySQL. Команды заканчиваются ; или \g.)
Your MySQL connection id is 236 to server version: 5.0.27-standard
(Идентификатор подсоединения вашего MySQL — 236 к версии сервера
5.0.27-standard)
Type 'help;' or '\h' for help. Type '\c' to clear the buffer.
(Наберите 'help;' или '\h' для вызова справки. Наберите '\c'
для очистки буфера.)
mysql> create database addressbook_development;
Query OK, 1 row affected (0.00 sec)
(Запрос OK, 1 неисправная строка)

Важно указать имя addressbook_development, т. к. Rails при конфигурирова-


нии автоматически ориентируется на базу данных с этим именем.
Воспользуйтесь командой SQL show databases, выберите нашу новую базу
данных командой use addressbook, а затем наберите show tables, чтобы
убедиться, что в текущей базе данных addressbook еще нет ни одной таблицы.
mysql> show databases;
+--------------------------+
| Database |
+--------------------------+
250 Глава 11

| information_schema |
| addressbook_development |
| mysql |
| test |
+--------------------------+
4 rows in set (0.00 sec)

mysql> use addressbook_development;


Database changed
mysql> show tables;
Empty set (0.06 sec)

Создайте в addressbook таблицу с помощью команды create table с указа-


нием полей для адресной книги — name, address, citystate и т. д.:
mysql> create table addresses (
-> id int not null auto_increment,
-> name varchar(100) not null,
-> address varchar(255) not null,
-> citystate varchar(100) not null,
-> postcode varchar(20) not null,
-> country varchar(100) not null,
-> primary key(id) );
Query OK, 0 rows affected (0.18 sec)

Проконтролируйте свою работу с помощью команд show tables и describe


addresses, затем выйдите из MySQL:
mysql> show tables;
+------------------------------------+
| Tables_in_addressbook_development |
| addresses |
+------------------------------------+
1 row in set (0.00 sec)
mysql> describe addresses;
+----------+-------------+-------+--------+-----------+---------------+
| Field | Type | Null | Key | Default | Extra |
|----------+-------------+-------+--------+-----------+---------------+
| id | itit(11) | NO | PRI | NULL |auto_increment |
| name | varchar(100)| NO | | | |
| address | varchar(255)| NO | | | |
Краткий курс по Ruby on Rails 251

| citystate| varchar(100)| NO | | | |
| postcode | varchar(20) | NO | | | |
| country | varchar(100)| NO | | | |
+----------+-------------+-------+--------+-----------+---------------+
6 rows in set (0.0l sec)
mysql> quit
Bye

В ранних версиях Rails для работы с данной базой необходимо было менять
конфигурационный файл config/database.yml. Теперь Rails выполняет это за
вас автоматически, предполагая, что имя приложения Rails addressbook будет
привязано к базе данных с именем addressbook_development. А это значит,
что вам не нужно менять конфигурационный файл или запускать Web-
сервер.
База данных и таблица на месте, и вы готовы сгенерировать "подмостки"
(scaffolding) для модели и контроллера с помощью простой скриптовой ко-
манды. Вот где колеса встречаются с дорогой: "подмостки" сверхъестествен-
ным образом заставляют все работать. Введите следующий скрипт, чтобы это
произошло:
$ ./script/generate scaffold address address
exists app/controllers/
exists app/helpers/
create app/views/address
exists app/views/layouts/
exists test/functional/
dependency model
exists app/models/
exists test/unit/
exists test/fixtures/
create app/models/address.rb
create test/unit/address_test.rb
create test/fixtures/addresses.yml
create app/views/address/_form.rhtml
create app/views/address/list.rhtml
create app/views/address/show.rhtml
create app/views/address/new.rhtml
create app/views/address/edit.rhtml
create app/controllers/address_controller.rb
252 Глава 11

create test/functional/address_controller_test.rb
create app/helpers/address_helper.rb
create app/views/layouts/address.rhtml
create public/stylesheets/scaffold.css

У скрипта generate scaffold есть параметры address и address. Первый


параметр — это имя модели, которая является слоем объектно-реляционного
отображения (object-relational mapping; ORM) для базы данных
(ActiveRecord), а второй параметр — это имя контроллера, который прини-
мает входные данные пользователя и реагирует действиями на модели, а за-
тем подготавливает результат для выдачи на экран (часть ActionPack). Когда
"подмостки" окажутся на месте, добавьте address к URL, как в
http://0.0.0.0:3000/address, и станете свидетелем чуда (рис. 11.5).

Рис. 11.5. Сгенерированный Rails список

Применив встраиваемый код Ruby (ERB) в list.rhtml (о котором вы узнали


в главе 10), Rails оттранслировал имена в полях таблицы в заголовки столб-
цов таблицы XHTML! Вот пример того, что "подмостки" делают для вас.
Они производят такие файлы, как list.rhtml, new.rhtml, edit.rhtml и т. д., давая
вам возможность загружать данные в таблицу базы данных и обрабатывать
их при помощи сетевого интерфейса.
Просто поразительно, как много работы вы можете не делать благодаря
Rails! Вам достается только приятная возня с приложением, пока оно не ста-
нет таким сетевым приложением, каким вы хотели его видеть.
Время предпринять следующий шаг. Щелкните по ссылке New address, что-
бы вызвать страницу New address (new.rhtml). Введите новый адрес — нечто
похожее на то, что показано на рис. 11.6 — затем нажмите кнопку Create
(Создать); появится страница списка (рис. 11.7) с новым адресом.
Краткий курс по Ruby on Rails 253

Рис. 11.6. Создание нового адреса

Рис. 11.7. Список Rails с новым адресом

Готово. Вот насколько мы продвинулись при помощи этого небольшого ру-


ководства. Щелкните по ссылкам Show, Edit и Destroy и совершите полный
тур по ландшафту.
Чтобы поднять свои разработки в Rails на следующий уровень, воспользуй-
тесь ресурсами, описанными в разд. "Изучаем Rails" ранее в этой главе.
Невозможно оторваться, когда наблюдаешь за теми, кто с помощью Ruby
и Rails так далеко продвигается вперед за относительно короткий период
времени. Приятного времяпрепровождения!
254 Глава 11

Вопросы для самопроверки


1. Из какой программы был извлечен каркас Rails?
2. Что такое MVC?
3. Какая часть Rails оперирует базами данных?
4. Для чего предназначена миграция?
5. Какие приложения использует Rails?
6. Что такое Rake?
7. В чем назначение Capistrano?
8. Какой метод наиболее предпочтителен для установки Rails?
9. Где хранится конфигурация баз данных Rails?
10. В чем состоит роль "подмостков" в Rails?
ПРИЛОЖЕНИЯ
VI Оглавление
Приложение 1

Справочник по Ruby

В этом приложении для удобства собраны все справочные материалы по


языку Ruby. Здесь вы найдете информацию: об опциях интерпретатора, заре-
зервированных (ключевых) словах, операторах, знаках перехода, предопре-
деленных переменных, глобальных константах, регулярных выражениях,
директивах распаковки в String, директивах упаковки в Array, флажках
и полях для sprintf, файловых тестах из Kernel#test, директивах формати-
рования времени, опциях RDoc и Rake.

Интерпретатор Ruby
Синтаксис интерпретатора Ruby:
ruby [ключи] [--] [имя файла с программой] [параметры]

В ключи (или опции командной строки) входят:


 -h — показать допустимые ключи;
 -0[восьмеричное_число] — определить разделитель записей (\0, если нет
параметра);
 -a — установить режим автоматического разбиения с -n или -p ($_ в $F);
 -c — проверять только синтаксис;
 -Cкаталог — перейти в каталог перед выполнением скрипта;
 -d — установить флажки отладки ($DEBUG устанавливается в true);
 -e 'command' — выполнить одну строку скрипта; допускается несколько -e;
опустить [имя файла с программой];
 -Fшаблон — шаблон split() для автоматического разбиения (-a);
 -i[расширение] — редактировать файлы ARGV по месту (если указано
расширение, создается резервная копия);
258 Приложения

 -Iкаталог — определить каталог $LOAD_PATH (этот ключ может быть ис-


пользован несколько раз);
 -Kkcode — определить кодовый набор KANJI (японский);
 -l — разрешить обработку конца строки;
 -n — подразумевать вокруг скрипта цикл 'while gets( ); ... end';
 -p — подразумевать цикл, подобный –n, но печатать строку, подобно sed;
 -rбиблиотека — затребовать библиотеку перед выполнением скрипта;
 -s — разрешить синтаксический анализ некоторых ключей, указанных
после имени скрипта;
 -S — искать скрипт при помощи переменной окружения PATH;
 -T[уровень] — включить проверки порчи;
 -v — напечатать номер версии, затем включить подробный режим;
 -w — включить предупреждения для скрипта;
 -W[уровень] — установить уровень предупреждения: 0 — подавление пе-
чати, 1 — средний уровень, 2 — подробный уровень (по умолчанию);
 -x[каталог] — разобрать текст перед строкой #! ruby и, возможно, из-
менить каталог;
 --copyright — напечатать авторское право;
 --version — напечатать версию (ср. с -v).

Зарезервированные слова языка Ruby


В табл. П1.l перечислены все зарезервированные слова языка Ruby.

Таблица П1.1. Зарезервированные слова языка Ruby

Зарезервирован- Описание
ное слово
BEGIN Код, заключенный в { и }, выполняется до выполнения про-
граммы
END Код, заключенный в { и }, выполняется, когда программа
заканчивается
alias Создает альтернативное имя (псевдоним) для существующе-
го метода, оператора или глобальной переменной
and Логический оператор; то же самое, что &&, только у and бо-
лее низкий приоритет (ср. с or)
Приложение 1. Справочник по Ruby 259

Таблица П1.1 (продолжение)

Зарезервирован- Описание
ное слово
begin Начинает блок кода или группу операторов; закрывается при
помощи end
break Завершает циклы while или until или метод внутри блока
case Сравнивает выражение с соответствующим выражением вы-
бора в операторе when; закрывается при помощи end (см.
when)
class Определяет класс; закрывается при помощи end
def Определяет метод; закрывается при помощи end
defined? Специальный оператор, который определяет, существует ли
переменная, метод, суперметод или блок
do Начинает блок и выполняет код в этом блоке; закрывается
при помощи end
else Выполняет следующий за ним код, если значение предшест-
вующего условия в if, elsif, unless или when не true
elsif Выполняет следующий за ним код, если значение предшест-
вующего условия в if или elsif не true
end Заканчивает блок кода (группу операторов), начинающуюся
с begin, def, do, if и т. д.
ensure Всегда выполняется при завершении блока; используется
после последнего rescue
false Логическая или булевская ложь, экземпляр класса
FalseClass (см. true)
for Начинает цикл for; используется с in
if Выполняет блок кода, если условие имеет значение true.
Закрывается при помощи end (ср. с unless, until)
in Используется в циклах (см. for)
module Определяет модуль; закрывается при помощи end
next Совершает переход в точку перед проверкой условия в цикле
(ср. с redo)
nil Пустая, не проинициализированная или недопустимая пере-
менная, но не то же самое, что 0; объект класса NilClass
not Логический оператор; то же самое, что !
or Логический оператор; то же самое, что ||, только у or более
низкий приоритет (ср. с and)
260 Приложения

Таблица П1.1 (окончание)

Зарезервирован- Описание
ное слово
redo Совершает переход в точку после проверки условия в цикле
(ср. с next)
rescue Вычисляет выражение после возникновения исключения;
используется перед ensure
retry Вне rescue повторяет вызов метода; в rescue совершает
переход к началу блока (begin)
return Возвращает значение из метода или блока. Может быть
опущено
self Текущий объект (вызванный при помощи метода)
super Вызывает метод с тем же самым именем из суперкласса.
Суперкласс — родитель данного класса
then Продолжение для if, unless и when. Может быть опущено
true Логическая или булевская истина, экземпляр класса
TrueClass (см. false)
undef Метод в текущем классе становится неопределенным
unless Выполняет блок кода, если условие имеет значение false
(ср. с if, until)
until Выполняет блок кода, если условие имеет значение false
(ср. с if, unless)
when Начинает выражение выбора (одно или несколько) после
case
while Выполняет код, пока условие имеет значение true
yield Выполняет блок, переданный методу
__FILE__ Имя текущего исходного файла
__LINE__ Номер текущей строки в текущем исходном файле

Операторы
В табл. П1.2 перечислены по старшинству операций все математические
операторы языка Ruby. Если оператор определен как метод, это указы-
вается в колонке "Метод", и этот метод может быть заменен.
Приложение 1. Справочник по Ruby 261

Таблица П1.2. Математические операторы языка Ruby

Оператор Описание Метод


:: Разрешение границ видимости
[] []= Ссылка, множество
** Возведение в степень
+ - ! ~ Унарный плюс, унарный минус, логическое (но не !)
отрицание, дополнение
* / % Умножение, деление, деление по модулю
(остаток)
+ - Сложение, вычитание
<< >> Сдвиг влево, сдвиг вправо
& Побитовое "И"
| ^ Побитовое "ИЛИ", побитовое исключающее
"ИЛИ"
> >= < <= Больше, больше или равно, меньше, мень-
ше или равно
<=> == === != =~ Сравнение на равенство, равенство, равен- (но не !=
!~ ство (например, в диапазоне), неравенство, или !~)
совпадение, несовпадение
&& Логическое "И" (также ключевое слово and,
которое имеет более низкий приоритет)
|| Логическое "ИЛИ" (также ключевое слово
or, которое имеет более низкий приоритет)
.. ... Диапазон включающий; диапазон исклю- (но не ...)
чающий
?: Трехместный оператор
= += -= *= /= %= Присваивание, сокращенное присваивание
**= <<= >>= &=
|= ^= &&= ||=
not Логическое отрицание
and or Логическая композиция
defined? Специальный оператор (без приоритета)

Escape-символы
В табл. П1.3 перечислены все escape-символы языка Ruby.
262 Приложения

Таблица П1.3. Escape-символы (непечатаемые символы)

Обозначение Шестнадцатеричное Описание


с обратной представление
косой чертой
\a 0x07 "Звонок" или предупреждение
\b 0x08 Возврат (backspace)
\cx Ctrl-x
\C-x Ctrl-x
\e 0x1b Esc
\f 0x0c Перевод страницы (FF, Formfeed)
\M-\C-x Meta-Ctrl-x
\n 0x0a Перевод строки (newline)
\nnn Восьмеричное обозначение,
где n — в диапазоне 0—7
\r 0x0d Возврат каретки (Carriage return)
\s 0x20 Пробел (Space)
\t 0x09 Табуляция (Tab)
\v 0x0b Вертикальная табуляция
\x Символ x
\xnn Шестнадцатеричное обозначение,
где n — в диапазоне 0—9, a—f или A—F

Предопределенные переменные
В табл. П1.4 перечислены все предопределенные переменные языка Ruby.

Таблица П1.4. Предопределенные переменные

Предопределенная Описание
переменная
$! Сообщение об исключении, содержащее информацию о
последнем возникшем исключении. Эту переменную уста-
навливает raise. Доступна с помощью => в операторе
rescue
$@ Обратная трассировка стека для последнего исключения,
восстанавливается через Exception#backtrace
Приложение 1. Справочник по Ruby 263

Таблица П1.4 (продолжение)

Предопределенная Описание
переменная
$& Строка, соответствующая последнему успешному сравне-
нию с шаблоном в этой области видимости, или nil, если
последнее сравнение потерпело неудачу. То же самое,
что m[0], где m — объект MatchData. Только для чтения.
Локальная
$` Строка, предшествующая тому, что соответствовало по-
следнему успешному сравнению с шаблоном в этой области
видимости, или nil, если последнее сравнение потерпело
неудачу. То же самое, что m.pre_match, где m — объект
MatchData. Только для чтения. Локальная
$' Строка, следующая за тем, что соответствовало последнему
успешному сравнению с шаблоном в этой области видимости,
или nil, если последнее сравнение потерпело неудачу.
То же самое, что m.post_match где m — объект MatchData.
Только для чтения. Локальная
$+ Последняя скобка, соответствующая последнему успешно-
му поиску шаблона, или nil, если последнее сравнение
потерпело неудачу. Удобно, если вы не знаете, какой из
альтернативных шаблонов подошел. Только для чтения.
Локальная
$1, $2, ... Подшаблон из соответствующего множества скобок в по-
следнем успешном сравнении с шаблоном, не считая сов-
павших шаблонов во вложенных блоках, из которых уже был
осуществлен выход, или nil, если последнее сравнение
потерпело неудачу. То же самое, что m[n], где m — объект
MatchData. Только для чтения. Локальная
$~ Информация о последнем совпадении в текущей области
видимости. Regex#match возвращает информацию о по-
следнем совпадении. Установка этой переменной оказывает
влияние на такие переменные совпадения, как $&, $+, $1,
$2 и т. д. n-ое подвыражение можно извлечь при помощи
$~[n]. Локальная
$= Флажок независимости от регистра; nil по умолчанию
$/ Разделитель вводимой записи; по умолчанию newline.
Работает как переменная RS из awk. Если установить nil,
то за один раз будет прочитан целый файл. gets, readline
и т. д. принимают в качестве необязательного параметра
разделитель вводимой записи
264 Приложения

Таблица П1.4 (продолжение)

Предопределенная Описание
переменная
$\ Разделитель выводимой записи для печати и IO#write;
nil по умолчанию
$, Разделитель выводимых полей между параметрами; а так-
же разделитель по умолчанию для Array#join, который
позволяет указать разделитель в явном виде
$; Разделитель по умолчанию для String#split; nil по
умолчанию
$. Номер текущей вводимой строки последнего прочитанного
файла. То же самое, что ARGF.lineno
$< Виртуальный файл, объединяющий файлы, заданные в па-
раметрах командной строки, или стандартное устройство
ввода (в случае, если имена файлов не заданы).
$<.filename возвращает имя текущего файла. Синоним
для ARGF
$> Вывод по умолчанию для print, printf и $stdout. Сино-
ним для $defout
$_ Последняя строка текста строки, вводимой при помощи
gets или readline в текущей области видимости; устанав-
ливается в nil, если gets или readline повстречает EOF.
Локальная
$0 Имя текущей выполняющейся программы на языке Ruby
$* Параметры для скрипта, заданные в командной строке. Оп-
ции для интерпретатора Ruby уже удалены
$S Номер процесса (process.pid) для выполняемой про-
граммы на языке Ruby
$? Выходной статус последнего выполненного процесса
$: Синоним для $LOAD_PATH
$" Массив, содержащий имена модулей, загруженных по
require. Используется для предотвращения повторной
загрузки модулей
$DEBUG true, если установлен ключ -d или -debug
$defout Вывод по умолчанию для print, printf и $stdout. Сино-
ним для $>
$F Получает выходные данные из split, если указан ключ –a.
Устанавливается, если установлен -a вместе с -p или -n
Приложение 1. Справочник по Ruby 265

Таблица П1.4 (окончание)

Предопределенная Описание
переменная
$FILENAME Имя файла, читаемого в настоящее время из ARGF. То же
самое, что ARGF.filename или %<.filename
$LOAD_PATH Синоним для $:
$SAFE Уровень безопасности:
0 — разрешается не проверять поставляемые извне (де-
фективные) данные (по умолчанию);
1 — запрещены потенциально опасные операции, исполь-
зующие дефективные данные;
2 — запрещены потенциально опасные операции, выпол-
няемые на процессах и файлах;
3 — считаются дефективными все заново создаваемые
объекты;
4 — запрещена модификация глобальных данных
$stdin Текущее стандартное устройство ввода; STDIN по умол-
чанию
$stdout Текущее стандартное устройство вывода; STDOUT по умол-
чанию
$stderr Текущее стандартное устройство вывода ошибок; STDERR
по умолчанию
$VERBOSE true, если установлен флажок подробностей с помощью
ключей -v, -w или –verbose интерпретатора Ruby
$-0 Альтернативное имя для $/
$-a true, если установлена опция -a. Только для чтения
$-d Альтернативное имя для $DEBUG
$-F Альтернативное имя для $;
$-i В режиме редактирования по месту содержит расширение;
в противном случает nil. Может включать и отключать ре-
жим редактирования по месту
$-I Альтернативное имя для $:
$-l true, если установлена опция -lis. Только для чтения
$-p true, если установлена опция -pis. Только для чтения
266 Приложения

Глобальные константы
В табл. П1.5 перечислены все глобальные константы языка Ruby.

Таблица П1.5. Глобальные константы

Константа Описание

ARGF Поток, подобный вводу/выводу, который санкционирует


доступ к виртуальному объединению всех файлов из ко-
мандной строки, или стандартное устройство ввода, если
файлы не указаны. Синоним для $<
ARGV Массив, который содержит все параметры из командной
строки, передаваемые программе. Синоним для $*
DATA Входной поток для чтения строк кода, за которыми следует
директива __END__. Не определен, если __END__ в коде
не присутствует
ENV Объект, похожий на хэш, который содержит переменные
среды программы; может обрабатываться как хэш
FALSE Синоним для false; false предпочтительнее
NIL Синоним для nil; nil предпочтительнее
PLATFORM Синоним для RUBY_PLATFORM. Укорочено
RELEASE_DATE Синоним для RUBY_RELEASE_DATE. Укорочено
RUBY PLATFORM Строка, указывающая платформу интерпретатора Ruby;
например, "powerpc-darwin 8.8.0"
RUBY RELEASE DATE Строка, указывающая дату выпуска интерпретатора Ruby;
например, "2006-08-25"
RUBY_VERSION Версия Ruby; например, "1.8.5"
STDERR Стандартный поток для вывода ошибок со значением по
умолчанию $stderr
STDIN Стандартный поток ввода со значением по умолчанию
$stdin
STDOUT Стандартный поток вывода со значением по умолчанию
$stdout
TOPLEVEL_BINDING Объект Binding на верхнем уровне Ruby
TRUE Синоним для true; true предпочтительнее
VERSION Синоним для RUBY_VERSION. Укорочено
Приложение 1. Справочник по Ruby 267

Регулярные выражения
В табл. П1.6 перечислены регулярные выражения в языке Ruby.
Таблица П1.6. Регулярные выражения в языке Ruby

Шаблон Описание
/pattern/опции Шаблон pattern между двумя косыми чертами, за которым
следуют необязательные опции, т. е. один или несколько сим-
волов: i — независимость от регистра; о — подстановка; x —
игнорирование пробельных символов, допускаются коммента-
рии; m — сопоставление нескольких строк текста, символы пе-
ревода строки считаются обычными символами
%r!pattern! Основная строка с разделителями для регулярного выражения,
где ! — произвольный символ
^ Соответствует началу строки текста
$ Соответствует концу строки текста
. Соответствует любому символу
\1...\9 Соответствует n-ому групповому подвыражению
\10 Соответствует n-ому групповому подвыражению, если соответ-
ствие уже найдено; в противном случае ссылается на восьме-
ричное представление кода символа
\n, \r, \t и т. д. Соответствует символу в обозначении с обратной косой чертой
\w Соответствует символу слова; то же, что [0-9A-Za-z]
\W Соответствует символу неслова
\s Соответствует пробельному символу, как в [\t\n\r\f]
\S Соответствует непробельному символу
\d Соответствует цифре, то же что [0-9]
\D Соответствует нецифре
\A Соответствует началу строки
\Z Соответствует концу строки или символу перед символом пе-
ревода строки в конце строки
\z Соответствует концу строки
\b Соответствует границе слова снаружи [] или символу возвра-
та каретки (0x08) внутри []
\B Соответствует границе неслова
\G Соответствует точке, где закончилось последнее совпадение
268 Приложения

Таблица П1.6 (продолжение)

Шаблон Описание
[..] Соответствует любому единичному символу в квадратных
скобках
[^..] Соответствует любому единичному символу не в квадратных
скобках
* Соответствует нулевому (или большему) количеству предыду-
щих регулярных выражений
*? Соответствует нулевому (или большему) количеству предыду-
щих регулярных выражений (не поглощающий)
+ Соответствует одному или нескольким предыдущим регуляр-
ным выражениям
+? Соответствует одному или нескольким предыдущим регуляр-
ным выражениям (не поглощающий)
{m} Соответствует в точности m предыдущим регулярным выраже-
ниям
{m,} Соответствует, по меньшей мере, m предыдущим регулярным
выражениям
{m,n} Соответствует, по меньшей мере, m, но самое большее n пре-
дыдущим регулярным выражениям
{m,n}? Соответствует, по меньшей мере, m, но самое большее n пре-
дыдущим регулярным выражениям (не поглощающий)
? Соответствует нулевому количеству или одному предыдущему
регулярному выражению
| Чередование, как color | colour
( ) Группирование регулярных выражений или подвыражений, как
col(o|ou)r
(?#..) Комментарий
(?:..) Группирование без обратных ссылок (без запоминания сопос-
тавленного текста)
(?=..) Определяет позицию с шаблоном
(?!..) Определяет позицию с отрицанием шаблона
(?>..) Определяет независимый шаблон без поиска с возвратом
(?imx) Включает опции i, m или x
(?-imx) Отключает опции i, m или x
(?imx:..) Включает опции i, m или x внутри круглых скобок
Приложение 1. Справочник по Ruby 269

Таблица П1.6 (окончание)

Шаблон Описание
(?-imx:..) Отключает опции i, m или x внутри круглых скобок
(?ix-ix: ) Включает (или выключает) опции i и x внутри этой неохвачен-
ной группы
[:alnum:] Символьный класс POSIX для буквенно-цифровых символов
[:alpha:] Символьный класс POSIX для букв верхнего и нижнего реги-
стров
[:blank:] Символьный класс POSIX для пробела и символа табуляции
[:cntrl:] Символьный класс POSIX для управляющих символов
[:digit:] Символьный класс POSIX для цифр
[:graph:] Символьный класс POSIX для печатаемых символов (но без
пробела)
[:lower:] Символьный класс POSIX для букв нижнего регистра
[:print:] Символьный класс POSIX для печатаемых символов (включая
пробел)
[:punct:] Символьный класс POSIX для печатаемых символов (но без
пробела и буквенно-цифровых символов)
[:space:] Символьный класс POSIX для непробельных символов
[:upper:] Символьный класс POSIX для букв верхнего регистра
[:xdigit:] Символьный класс POSIX для шестнадцатеричных цифр: A—F,
a—f и 0—9

Директивы распаковки в String


В табл. П1.7 перечислены директивы распаковки для String#unpack.

Таблица П1.7. Директивы распаковки в String

Директива Возвращает Описание


A String Удаляет конечные нулевые символы и пробелы
a String Строка
B String Извлекает биты из каждого символа (наибольший зна-
чащий бит первым)
b String Извлекает биты из каждого символа (наименьший зна-
чащий бит первым)
270 Приложения

Таблица П1.7 (продолжение)

Директива Возвращает Описание


C Fixnum Извлекает символ как целое число без знака
c Fixnum Извлекает символ как целое число
d, D Float Обрабатывает sizeof(double) символов как "род-
ное" число с плавающей точкой с двойной точностью
E Float Обрабатывает sizeof(double) символов как число
с плавающей точкой с двойной точностью с прямым
порядком байтов (сначала наименьшие значащие)
e Float Обрабатывает sizeof(float) символов как число
с плавающей точкой с прямым порядком байтов (сна-
чала наименьшие значащие)
f, F Float Обрабатывает sizeof(float) символов как "родное"
число с плавающей точкой
G Float Обрабатывает sizeof(double) символов как число
с плавающей точкой с двойной точностью с сетевым
порядком байтов (сначала наибольшие значащие)
g Float Обрабатывает sizeof(float) символов как число
с плавающей точкой с сетевым порядком байтов (сна-
чала наибольшие значащие)
H String Извлекает шестнадцатеричные полубайты из каждого
символа (наибольший значащий бит первым)
h String Извлекает шестнадцатеричные полубайты из каждого
символа (наименьший значащий бит первым)
I Integer Обрабатывает sizeof(int) соседних символов
(модифицированных при помощи _) как "родное"
целое без знака
i Integer Обрабатывает sizeof(int) соседних символов
(модифицированных при помощи _) как "родное"
целое со знаком
L Integer Обрабатывает четыре соседних символа (модифици-
рованных с помощью _) как "родное" длинное целое
без знака
l Integer Обрабатывает четыре соседних символа (модифици-
рованных с помощью _) как "родное" длинное целое со
знаком
M String Печатаемые символы в кавычках
m String В кодировке Base64
Приложение 1. Справочник по Ruby 271

Таблица П1.7 (окончание)

Директива Возвращает Описание


N Integer Обрабатывает четыре символа как длинное целое
число без знака с сетевым порядком байтов (сначала
наибольшие значащие)
n Fixnum Обрабатывает два символа как короткое целое число
без знака с сетевым порядком байтов (сначала наи-
большие значащие)
P String Обрабатывает sizeof(char*) символов как указа-
тель и возвращает \emph{len} символов с указанной
позиции
p String Обрабатывает sizeof(char*) символов как указа-
тель на строку, заканчивающуюся нулевым символом
Q Integer Обрабатывает восемь символов как четыре слова без
знака (64 бита)
q Integer Обрабатывает восемь символов как четыре слова со
знаком (64 бита)
S Fixnum Обрабатывает два (различных, если используется _)
соседних символа как короткое целое без знака с
"родным" порядком байтов
s Fixnum Обрабатывает два (различных, если используется _)
соседних символа как короткое целое со знаком с
"родным" порядком байтов
U Integer Символы UTF-8 как целые без знака
u String В кодировке UU
V Fixnum Обрабатывает четыре символа как длинное целое
число без знака с прямым порядком байтов (сначала
наименьшие значащие)
v Fixnum Обрабатывает два символа как короткое целое число
без знака с прямым порядком байтов (сначала наи-
меньшие значащие)
w Integer Сжатое по BER целое число (см. Array#pack)
X Переход назад на один символ
x Переход вперед на один символ
Z String Конечные нулевые символы удаляются до первого
нулевого символа с *
@ Переход на смещение, заданное параметром длины
272 Приложения

Директивы упаковки в Array


В табл. П1.8 перечислены директивы упаковки для использования с Array#pack.
Таблица П1.8. Директивы упаковки в Array

Директива Описание

@ Перемещение в абсолютную позицию


A Строка ASCII (заполняется пробелами; подсчет по ширине)
a Строка ASCII (заполняется null; подсчет по ширине)
B Битовая строка (убывающий порядок битов)
b Битовая строка (возрастающий порядок битов)
C Символ без знака
c Символьный тип
D, d Число с плавающей точкой с двойной точностью, "родной" формат
E Число с плавающей точкой с двойной точностью, прямой порядок
байтов (сначала наименьшие значащие)
e Число с плавающей точкой с одинарной точностью, прямой порядок
байтов (сначала наименьшие значащие)
F, f Число с плавающей точкой с одинарной точностью, "родной" формат
G Число с плавающей точкой с двойной точностью, сетевой (обрат-
ный) порядок байтов (сначала наибольшие значащие)
g Число с плавающей точкой с одинарной точностью, сетевой (обрат-
ный) порядок байтов (сначала наибольшие значащие)
H Шестнадцатеричная строка (сначала старшие полубайты)
h Шестнадцатеричная строка (сначала младшие полубайты)
I Целое без знака
i Целое
L Длинное целое без знака
l Длинное целое
M Печатаемые символы в кавычках, кодировка MIME (см. RFC 2045)
m Строка в кодировке Base64
N Длинное целое, сетевой (обратный) порядок байтов (сначала наи-
большие значащие)
n Короткое целое, сетевой (обратный) порядок байтов (сначала наи-
большие значащие)
Приложение 1. Справочник по Ruby 273

Таблица П1.8 (окончание)

Директива Описание
P Указатель на структуру (строка фиксированной длины)
p Указатель на строку, заканчивающуюся нулевым символом
Q, q 64-битовое число
S Короткое целое без знака
s Короткое целое
U UTF-8
u Строка в кодировке UU
V Длинное целое, прямой порядок байтов (сначала наименьшие зна-
чащие)
v Короткое целое, прямой порядок байтов (сначала наименьшие зна-
чащие)
w Сжатое по BER целое\fnm
X Резервное копирование байта
x Нулевой байт
Z То же самое, что a, но нулевой символ добавляется со *

Флажки и типы полей для sprintf


В табл. П1.9 и П1.10 перечислены флажки и типы полей для Kernel#sprintf
(или его синонима Kernel#format), соответственно.

Таблица П1.9. Флажки для sprintf

Флажок Для типов Описание


полей
[пробел] bdeEfgGiouxX Помещает пробел в начало положительного числа
[1-9]$ Все типы полей Абсолютный номер параметра для этого поля
# beEfgGoxX Для поля b результату предшествует 0b; для o — 0;
для x — 0x; для X — 0X; для e, E, f, g и G добавля-
ется десятичная точка; для g и G не удаляются хво-
стовые пробелы
+ bdeEfgGiouxX Добавляет перед положительными числами знак
плюс (+)
274 Приложения

Таблица П1.9 (окончание)

Флажок Для типов Описание


полей
- Все типы полей Выравнивает результат влево
0 bdeEfgGiouxX Дополняет результаты нулями (0) вместо пробелов
* Все типы полей Использует следующий параметр как ширину поля.
Если он отрицательный, выравнивает результат
влево. Если за звездочкой (*) следует число и знак
доллара ($), использует параметр как ширину

Таблица П1.10. Типы полей для sprintf

Поле Описание
b Преобразует числовой параметр в двоичное число
с Преобразует числовой параметр (код символа) в символ
d Преобразует числовой параметр в десятичное число. То же самое,
что i
e Преобразует параметр с плавающей точкой в экспоненциальное пред-
ставление, с использованием одной цифры перед десятичной точкой.
По умолчанию в дробной части устанавливается шесть цифр (ср. с g)
E То же самое, что e, но в результате используется E
f Преобразует числовой параметр в число с плавающей точкой. По умол-
чанию в дробной части устанавливается шесть цифр. Количество цифр
дробной части определяется точностью
g Преобразует числовой параметр в число с плавающей точкой; исполь-
зует экспоненциальную форму, если экспонента меньше, чем -4, или
больше или равна точности, в противном случае использует форму
d.dddd (ср. с e)
G То же самое, что g, но в результате используется E
i Преобразует числовой параметр в десятичное число. То же самое,
что d
о Преобразует числовой параметр в восьмеричное число
p То же самое, что argument.inspect, где inspect предоставляет пе-
чатаемую версию параметра, с удаленными специальными символами
s Подставляет параметр как строку. Если форматирующая строка содер-
жит точность, то в подстановку копируется не менее указанного количе-
ства символов
Приложение 1. Справочник по Ruby 275

Таблица П1.10 (окончание)

Поле Описание
u Трактует параметр как десятичное число без знака. Отрицательные
числа для базовой архитектуры показываются как 32-битовое дополне-
ние до двух плюс единица (например, 2**32+n). Так как в Ruby нет соб-
ственного лимита на количество битов, используемых для представле-
ния целого числа, отрицательным значениям предшествуют две точки,
обозначающие бесконечное количество лидирующих знаковых битов
x Преобразует числовой параметр в шестнадцатеричное число со строч-
ными буквами от a до f. Отрицательные числа показываются с двумя
предшествующими точками, обозначающими бесконечную строку лиди-
рующих ff
X То же самое, что x, но в результате используются заглавные буквы от A
до F. Отрицательные числа показываются с двумя предшествующими
точками, обозначающими бесконечную строку лидирующих FF

Файловые тесты
В табл. П1.11 и П1.12 перечислены файловые тесты из Kernel#test для од-
ного и двух файлов, соответственно.

Таблица П1.11. Файловые тесты

Тест Возвращает Содержание


?A Time Время последнего доступа к file1
?b Boolean true, если file1 — блочное устройство ввода/вывода
?c Boolean true, если file1 — посимвольное устройство вво-
да/вывода
?C Time Время последнего изменения file1
?d Boolean true, если file1 существует и является каталогом
?e Boolean true, если file1 существует
?f Boolean true, если file1 существует и является обычным файлом
?g Boolean true, если file1 имеет установку битов \CF{setgid}
(false под NT)
?G Boolean true, если file1 существует и относится к групповому вла-
дению, идентичному группе вызывающей программы
?k Boolean true, если file1 существует и имеет установку sticky bit
276 Приложения

Таблица П1.11 (окончание)

Тест Возвращает Содержание


?l Boolean true, если file1 существует и является символической
ссылкой
?M Time Время последней модификации file1
?o Boolean true, если file1 существует и является собственностью
действующего UID (идентификатора пользователя) вызы-
вающей программы
?O Boolean true, если file1 существует и является собственностью
реального UID вызывающей программы
?p Boolean true, если file1 существует и это FIFO
?r Boolean true, если file1 читается действующим UID/GID (иденти-
фикатором группы) вызывающей программы
?R Boolean true, если file1 читается реальным UID/GID вызывающей
программы
?s Int/nil Если file1 имеет ненулевую длину, то возвращается его
размер; в противном случае возвращается nil
?S Boolean true, если file1 существует и является сокетом
?u Boolean true, если file1 имеет установку setuid bit
?w Boolean true, если file1 существует и перезаписывается дейст-
вующим UID/GID
?W Boolean true, если file1 существует и перезаписывается реаль-
ным UID/GID
?x Boolean true, если file1 существует и выполняется действующим
UID/GID
?X Boolean true, если file1 существует и выполняется реальным UID/GID
?z Boolean true, если file1 существует и имеет нулевую длину

Таблица П1.12. Файловые тесты для двух файлов

Тест Возвращает Описание


?- Boolean true, если file1 и file2 идентичны
?= Boolean true, если время модификации file1 и file2 совпадает
?< Boolean true, если время модификации file1 меньше времени
модификации file2
?> Boolean true, если время модификации file1 больше времени
модификации file2
Приложение 1. Справочник по Ruby 277

Директивы форматирования времени


Директивы, перечисленные в табл. П1.13, используются совместно с методом
Time#strftime.

Таблица П1.13. Директивы форматирования времени

Директива Описание

%a Сокращенное название дня недели (Sun)


%A Полное название дня недели (Sunday)
%b Сокращенное название месяца (Jan)
%B Полное название месяца (January)
%c Предпочтительное представление местной даты и времени
%d День месяца (01—31)
%H Час дня, 24-часовое время (00—23)
%I Час дня, 12-часовое время (01—12)
%j День года (001—366)
%m Месяц года (01—12)
%M Минута часа (00—59)
%p Меридиональный индикатор (AM или PM)
%S Секунды в минуте (00—60)
%U Номер недели текущего года, начиная с первого воскресенья как
первого дня первой недели (00—53)
%W Номер недели текущего года, начиная с первого понедельника как
первого дня первой недели (00—53)
%w День недели (0—6; воскресенье — 0)
%x Предпочтительное представление одной даты, без времени
%X Предпочтительное представление времени, без даты
%y Год без столетия (00—99)
%Y Год со столетием
%Z Название часового пояса
%% Символ литерала %
278 Приложения

Опции RDoc
Опции RDoc применяются таким образом:
rdoc [опции] [имена...]

Файлы подвергаются синтаксическому анализу, а находящаяся в них инфор-


мация накапливается, и лишь затем производится вывод результатов. Это по-
зволяет разрешить перекрестные ссылки между всеми файлами. Если имя
в командной строке является именем каталога, то происходит переход в этот
каталог. Если имена в командной строке не указаны, то обрабатываются все
файлы Ruby в текущем каталоге (и подкаталогах).
Опции включают:
 --accessor, -A accessorname[,..] — разделенный запятыми список до-
полнительных методов класса, которые должны обрабатываться как
attr_reader и "друзья" класса. Опция может быть повторена. Каждое имя
accessorname может иметь дополнение =text в конце, в этом случае
указанный текст появится там, где для обычных аксессоров появл я-
ется r/w/rw;
 --all, -a — включить в результат все методы (а не только public);
 --charset, -c charset — определить набор символов HTML;
 --debug, -D — показать внутреннюю информацию;
 --diagram, -d — сгенерировать диаграммы, показывающие модули и
классы. Чтобы опция --diagram использовалась корректно, необходим dot
v 1.8.6 или выше. Dot доступен на http://www.research.att.com/
sw/tools/graphviz;
 --exclude, -x pattern — не обрабатывать файлы или каталоги, соответ-
ствующие pattern. Файлы, заданные в командной строке явно, не будут
исключены;
 --extension, -E new=old — обращаться с файлами, имена которых закан-
чиваются на .new, так, как если бы они заканчивались на .old. Использо-
вание '-E cgi=rb' заставит синтаксический разбор считать xxx.cgi фай-
лом Ruby;
 --fileboxes, -F — классы помещаются в прямоугольники, представляю-
щие файлы, в которых постоянно хранятся эти классы. Классы, совместно
используемые несколькими файлами, показаны со списком таких файлов.
Отбрасываются, если в --diagram не задано Experimental;
 --fmt, -f chm/html/ri/xml — установить средство форматирования вы-
ходных данных. Доступные форматеры — chm, html, ri и xml;
Приложение 1. Справочник по Ruby 279

 --help, -h — вывод справочных сведений;


 --help-output, -O — объясняет различные опции вывода результата;
 --image-format, -I gif/png/jpg/jpeg — установить формат вывода изо-
бражения для диаграмм. Возможны форматы: png, gif, jpeg, jpg. Если эта
опция опущена, то используется png. Требуется –diagram;
 --include, -i dir[,dir...] — установить (или добавить) список катало-
гов, которые будут просматриваться для удовлетворения запросов
:include:. Можно использовать несколько раз;
 --inline-source, -S — показывать исходный текст метода по месту, а не
через всплывающую ссылку;
 --line-numbers, -N — включать в исходный текст номера строк;
 --main, -m name — первоначальной показанной страницей будет name;
 --merge, -M — при создании выходных данных ri, merge перерабатывает
классы в ранее документированные классы с именем name;
 --one-file, -1 — поместить все выходные данные в единственный файл;
 --op, -o dir — установить каталог для выходных данных;
 --opname, -n name — установить имя выходных данных. Не действует для
HTML;
 --promiscuous, -p — при документировании файла, который содержит
модуль или класс, определенный также в других файлах, показывать всю
информацию для этого модуля/класса на странице каждого файла. По
умолчанию, показывать только информацию, определенную в этом от-
дельном файле;
 --quiet, -q — не показывать продвижение при синтаксическом анализе;
 --ri, -r — генерировать выходные данные для использования в ri. Фай-
лы сохраняются в каталоге .rdoc под вашим личным каталогом, если толь-
ко это не было изменено последующим параметром --op. Отсутствует не-
обходимость в особых привилегиях;
 --ri-site, -R — генерировать выходные данные для использования в ri.
Файлы сохраняются в общем каталоге сайта, что делает их доступными
для других, следовательно, необходимы особые привилегии;
 --ri-system, -Y — генерировать выходные данные для использования
в ri. Файлы сохраняются в каталоге системного уровня, что делает их
доступными для других, следовательно, необходимы особые привилегии.
Эта опция предназначена для использования во время установок Ruby;
280 Приложения

 --show-hash, -H — имя формы #name в комментарии является возможной


гиперссылкой на имя метода экземпляра класса. При показе # удаляется,
если только не задана эта опция;
 --style, -s stylesheet url — определяет URL отдельной таблицы сти-
лей;
 --tab-width, -w n — установить ширину символов табуляции (по умол-
чанию 8);
 --template, -T template name — установить шаблон, используемый при
генерации выходных данных;
 --title, -t text — установить text в качестве заголовка для выходных
данных;
 --version, -v — показать версию RDoc;
 --webcvs, -W url — указать URL для компоновки с сетевым пользова-
тельским интерфейсом к CVS. Если URL содержит "%s", то имя текущего
файла будет подставлено; если URL не содержит "%s", то имя файла будет
добавлено в конец.
Для получения информации о том, куда направляются выходные данные,
наберите:
rdoc --help-output

То, как RDoc генерирует результаты, зависит от применяемого форматера


выходных данных и от заданных вами опций.
 Выходные данные HTML обычно выводятся в несколько отдельных файлов
(по одному на класс, модуль и файл, наряду с различными индексами). Эти
файлы появятся в каталоге, заданном опцией --op (по умолчанию doc/).
 Выходные данные XML по умолчанию записываются на стандартное уст-
ройство вывода. Если задана опция --opname, то вместо этого выходные
данные будут записаны в файл с указанным именем в каталог выходных
данных.
 Файлы chm (справочные файлы Windows) записываются в каталог
--op. Если присутствует параметр --opname, используется указанное
в нем имя; в противном случае файл будет назван rdoc.chm.

Rake
Этот встроенный инструмент, средство построения, поможет вам создать,
скомпилировать и иными способами обработать файлы, количество которых
в проекте иногда бывает весьма значительным. Rake — подобен make
(http://www.gnu.org/software/make) и Apache Ant (http://ant.apache.org),
Приложение 1. Справочник по Ruby 281

но написан на Ruby. Он служит не только Rails, но и многим другим прило-


жениям. Rails в работе часто прибегает к Rake, поэтому последний и заслу-
жил здесь упоминания.
Для определения того, что нужно сделать, Rake применяет Rakefile. В Rakefile
содержатся именованные задачи. Когда вы создаете в Rails проект, в помощь
вам для разнообразных заданий, таких как выполнение тестов и просмотр
статистики проекта, автоматически формируется Rakefile. (Создав в Rails
проект с помощью одного из указанных далее руководств, запустите из глав-
ного каталога проекта Rails rake --tasks или rake stats, чтобы почувство-
вать вкус того, что делает Rake.)
Rake был написан Джимом Вейрихом (Jim Weirich) (http://onestepback.org).
Документацию по Rake вы найдете на http://rake.rubyforge.org. Хорошее
введение в Rake предоставлено Мартином Фаулером (Martin Fowler) на
http://www.martinfowler.com/articles/rake.html.
Чтобы запустить справку по Rake, наберите:
$ rake –help

А вот как запускается Rake:


rake [-f rakefile] {options} targets...

Опции (options) включают:


 поместить Task и FileTask в пространство имен верхнего уровня
--classic-namespace (-C)

 запустить пробный прогон без выполнения действий


--dry-run (-n)

 показать это справочное сообщение


--help (-H)

 включить libdir в путь поиска для требуемых модулей


--libdir=libdir (-I)

 не искать родительские каталоги для Rakefile


--nosearch (-N)

 показать задачи и зависимости, затем выйти


--prereqs (-P)

 не записывать сообщения в стандартный вывод


--quiet (-0)
282 Приложения

 использовать FILE в качестве Rakefile


-rakefile (-f)

 автоматически импортировать любые файлы .rake в rakelibdir (по умол-


чанию в rakelib)
--rakelibdir=rakelibdir (-R)

 затребовать module перед выполнением Rakefile


--require=module (-r)

 подобно --quiet, но также подавляет сообщение "в каталог"


--silent (-s)

 показать задачи (соответствующие необязательному PATTERN) с описания-


ми, затем выйти
--tasks (-T)

 включить трассировку вызвать/выполнить. Активировать полную обрат-


ную трассировку
--trace (-t)

 показать использование
--usage (-h)

 записывать сообщения в стандартный вывод (по умолчанию)


--verbose (-v)

 показать версию программы


--version (-V)
Приложение 2

Ответы на вопросы
для самопроверки

Глава 1
1. Какое прозвище у изобретателя Ruby?
Ответ: Matz.
2. Ruby появился в 1995 году. Какой еще язык программирования был вы-
пущен в свет в том же году?
Ответ: Java.
3. Обязан ли морально или еще как-то каждый, кто пишет книги по про-
граммированию, писать программу "Hello, World!" ("Привет, мир!")?
Ответ: Нет!
4. Что означает аббревиатура irb?
Ответ: Interactive Ruby, построчно-ориентированная "песочница" Ruby.
5. Какой у Ruby "захватчик рынка" (killer app)?
Ответ: Ruby on Rails.
6. Как называется забавная книга по языку Ruby?
Ответ: why's (poignant) guide to Ruby.
7. Кто написал книгу с киркомотыгой на обложке?
Ответ: Дейв Томас (Dave Thomas).
8. Какая у автора любимая среда программирования на Mac?
Ответ: TextMate.
284 Приложения

Глава 2
1. В чем состоит одно из основных отличий между классом и модулем?
Ответ: можно создать экземпляр класса, но не модуля.
2. Какой модуль включает класс Object?
Ответ: Kernel.
3. Какой синтаксис используется для создания блока комментариев?
Ответ: =begin/=end.
4. С какого специального символа начинается переменная экземпляра? Пере-
менная класса? Глобальная переменная?
Ответ: @, @@, $.
5. Какое основное свойство отличает константу?
Ответ: имя константы должно начинаться с заглавной буквы.
6. Когда имя метода заканчивается знаком вопроса (?), что это по догово-
ренности означает?
Ответ: метод возвращает true или false.
7. Блок — это вид безымянного _________________ .
Ответ: метода или функции.
8. Что такое proc?
Ответ: сохраненная процедура, с контекстом.
9. Какова наиболее важная характеристика символа?
Ответ: он занимает единственную ячейку памяти.
10. Что такое RDoc?
Ответ: инструмент по созданию документации по Ruby.

Глава 3
1. Почему case/when более удобны, чем if/elsif/else?
Ответ: запись короче, т. к. == подразумевается.
2. Что такое трехместный оператор?
Ответ: expr ? expr : expr.
3. Что такое модификатор оператора?
Ответ: условный оператор, например if, в конце оператора.
Приложение 2. Ответы на вопросы для самопроверки 285

4. Почему upto или downto более удобны, чем обычный цикл for?
Ответ: они короче и используют блоки.
5. Оператор unless является инвертированной формой другой управляющей
структуры. Какой?
Ответ: if.
6. Какие синонимы у && и || ?
Ответ: and/or, но у них ниже приоритет.
7. Какая управляющая структура является, вероятно, самой тривиальной
управляющей структурой, применяемой в Ruby и других языках?
Ответ: if.
8. В чем преимущество использования begin/end в операторе while?
Ответ: операторы в цикле выполняются один раз до проверки условия.

Глава 4
1. Чем отличаются chop и chomp?
Ответ: chop удаляет последний символ, а chomp — последний раздели-
тель записи.
2. Назовите два способа конкатенации строк.
Ответ: <<, concat или +.
3. Что происходит, когда вы переворачиваете палиндром?
Ответ: ничего.
4. Как вы выполняете итерации над строкой?
Ответ: с помощью метода each или each_line.
5. Назовите не менее двух методов преобразования регистра.
Ответ: capitalize, capitalize!, casecmp, downcase, downcase!,
swapcase, swapcase!, upcase, upcase!.
6. Какие методы вы будете использовать для выравнивания пробелов
в строке?
Ответ: center, ljust, lstrip, lstrip!, rjust, rstrip, rstrip!, strip,
strip!.
7. Опишите чередование в шаблоне регулярного выражения.
Ответ: символ | (используется или одно, или другое).
286 Приложения

8. Чему соответствует /\d{3}/?


Ответ: трем цифрам.
9. Как вы преобразуете строку в массив?
Ответ: методом to_a.
10. Какой, по-вашему, самый простой способ создать строку?
Ответ: выбор за читателем, но я думаю, что проще всего заключить
строку в кавычки.

Глава 5
1. В Ruby числа являются примитивами или объектами?
Ответ: объектами.
2. Каким методом необходимо воспользоваться, чтобы определить, какие
модули включает класс языка Ruby?
Ответ: included_modules.
3. Каков возможный диапазон чисел, представленных классом Fixnum?
Ответ: тот, который компьютер может хранить в своем машинном слове
(32 или 64 бита, минус 1).
4. Как можно избежать округления результатов деления?
Ответ: используйте в качестве операнда, по крайней мере, одно число
с плавающей точкой.
5. Рациональные числа — это другое название для __________________.
Ответ: дробей.
6. Если унарный оператор отсутствует, каков знак числа?
Ответ: плюс.
7. Какие две константы имеются в модуле Math?
Ответ: Math::PI и Math::E.
8. Каким методом вы пользуетесь для преобразования целого числа в сим-
вольное представление?
Ответ: методом chr.

Глава 6
1. Назовите методы класса для Array. Есть только два таких.
Ответ: new и [].
Приложение 2. Ответы на вопросы для самопроверки 287

2. Продемонстрируйте три способа создания массива.


Ответ: Array(), [], %w{} и т. д.
3. Воспользуйтесь двумя методами получения доступа к последнему элемен-
ту в массиве.
Ответ: ary.last и ary[-1].
4. Да или нет: shift и unshift выполняют операции переворачивания стека.
Ответ: да.
5. В чем разница между delete и delete_at?
Ответ: delete удаляет соответствующий объект; delete_at удаляет со-
ответствующий индекс.
6. Вам необходимо добавить объект в каждый элемент массива. Выберите
вариант:
value_at;
length;
map;
[] =.
Ответ: map.
7. Какие методы сравнивают массивы на равенство?
Ответ: == или <=> или eql?.
8. Каким методом можно воспользоваться для удаления из массива nil?
Ответ: compact.

Глава 7
1. В чем разница между хэшем и массивом?
Ответ: хэш — это неупорядоченная совокупность, с ключами и значе-
ниями. Массив — это упорядоченная совокупность, с индексом, начи-
нающимся с 0, и значениями, называемыми элементами.
2. Когда хэш более предпочтителен, чем массив?
Ответ: когда порядок не важен и когда имеется связь ключа со значением.
3. Как бы вы проверили, есть ли в хэше заданный ключ или заданное значе-
ние?
Ответ: has_key?, key?, has_value?, value?.
288 Приложения

4. На каком другом классе основывается класс Hash?


Ответ: Array.
5. Чем выгодно преобразование хэша в хэш?
Ответ: у них одинаковый ID объекта.
6. В чем разница между has_key? и key??
Ответ: ни в чем. Они синонимы, как member? и include?.
7. Покажите, как создать хэш с помощью метода [] из Hash.
Ответ: Hash[ ключ => значение ] или Hash[ ключ, значение ].
8. Что получается в результате сортировки хэша?
Ответ: массив двухэлементных массивов.

Глава 8
1. Для чего пригодна константа ARGV?
Ответ: она представляет имена всех файлов, указанных в командной
строке.
2. Как бы вы с помощью Ruby получили тип файла для файла на диске?
Ответ: ftype.
3. Что маска 0700 делает с правами доступа к файлу?
Ответ: создает для владельца маску rwx.
4. Как бы вы получили доступ к дате и времени создания файла?
Ответ: ctime, mtime, atime.
5. Какой тип объекта возвращает метод entries класса Dir?
Ответ: массив.

Глава 9
1. Да или нет: вы не можете добавлять методы или переменные во встроен-
ные классы.
Ответ: нет.
2. Имени переменной экземпляра предшествует символ _________.
Ответ: символ коммерческое "at" (@).
3. Что является отличительной характеристикой метода класса?
Ответ: ему предшествует имя класса.
Приложение 2. Ответы на вопросы для самопроверки 289

4. Да или нет: в Ruby даже класс является объектом.


Ответ: да.
5. Что такое одноэлементный метод, как его создать?
Ответ: метод, связанный с одноэлементным классом; при помощи метода
экземпляра класса для экземпляра одноэлементного класса.
6. Можно ли создать экземпляр модуля?
Ответ: нет, но модуль можно включить в класс.
7. В чем состоит основное различие между единичным и множественным
наследованием?
Ответ: единичное наследование происходит от одного класса; множест-
венное — от нескольких.
8. Какой класс в Ruby является базовым?
Ответ: Object.
9. Какая видимость установлена по умолчанию для членов класса?
Ответ: public.

Глава 10
1. Для чего служит поле формата b в sprintf (printf)?
Ответ: для двоичных данных.
2. Какой метод вы бы применили, чтобы получить структурную распечатку
документа с помощью Builder?
Ответ: to_xs.
3. Что делает метод superclass?
Ответ: возвращает имя родительского класса.
4. Как можно проверить, соответствует ли данный класс методу?
Ответ: respond_to?.
5. Как затребовать пакет RubyGems в программах Ruby?
Ответ: require 'rubygems' и require_gem.
6. Как в Ruby называется ключевой метод метапрограммирования?
Ответ: define_method.
7. Какой командой RubyGems вы бы воспользовались для установки пакета?
Ответ: [sudo] gem install pkg_nam.
290 Приложения

8. Какой класс Tk используется для создания меток?


Ответ: TkLabel.
9. Для каких ключевых слов в Java являются синонимами ключевые слова
rescue и ensure из Ruby?
Ответ: catch и finally.
10. Как вы форматируете заголовки для обработки в RDoc?
Ответ: при помощи знаков равенства.

Глава 11
1. Из какой программы был извлечен каркас Rails?
Ответ: Basecamp от компании 37 signals.
2. Что такое MVC?
Ответ: Model-View-Controller (Модель-Вид-Контроллер).
3. Какая часть Rails оперирует базами данных?
Ответ: ActiveRecord или модель.
4. Для чего предназначена миграция?
Ответ: позволяет переходить с одной схемы базы данных на другую.
5. Какие приложения используют Rails?
Ответ: Basecamp, Blinksale, 43things, и это только малая часть.
6. Что такое Rake?
Ответ: средство построения, написанное на Ruby.
7. В чем назначение Capistrano?
Ответ: в развертывании приложений.
8. Какой метод наиболее предпочтителен для установки Rails?
Ответ: RubyGems.
9. Где хранится конфигурация баз данных Rails?
Ответ: в config/database.yml.
10. В чем состоит роль "подмостков" в Rails?
Ответ: создавать мгновенное сетевое отображение информации для ва-
шего приложения Rails.
Глоссарий

Ajax
Первоначально аббревиатура для Asynchronous JavaScript and XML. Методи-
ка проектирования Web-страниц, в которой при помощи XMLHttpRequest
данные (часто минимальное количество данных) загружаются на Web-
страницу без обязательного обновления всей страницы с сервера.

ARGF
Подобно потоку ввода/вывода санкционирует доступ к виртуальному объе-
динению всех файлов, указанных в командной строке, или к стандартному
устройству ввода, если файлы не указаны.

ARGV
Массив, который содержит все параметры из командной строки, передавае-
мые в программу.

ASCII
Аббревиатура для American Standard Code for Information Interchange (Амери-
канский стандартный код обмена информацией). ASCII — это набор симво-
лов, включающий 128 букв, цифр, знаков и специальных кодов в диапазоне
от 0 до 127. Каждый символ может быть представлен 8-битовым байтом (ок-
тетом). Ср. с UTF-8. Используется в языке Ruby по умолчанию. Устанавлива-
ется с помощью $KCODE = 'a'.

С-расширение (C extensions)
Ruby написан на языке программирования С. Расширение языка Ruby с помощью
С-кода допустимо, пожалуй, для увеличения быстродействия или реализации
292 Глоссарий

каких-то громоздких вещей. Инструкции ищите в статье Питера Купера


(Peter Cooper) "How to create a Ruby Extension in C in under 5 minutes" ("Как
создать расширение для Ruby на языке С за 5 минут") на сайте
http://www.rubyinside.com/how-to-create-a-ruby-extension-in-c-in-under-5-
minutes-100.html.

еach
В языке Ruby метод с именем each (или аналогичным, например each_line)
выполняет итерации в пределах заданного блока, обрабатывая данные по
частям, — по байтам, символам, строкам, элементам и т. д., в зависимости от
структуры данных. Такие методы называются итераторами.

ERB
Аббревиатура для Embedded Ruby (встраиваемый Ruby). Технология, анало-
гичная JavaServer Pages, для встраивания кода Ruby в тегах — таких как <%=
и %> — в текстовые файлы, включая HTML и XHTML, который выполняется
при обработке этих файлов. Встраиваемый Ruby экстенсивно используется в
Ruby on Rails. Фактически ERB — это встроенная реализация встраиваемого
Ruby, тем не менее, существуют другие, более быстрые реализации, такие
как Erubis (http://rubyforge.org/projects/erubis).

eRuby
См. ERB.

gem
См. RubyGems.

GUI
Аббревиатура для Graphical User Interface (графический интерфейс пользова-
теля). Интерфейс пользователя, сфокусированный на графике, а не на тексте.
Примером является Mac OS X. Tcl/Tk в Ruby — встроенная библиотека GUI.

I/O
Аббревиатура для Input/Output. Ссылается на поток данных, входящий и вы-
ходящий из компьютера, такой как считывание данных в файл и из файла.
Класс IO — основной класс для всего ввода/вывода в Ruby, а класс File —
это подкласс класса IO.
Глоссарий 293

lambda
Метод, который при вызове создает объект Proc, связанный с текущим контек-
стом, и выполняет проверку параметров (проверяет их количество). См. proc.

mixin
См. смешивание.

nil
Пустой, неинициализированный или недопустимый. Его значение всегда
false ("ложь"), но это не то же самое, что zero. Это объект класса NilClass.

pop (вытолкнуть из стека)


Термин, связанный со стеком магазинного типа (LIFO, last-in first-out). Когда про-
исходит выталкивание элемента из стека, то в первую очередь удаляется последний
элемент. В языке Ruby можно выталкивать элементы из массивов. Ср. с push.

private (частный, закрытый)


Метод, помеченный как private, доступен или видим только внутри своего
собственного класса. Ср. с protected, public.

proc
В языке Ruby это процедура, хранящаяся как объект, вместе с контекстом;
объект класса Proc. См. lambda.

protected (защищенный)
Метод, помеченный как protected, доступен или видим только внутри сво-
его собственного класса или порожденного класса. Ср. с private, public.

public (общедоступный, открытый)


Метод, помеченный как public (устанавливается по умолчанию), доступен
или видим и внутри своего собственного класса, и из других классов. Ср.
с private, protected.

push (поместить в стек)


Термин, связанный со стеком магазинного типа (LIFO, last-in first-out). Когда
элемент помещают в стек, то он добавляется в конец массива. В языке Ruby
можно выталкивать элементы из массивов. Ср. с pop.
294 Глоссарий

RAA
См. Ruby Application Archive (архив приложений языка Ruby).

Rails
См. Ruby on Rails.

Rake
Встроенный инструмент, написанный на языке Ruby, с возможностями, как
у make, его предшественника. См. http://rake.rubyforge.org.

RDoc
Инструмент для генерации документации, встроенной в комментарии в ис-
ходных текстах Ruby. См. http://rdoc.sourceforge.net.

RoR
Аббревиатура для Ruby on Rails. См. Ruby on Rails.

Ruby Application Archive


Архив для приложений языка Ruby, основанный на интернет-технологии.
Не то же самое, что RubyForge.

RubyGems
Первая объединяющая система для приложений языка Ruby. Пакет
RubyGems называют gem (гемма, драгоценный камень). Поставляется вместе
с Ruby (но его установку с помощью определенных процедур установки
нужно выбрать отдельно).

Ruby on Rails
Продуктивная, популярная среда для разработки интернет-приложений, на-
писанная на языке Ruby. Matz, разработчик Ruby, назвал его "захватчиком
рынка" (killer app) для языка Ruby.

singleton (одноэлементный)
Одноэлементный класс привязан к отдельному объекту, может быть создан
только один экземпляр класса, и его имя не имеет префикса. С классом
singleton связан метод singleton.
Глоссарий 295

Tcl/Tk
Язык написания сценариев Tcl с инструментарием Tk для разработки пользо-
вательского интерфейса. Встроенная в Ruby библиотека или система GUI
(графического интерфейса пользователя).

Unicode
Международная система кодирования символов, учитывающая приблизи-
тельно 65 000 символов. См. http://www.unicode.org.

UTF-8
Набор символов, базирующийся на байтах (от одного до четырех); может
описать большую часть символов различного рода систем записи. Устанав-
ливается при помощи $KCODE = ' n'. Ср. с ASCII.

XML
Аббревиатура для Extensible Markup Language (расширяемый язык разметки
гипертекста). Язык, специфицированный в W3C (World Wide Web Consortium),
позволяет создавать словари, посредством применения тегов и другой раз-
метки. В Ruby для обработки XML используются REXML, Builder и libxml.

Аксессор (accessor)
Метод доступа к данным в классе, обычно недоступном иным способом.
Также носит название "геттер" и "сеттер".

База данных (database)


Систематизированная совокупность данных, хранящихся в компьютере. Ruby
on Rails — среда для разработки интернет-приложений, дающая возможность
работать с базами данных.

Библиотека (library)
См. стандартная библиотека.

Блок (block)
Безымянная функция, всегда связанная с вызовом метода и заключенная
в пару фигурных скобок ({}) или do/end.
296 Глоссарий

Блок комментария (block comment)


См. комментарий.

Вложенный документ (embedded document)


См. комментарий.

Возврат каретки (carriage return, CR)


См. новая строка.

Восьмеричное число (octal)


Число в восьмеричной системе счисления, представленное цифрами 0—7.
Часто имеет префикс 0 (ноль). Например, число 26 из десятичной системы
счисления выглядит в восьмеричной как 32.

Встраиваемый Ruby (embedded Ruby)


См. ERB.

Выражение (expression)
Содержит ключевые слова, математические операторы, переменные и тому
подобное, и возвращает значение.

Глобальная переменная (global variable)


Переменная, область видимости которой включает всю программу. Ср. с пе-
ременной класса, переменной экземпляра, локальной переменной.

Графический интерфейс пользователя (graphical user interface)


См. GUI.

Деление по модулю (modulo)


Операция деления, которая возвращает остаток от деления. В качестве опера-
тора деления по модулю используется знак процента (%).

Диапазон (range)
В языке Ruby это способ представления включающих (..) и исключающих
(...) диапазонов объектов, обычно чисел. Например, 1..10 — это диапазон
Глоссарий 297

чисел от 1 до 10, включающий; применение .. вместо ... исключает по-


следнее значение из диапазона.

Документ "здесь и сейчас" (here document)


Методика, которая позволяет компоновать строки из нескольких строк текста
при помощи <<name/name, где name — произвольное имя. Варианты синтак-
сиса: <<"string"/string — для строк в двойных кавычках, <<'string'/
string — для строк в одинарных кавычках, <<`string`/string — для строк
в обратных кавычках и <<-string /string — для строк с отступом.

Дочерний класс (child class)


Производится из родительского класса или суперкласса. Ср. с суперклассом.

Единичное наследование (single inheritance)


Класс может наследовать только от одного класса, в противоположность
множественному наследованию, которое допускает наследование классом от
множества классов. См. множественное наследование.

Замыкание (closure)
Безымянная функция или метод. Замыкание подобно методу в методе, кото-
рый обращается или совместно использует переменные в скобках или внеш-
ний метод. В языке Ruby замыкание, как и блок, заключено в фигурные скоб-
ки ({}) или скобки do/end, и его работа зависит от связанного с ним метода.

Зарезервированное слово (reserved word)


Еще одно название для ключевого слова. Зарезервированные слова, такие как
begin, end, if, else и тому подобные, имеют особое значение для интерпре-
татора с языка Ruby.

Значение по умолчанию (default)


Значение, которое присваивается автоматически при взаимодействии с кодом
или программой.

Индекс (index)
Целое число, начиная с 0, которое нумерует или идентифицирует элементы
массива. См. массив.
298 Глоссарий

Исключение (exception)
Позволяет в процессе программирования отловить и обработать ошибки пе-
риода исполнения программы, а также другие ошибки. Обработка ведется
с помощью rescue, ensure и raise. Ср. с ошибкой.

Класс (class)
Коллекция кодов, включающая методы и переменные, называемые членами
класса. Код в классе устанавливает правила для объектов данного класса.
См. экземпляр класса, модуль, объект.

Ключ (key)
Ключ связан со значением в хэше. Ключи можно использовать для доступа
к значениям в хэше. См. хэш.

Ключевое слово (keyword)


См. зарезервированное слово.

Комментарий (comment)
Текст программы, пропускаемый интерпретатором с языка Ruby. Если ему
предшествует знак # и он не заключен в двойные кавычки, то он не учитывается
интерпретатором. Блок комментария, заключенный в скобки =begin/=code,
может содержать несколько строк текста. Он также называется вложенным
документом.

Конкатенация (concatenation)
Соединение или сцепление двух символьных строк, выполняемое в языке
Ruby с помощью методов +, << и concat.

Константа (constant)
В языке Ruby имя константы начинается с заглавной буквы или пишется за-
главными буквами. Константа не фиксируется, как в других языках. Впро-
чем, если поменять значение константы, интерпретатор Ruby предупредит,
что константа уже инициализирована.

Локальная переменная (local variable)


Переменная с локальной областью видимости, такой как внутри метода.
Нельзя получить доступ к локальной переменной из точки программы, нахо-
Глоссарий 299

дящейся вне ее области видимости. В языке Ruby имена локальных перемен-


ных начинаются со строчной буквы или символа подчеркивания (_). Примеры
имен локальных переменных: num и _outer. См. переменная класса, гло-
бальная переменная, переменная экземпляра.

Массив (array)
Структура данных, содержащая упорядоченный список элементов — любых
объектов языка Ruby, — начинающийся с индекса 0. Ср. с хэш.

Метапрограммирование (metaprogramming)
Программирование, которое создает и/или манипулирует другими програм-
мами. В языке Ruby одним из инструментов, находящихся на службе мета-
программирования, является метод define_method. Рефлексия — другое
свойство Ruby, играющее роль в метапрограммировании. См. рефлексия.

Метод (method)
Именованная совокупность операторов, с параметрами или без параметров,
и возвращаемое значение. Член класса. См. класс.

Метод-геттер (getter)
См. аксессор.

Метод-сеттер (setter)
См. аксессор.

Множественное наследование (multiple inheritance)


В некоторых языках программирования класс может наследовать от несколь-
ких классов. Например, в языке C++ поддерживается множественное насле-
дование, недостатки которого, по мнению большинства, перевешивают его
достоинства. См. единичное наследование.

Модуль (module)
Модуль подобен классу, но невозможно создать экземпляр модуля. Класс
может включать модуль, так что, когда создается экземпляр класса, он полу-
чает методы и все прочее из включенного модуля. Методы из включенного
модуля становятся экземплярами методов в классе, который включает мо-
дуль. Этот процесс называется смешиванием, а модуль именуется mixin.
См. класс, смешивание.
300 Глоссарий

Наследование (inheritance)
Способность класса наследовать свойства другого класса с помощью опера-
тора <. См. множественное наследование, единичное наследование.

Новая строка (newline)


Символ, заканчивающий строку, такой как перевод строки (linefeed) в Mac
OS X и UNIX/Linux или комбинация символов, таких как возврат каретки
и перевод строки (CR и linefeed) в Windows.

Объект (object)
Экземпляр класса, вещь, сущность или концепт, расположенный в непрерыв-
ной области памяти компьютера. См. экземпляр класса, класс.

Объектно-ориентированное программирование (object-oriented programming)


Относится к практике программирования, основанной на организации дан-
ных с помощью методов, которыми можно обрабатывать эти данные. Мето-
ды и данные (члены класса) организованы в классы, которые можно обраба-
тывать как объекты. См. класс.

ООП (OOP)
См. объектно-ориентированное программирование.

Оператор (statement)
Инструкция программе для приведения в исполнение.

Операторы (operators)
Выполняют такие математические операции, как сложение и вычитание.
Операторы в языке Ruby включают, как и в других языках, + для сложения, -
для вычитания, * для умножения, / для деления, % для деления по модулю и
т. д. Многие операторы в языке Ruby являются методами.

Ошибка (error)
Трудность или дефект в коде, который обычно приводит к останову про-
граммы. В программах на языке Ruby распространенные ошибки отождеств-
ляются с такими классами, как ArgumentError, EOFError и ZeroDivisionError.
Ср. с исключением.
Глоссарий 301

Пакет (package)
См. RubyGems.

Параметр (argument)
Переменная, передаваемая методу. В вызове метода hello ( name ) пере-
менная name является параметром. См. метод.

Перевод строки (linefeed)


См. новая строка.

Перегрузка (overloading)
Перегрузка метода или функции — обычная практика в объектно-
ориентированном программировании, она позволяет методам с одинаковыми
именами оперировать различного вида данными (методам или функциям
с одинаковыми именами, но разными отличительными признаками). В языке
Ruby, по правде говоря, нельзя перегрузить методы без ветвления логики
внутри метода. См. подмена.

Переменная (variable)
Имя, которому может быть присвоено количество или значение. См. перемен-
ная класса, глобальная переменная, переменная экземпляра, локальная пере-
менная.

Переменная класса (class variable)


Переменная, которая может использоваться совместно объектами данного
класса. В Ruby ее имени предшествуют два знака "эт", как в @@count.
См. глобальная переменная, переменная экземпляра, локальная переменная.

Переменная экземпляра (instance variable)


Переменная, связанная с экземпляром класса. В языке Ruby переменным эк-
земпляра предшествует одиночный символ "коммерческое at" — например,
@name. См. переменная класса, локальная переменная, глобальная переменная.

Перечислимый класс (enumerable)


В языке Ruby класс (коллекция), в котором есть методы обхода и поиска,
а также возможность сортировки.
302 Глоссарий

Подмена (overriding)
Переопределение метода. Последнее определение — это то, которое опозна-
но интерпретатором Ruby. Ср. с перегрузкой.

Подстановка (substitution)
См. подстановка выражения.

Подстановка выражения (expression substitution)


В языке Ruby это синтаксис, который позволяет вставлять выражения в стро-
ки и контексты. Подстановка заключается в скобки #{ и }, и результат вы-
числения выражения замещает подстановку при выполнении кода в ходе
интерпретирования.

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

Пригодность для компоновки (composability)


Степень, до которой можно выразить логику, комбинируя и рекомбинируя
части языка (см. книгу Джеймса Кларка (James Clark) "The Design of RELAX
NG" на http://www.thaiopensource.com/relaxng/ design.html#section:5).

Пространство имен (namespace)


В языке Ruby модуль действует как пространство имен. Пространство имен —
это множество имен — таких как имена методов, — у которых есть область
видимости или контекст. В языке Ruby модуль связывает одно имя с множест-
вом имен методов и констант. Имя модуля можно использовать в классах
в других модулях. Обычно область видимости или контекст такого пространст-
ва имен — это класс или модуль, в который включено это пространство имен
(имя модуля). Класс в языке Ruby тоже может считаться пространством имен.

Псевдоним (alias)
Посредством ключевого слова alias в языке Ruby можно дать другое имя
методу, оператору или глобальной константе, указав старое и новое имя.
Глоссарий 303

Псевдопеременная (pseudovariable)
Объект, который выглядит как переменная и ведет себя как константа, но
которому нельзя присвоить значение.

Путь (path)
Местонахождение файла в файловой системе. Используется для упрощения
локализации файлов для открытия, выполнения и тому подобных операций.
Содержится в переменной среды PATH.

Расширение, файл (extension, file)


Часть имени файла (если есть), которая следует за точкой. Стандартное рас-
ширение для файла Ruby — rb.

Расширение, С (extension, C)
См. С-расширение.

Рациональное число (rational number)


Дробь. В языке Ruby рациональные числа обрабатываются посредством
класса Rational.

Регулярное выражение (regular expression)


Краткая последовательность или шаблон специальных символов, применяе-
мые при поиске строки. См. совпадение.

Режим, файл (mode, file)


См. режимный код файла.

Режимный код файла (file mode)


В зависимости от того, что установлено, определяет возможность читать,
записывать и исполнять файл. Один из способов установить режимный код
файла — с помощью File.new в момент создания файла.

Ресивер (receiver)
Объект, который получает или является контекстом для действия, выполняе-
мого методом. В вызове метода str.length, str — ресивер метода length.
304 Глоссарий

Рефлексия (reflection)
Способность языка, такого как Ruby, проверять себя и совершать над собой
манипуляции.

Родительский класс (parent class)


См. суперкласс.

Символ конца строки (line-end character)


См. новая строка.

Случайное число (random number)


С помощью методов Kernel#rand или Kernel#srand в Ruby можно генериро-
вать произвольное, псевдослучайное число.

Смешивание (mixin)
Когда модуль включается в класс, он как бы смешивается с классом, отсюда
и его название mixin. Использование mixin помогает преодолеть проблемы,
возникающие из-за множественного наследования.

Совпадение (match)
При обнаружении заданного регулярного выражения метод сообщает, что
произошло совпадение. См. регулярное выражение.

Стандартная библиотека (standard library)


Библиотека или коллекция программ языка Ruby, содержащая пакеты для
выполнения специализированных заданий. Примерами таких пакетов явля-
ются REXML для обработки XML и Iconv для преобразования множеств сим-
волов. Электронная документация доступна на http://ruby-doc.org/stdlib.

Строка (string)
Последовательность объектов, обычно символов.

Cтроки с общими разделителями (general delimited strings)


Методика создания строк с использованием %! и !, где ! — произвольный не
алфавитно-цифровой символ. Варианты синтаксиса: %Q!string! — для
строк в двойных кавычках, %q!string! — для строк в одинарных кавыч-
ках и %x!string! — для строк в обратных кавычках.
Глоссарий 305

Структура данных (data structure)


Данные хранятся в компьютере таким способом, который (обычно) обеспе-
чивает их эффективный поиск. Примерами таких структур данных являются
массивы и хэш-таблицы.

Суперкласс (superclass)
Родительский класс. Дочерний класс получается из родительского класса или
суперкласса. Ср. с дочерним классом.

Точность (precision)
Определяется точностью, с которой выражаются численные величины. В языке
Ruby модуль Precision позволяет преобразовывать числа (числа с плаваю-
щей точкой в целые, целые числа в числа с плавающей точкой).

Трехместный оператор (ternary operator)


Оператор с тремя параметрами, разделенными ? и :, краткая форма
if/then/else. Например, label = length == 1? " argument" : " arguments".

Условное выражение (conditional expression)


См. трехместный оператор.

Условный оператор (conditional statement)


Проверяет, истинное или ложное значение принимает заданный оператор,
и, в зависимости от результата, выполняет (или нет) код. Условные операто-
ры формируются с помощью таких ключевых слов, как if, while и unless.

Хэш (hash)
Неупорядоченная совокупность данных, в которой отображены ключи и зна-
чения. Ср. с массивом.

Хэш-код (hash code)


Целое число, вычисленное из объекта. Идентичные объекты имеют одинако-
вый хэш-код. Генерируется методом hash.

Цикл (loop)
Повторяющееся выполнение одного или нескольких операторов. В Ruby ис-
пользуются циклы for и даже есть метод loop для решения такой задачи.
306 Глоссарий

Цикл может быть остановлен (прерван). Далее управление передается или


следующему оператору программы, или в особое место, или программа за-
вершает работу.

Числа с плавающей точкой (float)


В Ruby это объекты, представляющие действительные числа, такие как 1.0.

Член (member)
Переменные и методы считаются членами класса или объекта. См. класс, ме-
тод, объект, переменная.

Шаблон (pattern)
Последовательность ординарных и специальных символов, дающая возмож-
ность механизму регулярных выражений обнаружить строку. См. регулярное
выражение.

Шестнадцатеричное число (hexadecimal)


Число в шестнадцатеричной системе счисления, представленное цифрами
0—9 и буквами A—F или a—f. Часто имеет префикс 0x. Например, число
26 из десятичной системы счисления выглядит в шестнадцатеричной как
0x1A.

Экземпляр класса (instance)


Объект, который создается при реализации класса, часто с помощью метода
класса new. Например, str = String.new создает экземпляр класса String.
Предметный указатель

3 configure 27
CR+LF 22
37signals 231
CSS 223
C-расширение 291
A
Ajax (Asynchronous JavaScript and D
XML) 236, 291
DATA 266
Alias 38, 55, 258, 302
def 17, 39, 50, 259
and 39, 258
defined? 39, 259
ARGF 151, 156, 264—266, 291 do 39, 259
ArgumentError 186
ARGV 15, 151, 155, 266, 291 E
ASCII 94, 291
Autoexec.bat 34 else 39, 68, 259
elsif 39, 68, 259
B Embedded Ruby (ERB) 226, 292
теги-шаблоны 226
Basecamp 231, 238 end 39, 50, 73, 75, 166, 259
begin 39, 73, 75, 214, 259 END 38, 80, 258
BEGIN 38, 80, 258 ensure 39, 214, 215, 259
break 39, 73, 259 ENV 266
Builder, require_gem 191 Erubis 226
Escape-символы 261
C Extensible Markup Language, см. XML
Capistrano 237
Carriage return 262 F
case 39, 259 __FILE__ 40, 260
class 39, 259 false 39, 49, 259, 266
conf.last_value 201 for 39, 76, 259
308 Предметный указатель

G nil 22, 39, 126, 128, 259, 266, 293


not 40, 68, 259
GMT, Гринвичское время 195
GUI (Graphical User Interface) 292
O
I One-Click Installer 29
if 39, 259 or 40, 259
in 39, 259 ORM (Object-relational mapping) 252
Instant Rails 25, 244
IO (Input/Output) 292 P
irb (Interactive Ruby) 22, 46, 109 PLATFORM 266
обработка исключений 214 Precision Information Services 24
рефлексия 201 private 179, 293
тестирование приложений Rails 236
proc:
процедура 293
K
процедурный объект 18, 59
Kernel#test 275 protected 179, 293
public 179, 293
L
__LINE__ 40, 260 R
LF (linefeed, перевод строки) 22 raise 214
Libxml-Ruby 188 Rake 237, 280, 294
LIFO 133 rake test_units 237
Linux, настройка пути 31 Rakefile 237
Locomotive 26
rbfile 33
RDoc 24, 62, 294
M
обработка файлов 222
Macintosh: опции RDoc 278
TextMate 20 форматирование вывода 217
настройка пути 31 форматирование заголовков 218
установка Ruby readline 27
под Mac OS X Tiger 26 redo 40, 260
make 26 RELEASE_DATE 266
mixin 304 rescue 40, 214, 215, 260
module 39, 259 retry 40, 260
Mongrel 24, 247 return 40, 260
MVC (Model-View-Controller) 234 REXML (Ruby Electric XML) 18, 191
создание документа XML 188
N электронная документация и
newline 262 ресурсы 191
next 39, 259 ri (Ruby information) 62, 216, 224
Предметный указатель 309

Ruby: RUBY PLATFORM 266


Web-сайты, книги, списки RUBY RELEASE DATE 266
рассылок 23 RUBY_VERSION 266
выполнение системной RubyForge 24, 294
команды 13 RubyGems 25, 294
объектно-ориентированное dependency 212
программирование 37 install 210
определение версии 10 uninstall 213
Ruby Application Archive 25, 294 require_gem 191
Ruby Central 23 проверка установки 208
Ruby on Rails 3, 10, 208, 294 справочная информация
Capistrano 237 по командам 208
Mongrel 247 установка Rails 241
MVC 234 RubyMate 21
Rake 237 RuntimeError 216
дополнительная информация
по установке 244
S
достоинства 232
и Ajax 236 scRubyt 156
и XML 233 self 40, 260
изучение 244 singleton 294
история 231 sprintf 186
команда rails 246 индикатор точности 187
миграции 236 спецификаторы
обучающие руководства 245 формата (%) 183
подтверждение типы полей 183, 187, 273
правильности 235 флажки 184, 273
полный пакет среды STDERR 161, 266
разработки 233 STDIN 161, 266
приведение экранов 244 STDOUT 161, 266
применение RubyGems 241 sudo 28, 212
реальное положение super 40, 260
вещей 238
ресурсы для изучения 244 T
сервер Webrick 247
скрипты 235 Tcl/Tk 203, 295
соглашение TextMate 21
по конфигурации 234 then 40, 260
среда и тестирование 236 Tiger (Mac OS X) 26
тестирование на консоли 236 Tk 20, 203
услуги по размещению 241 TOPLEVEL_BINDING 266
установка 241 true 40, 49, 260, 266
философия DRY 233 try, блок 214
310 Предметный указатель

U сопоставление типа файлов 32


установка Ruby
undef 40, 50, 260
с One-Click Installer 29
Unicode 295
unless 40, 74, 260 X
until 40, 74, 260
XCode 26
URI, открытие 156
XML 18, 295
UTC, универсальное время
Builder 191
по Гринвичу 195
REXML 188
UTF-8 45, 94, 190, 295
и Rails 234
декларация 190
W
обработка 188
Web scraping toolkit 156 создание документов 189
when 40, 260 XmlSimple 188
while 40, 260
Windows 34 Y
assoc 33 yield 40, 57, 260
ftype 33
ruby 11 Z
настройка пути 31 ZeroDivisionError 215

А В
Аналогия с ведром 37 Ввод с клавиатуры 17
Архитектура MVC 234 Возведение в степень 47
Возврат каретки 22
Б Возвращаемое значение 51
База данных 295 Вопросительный знак (?) 49
Библиотека: Вставка команды из командной
mathn 122 строки 14
стандартная 304 Вывод форматированный,
Биты полномочий 154 см. sprintf
Блок 56, 295 Выражение условное 305
proc 59
кода 18 Г
оператор yield 57
Григорианский и юлианский
преобразование в proc 18
календари 198
Блоки и массивы 137
Группирование (регулярные
Быстрые комбинации (регулярные
выражения) 100 выражения) 100
Предметный указатель 311

Д поток каталога 153


создание и удаление 152
Деление 111
установка прав доступа 152
по модулю 296
Класс 19, 35, 298
Диапазон 45, 71, 115, 296
Array 125
Диапазоны, точки-индикаторы 86
Bignum 107
Динамическая типизация 42
Complex 108
Директива title 218
Date 196
Добавление в конец строки 13
календарные формы 198
Документ "здесь и сейчас" 83, 297
метод downto 197
Документация по Ruby 62
метод new 196
Документирование с помощью RDoc,
метод upto 197
см. RDoc DateTime 199
Дублирование выводимого текста 14 Dir 153
File 153
З Fixnum 47, 107
Заголовки, отформатированные Float 107
в RDoc 218 Integer 42, 107
Замена подстроки 92 IO 160, 292
Замыкания (блоки) 59, 297 MatchData 102
Зарезервированное слово 38, 297 Matrix 108
Значение по умолчанию 297 Module 169
метод define_method 207
И метод included_modules 200
Numeric 47, 107
Иерархия математических классов 108
Object 37, 165
Имитации 237
метод class 199
Индекс (массив) 297
метод instance_of? 200
Индикатор точности 187, 188
метод object_id 200
Интерпретатор Ruby 257
OpenURI 157, 206
местонахождение каталога 12
Prime 122
Исключение 298
Rational 108, 120
обработка 62
Regexp 102
Итеративное вычисление через
singleton 294
блоки 117
Time 193
метод local 194
К
метод now 193
Календарные формы 198 базовый 165
Канонические стандарты 194 дочерний 175, 297
Каскадные таблицы стилей 223 и модули 177
Каталог: интерфейсы 165
метод foreach 153 математический 107
методы класса Dir 151 методы public, private и protected 179
312 Предметный указатель

методы класса 48, 173 очистка 127


методы-аксессоры 169 преобразование строки в массив 93
наследование 165, 175 создание 126
одноэлементный 173, 294 сортировка 137
определение 166 список методов 139
переменная класса 43, 172, 301 сравнение с другим массивом 134
переменные экземпляра 167 ссылка на элемент 125
перечислимый 301 стеки 133
суперкласс 165, 305 уникальные элементы 133
члены класса 306 элемент 125, 126
Ключ 149, 298 изменение 135
Ключевое слово 38, 258 удаление 136
Коллизия имен 165 Метапрограммирование 169, 207, 299
Команда: метод define_method 207
assoc (Windows) 32 Метод 17, 56, 299
ftype (Windows) 32 % 15
gem 214 * 14, 88
puts 11 [] 45, 85, 127, 142
rails 246 []= 89, 145
ruby 11 + 13, 85
system 13, 160 << 13, 83, 132
Комментарий 12, 40, 298 =~ 102
блок комментария 41, 296 == 134
Конкатенация 298 === (для диапазона) 115
массивов 131 abs 118
Константа 44, 298 acos 120
глобальная 151, 266 acos! 120
рефлексия 201 acosh 120
acosh! 120
add_attribute 190
М
add_element 190
Маски chmod 159 ajd 199
Массив 18, 49, 125, 139, 299 ancestors 108, 201
будущие версии Ruby 139 asctime 194
директивы упаковки 272 asin и asin! 120
доступ к элементам 129 at 130
и блоки 137 atan 120
индекс 125 atan! 120
конкатенация с другим atime 159
массивом 131 attr 169, 207
методы класса Array 126 attr_accessor 169, 207
многомерный 138 attr_reader 169, 207
операции над множествами 132 (продолжение рубрики см. на стр. 313)
Предметный указатель 313

Метод (продолжение): dst? 195


attr_writer 169, 207 each 18, 57, 94, 137, 152, 207, 292
block_given? 58 each_byte 46, 94
call 18, 60 each_key 144
capitalize 86, 93 each_line 94
capitalize! 93 each_pair 144
casecmp 88 each_value 145
catch 214, 216 empty? 126, 141
ceil 118 entries 152
center 96 eql? 88, 134
chdir 151 erf и erfc 120
chmod 159 eval 16, 215
chomp 90 executable? 158
chomp! 90 exist? 158
chop 90 exists? 158
chop! 90 exit 215
chown 160 exp 120
chr 45, 118 exp! 120
civil 196 finite? 117
class (класс Object) 199 first 130
clear 127, 147 flatten 138
close 162 Float 109
comment! 193 floor 118
Comment.new 190 flush 162
concat 132 foreach 153
constants 119, 202 freeze 85
cos 120 frexp 120
cos! 120 ftype 158
cosh 120 getc 162
cosh! 120 gets 17, 75, 162
ctime 159, 194 getwd 151
day 194 global_variables 202
define_method 207 gmt? 195
delete 91, 136, 146, 152 gregorian 198
delete_at 137 gsub 92, 148
delete_if 147 has_key? 143
directory? 158 has_value? 143
div 110 hour 194
divmod 110 hypot 120
downcase 95 id2name 61
downcase! 95 include 177
downto 79, 118, 197 include? 131, 143
314 Предметный указатель

included_modules 109, 200 nan? 117


index 87, 130, 139 new 81, 126, 141, 153, 161, 196
infinite? 117 next 97, 118, 122, 196
initialize 167 next! 97
insert 89, 135 nitems 139
instance_methods 202 nonzero? 116
instance_of? 200 now 193
instance_variables 201 object_id 92, 200
instruct! 193 open 154
integer 109 path 153
integer? 116 pop 133, 139
intern 61, 99 print 16, 63
is_a? 200 printf 16
isdst 195 private 179, 181, 293
jd 198 private_instance_methods 202
join 136 private_methods 202
julian 198 protected 179, 181, 293
key? 143 protected_instance_methods 202
keys 143 protected_methods 202
kind_of? 42, 200 public 179, 181, 293
lambda 18, 59, 293 public_instance_ methods 202
last 130 public_methods 202
ldexp 120 push 133
length 82, 126, 141 putc 162
lineno 154 puts 11, 184
ljust 96 pwd 151
load 176 quo 110
local 194 raise 215
local_variables 201 rand 177
loop 75, 305 read 153
lstrip 97 readable? 158
lstrip! 97 readline 163
member? 143 reject 147
merge 145 remainder 110
merge! 146 rename 157
min 194 repeat 51
mjd 198 replace 148
mkdir 152 require 18, 176, 178
modulo 110 require_gem 191
month 194 respond_to? 175, 203
mtime 159 reverse 92, 138
name 199 (окончание рубрики см. на стр. 315)
Предметный указатель 315

Метод (окончание): times 14, 77, 117


reverse! 92 to_a 148
rewind 153 to_f 42, 99
rindex 130, 139 to_hash 148
rjust 96 to_i 162
rmdir 152 to_s 135, 139, 148, 196
round 118 to_sym 61, 99
rstrip и rstrip! 97 to_xs 192
scan 157 today 196
sec 194 transpose 139
select 144 uniq 133
shift 136 uniq! 133
sin 120 unshift 136
sin! 120 upcase 95
singleton 173 upcase! 95
singleton_methods 202 update 146
sinh и sinh! 120 upto 78, 98, 118, 197
size 82, 126, 141 utc? 195
size? 158 validate_presence_of 235
sleep 79 value? 143
slice 85, 131 values 143
sort 137, 146 values_at 144
split 93, 123 wday 194
sprintf 16 while 71
sqrt 120, 173 writable? 158
sqrt! 120 write 184
store 145 XMLDecl.new 189
strftime 79 yday 194
strip 97 year 194
strip! 97 zero? 49, 116, 158
succ 97, 118, 122, 196 zone (часовой пояс) 194
succ! 97 аксессор 295
superclass 200 вопросительный знак (?) в конце 126
swapcase 95 восклицательный знак (!) в конце 125
swapcase! 95 вспомогательный 180
tan 120 геттер 168, 299
tan! 120 класса Object 202
tanh 120 одноэлементный 173
tanh! 120 псевдоним 55
tell 153 рефлексия 202
text 190 сеттер 299
throw 214, 216 соглашения об именах 52
Time.now 193 статический 173
316 Предметный указатель

Миграция 235, 236 модификаторы операторов 66, 73, 74


Модуль 38, 299 проверки на равенство 87
Kernel 35, 38, 177, 183 проверки на равенство (==) 65
Math 48, 107 с основанием три 69
Precision 108 сокращенного присваивания 112
трехместный 69, 305
Н унарный 110
Наследование 35, 165, 175, 300 условный 48, 58, 65, 305
единичное 297 else и elsif 68
множественное 165, 175, 299 Операция:
одиночное 165, 175 математическая 110
Настройка пути 31 побитовая 113
Новая строка 300 Ошибки 300

О П

Область видимости 177, 179 Палиндром 93


Обработка исключений 214 Пара "ключ-значение" 141
операторы rescue и ensure 215 Параллельное присваивание 44
сравнение с C++ и Java 214 Параметр 301
Общие строки с разделителями 228 -e 16
Объединение (|) 132 переменное количество (для
Объект 35, 300 метода) 54
Объектно-ориентированное по умолчанию 54
программирование (ООП) 37, 300 Перегрузка 301
Объектно-реляционное отображение Переменная 14, 41, 301
(ORM) 234, 252 глобальная 43, 296
Округление 111 класса 43, 172, 301
Оператор 11, 38, 48, 56, 300 локальная 14, 43, 298
!~ 102 параллельное присваивание 44
&& 66 параметров командной строки 15
< 175 предопределенная 262
<=> (космический челнок) 88, 112, рефлексия 201
134, 195 среды PATHEXT (Windows) 33
case 70 экземпляра 43, 167, 168, 175, 301
if 49, 65 Пересечение (&) 132
unless 74 Подмена 302
until 74 Подстановка выражений 15, 154,
yield 17 196, 207, 302
диапазона 71 Подтверждение правильности
логический 67 (Rails) 235
математический 114 Полный пакет среды разработки 233
Предметный указатель 317

Поток 302 Символ:


Преобразование: : (двоеточие) 61
в шестнадцатеричное число, - (разность) операция
sprintf 187 с массивами 132
десятичного числа в двоичное 183 ! (восклицательный знак) 53, 125
Преобразование регистра # 12, 41
клавиатуры 95 #! (shebang) 12
Приведение экранов 244 $ (знак доллара) 43
Привязки (регулярные %, как спецификатор формата 183
выражения) 100 %o, тип поля 187
Пригодность для компоновки 9, 302 & (пересечение массивов) 132
Примеры кодов 3 & (фоновый режим) 20
Примитив 47 && (оператор И) 66
Пробельные символы (управление) 95 // (косые черты) 46
Пространство имен 177, 302 ; (точка с запятой) 11
Псевдоним 302 ? : (трехместный оператор) 69
Псевдопеременная 68 ? (вопросительный знак) 49, 126
Путь 31, 303 @ (переменная экземпляра) 43
загрузки 176 @@ (переменная класса) 43
[] (квадратные скобки) 126
Р _ (подчеркивание) 43
` (обратная кавычка или гравис) 14
Разность (массивов) 132
{} (фигурные скобки) 57, 80
Расширение файла 303
в Builder 193
rb 11, 12
| (объединение, операция над
Регулярное
массивами) 133
выражение 46, 90, 267, 303
<=> (оператор "космический
быстрые комбинации 100
челнок") 88, 112, 134, 195
оператор повторения 101
= (знак равенства) 53
Режим ввода/вывода 161
=== (оператор диапазона) 71
Режимный код файла 153, 303
=> (в комментариях) 14
изменение 159
новой строки 22
Ресивер 303
Скрипт generate scaffold 251
Рефлексия 108, 304
Смешивание 177, 304
для методов 202
Собственность класса 165
для переменных и констант 201
Совпадение 304
Сообщение "Permission denied" 32
С
Сопоставление типа файлов
Сервер: (Windows) 32
lighttpd 244 Спецификаторы формата 183
WEBrick 247 Списки рассылок по Ruby 24
Сетевой дневник, создание 245 Стандартное устройство ввода 17
318 Предметный указатель

Стандартный ввод 161 под Mac OS X Tiger 26


Стандартный поток 160 под Windows с One-Click Installer 29
Стек 133 сопоставление типа файлов
Строка 45, 304 в Windows 32
вставка строки в строку 89
выполнение итераций 94 Ф
директивы распаковки 269
Файл:
добавление в конец 13
ARGF 151, 156
документ "здесь и сейчас" 83
argf.rb 156
замена:
ARGV 151, 155
подстроки 92
argv.rb 155
строки или ее части 89
fileno 162
конкатенация 84
matz.rb 11
обработка 88
scrape.rb 157
преобразование 98
изменение режимного кода 159
в массив 93
маски chmod 159
регистра 93
открытие URI 157
приращение 97
открытие существующего 154
регулярные выражения 99
переименование 157
с общими разделителями 304
создание 153
создание 81
удаление 157
сравнение 87
файловые запросы 158
стороковые методы:
числовые дескрипторы 162
доступ 85
Файловые запросы 158
информационные ресурсы 81
Файловые тесты 275
управление пробельными
Форматирование времени,
символами 95
директивы 277
Структура данных 305
Форматирующие строки 186
Суперкласс 165, 175, 305
Форматирующий флажок 15
Функция:
Т
безымянная 56
Тестирование элементов 233 математическая 119
Типы полей 183, 185, 273
Точность 305 Х
Хэш 49, 305
У
выполнение итераций 144
Уникальные элементы 133 доступ 143
Условное выражение 69, 305 замещение 148
Установка Ruby 34 изменение 145
cообщение "Permission denied" 32 методы получения информации 149
двоичные файлы под Windows 30 объединение с другим хэшем 145
под Linux 32 (окончание рубрики см. на стр. 319)
Предметный указатель 319

Хэш (окончание): проверка на равенство 112


пара "ключ-значение" 141 простое 122
преобразование в другие классы 148 рациональное 120
создание 141 с плавающей точкой 306
сортировка 146 случайное 304
удаление и очистка 146 шестнадцатеричное 109, 306
хэш-код 305 Эйлера 119
элементарные математические
Ц операции 110
Числовой дескриптор файла 161
Цикл 305
Член класса 165, 306
for 76
while 71
Ш
Ч Шаблон 306
Чередование (регулярные
Э
выражения) 100
Число 47 Экземпляр класса 306
восьмеричное 109, 296 Элемент массива 49
классы и модули 107
нулевое и ненулевое значения 116 Ю
объекты 107
Юлианский и григорианский
преобразование 109
календари 198

Вам также может понравиться