Академический Документы
Профессиональный Документы
Культура Документы
Санкт-Петербург
«БХВ-Петербург»
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., собственника всех прав на публикацию
и продажу издания.
Об авторе ................................................................................................................ 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
1950—2006
Об авторе
О примерах
Я считаю, что обучаться лучше всего, наблюдая за тем, что делают другие,
а затем имитировать то, что видел. Так обучаются дети. Поэтому вы найдете
примеры текстов программ — для наблюдения и имитации — почти на каж-
дой странице этой книги.
Многие примеры можно скачать с сайта http://www.oreilly.com/catalog/
9780596529864. Идея заключается в том, чтобы у вас под рукой было доста-
точно примеров для выполнения большей части основных заданий по про-
граммированию.
Предисловие 5
Комментарии и вопросы
Адресуйте, пожалуйста, комментарии и вопросы, касающиеся этой книги,
издателю:
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
Основные положения
его в свет в 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
Или просто введите команду для определения версии Ruby (это работает
в UNIX/Linux):
$ ruby –v
или:
$ ruby –version
Основные положения 11
И в Windows:
ruby –v
или в Windows:
ruby 1.8.6 (2007-03-13 patchlevel 0) [i386-mswin32]
ПРЕДЛОЖЕНИЕ
Если Ruby не установлен на компьютере, а вы не совсем уверены, что
справитесь с установкой самостоятельно, прочитайте разд. "Установ-
ка Ruby" далее в этой главе. Следуя приведенным там инструкциям,
установите Ruby. А затем возвращайтесь сюда!
СОВЕТ
Неплохая идея сохранить файл в каталоге или папке, в которой вы
собираетесь работать с языком Ruby. Доступ к файлам получать
проще, когда они находятся в одном месте.
Shebang!
При выполнении программы на языке Ruby в операционной системе
Windows, обычно нужно перед именем файла с программой писать ко-
манду ruby (если только расширение rb не связано с типом файла; как сде-
лать это, см. в разд. "Сопоставление типа файлов в Windows" далее в этой
главе). В системах UNIX/Linux этого можно избежать, если добавить не-
что под названием "строка shebang (#!)" в начало файла с программой.
Добавьте строку #! в начало файла matz.rb:
#!/usr/local/bin/ruby
# a nice greeting for Matz
puts "Hello, Matz!"
ЗАМЕЧАНИЕ
Как уже говорилось ранее, Tiger поставляется со старой версией Ruby —
версией 1.8.2, которая хранится в /usr/bin. Мы не будем ее использо-
вать.
ПРЕДЛОЖЕНИЕ
Если во время выполнения программы matz.rb вы получили сообще-
ние об отказе в разрешении и не знаете, что с этим делать, я хотел бы
предложить вам помощь. См. разд. "В разрешении отказано" далее
в этой главе.
Теперь я покажу вам другие способы вывода текста "Hello, Matz!", которые
позволят вам оценить мощь Ruby. Здесь я не буду вдаваться в детали того,
что происходит. Просто следуйте инструкциям, наберите и протестируйте
столько программ, сколько захотите. Для тестирования программы выполни-
те следующие шаги:
1. Удалите предыдущую программу из matz.rb.
2. Наберите новую программу.
3. Выполните программу, вызвав интерпретатор Ruby в командной строке,
и посмотрите на результат.
Вы будете удалять старую программу из файла matz.rb и вводить на ее место
новую до тех пор, пока в тексте книги не появится файл с другим именем.
Эти другие файлы с заданными именами можно воссоздать самому или за-
грузить все файлы, упомянутые в книге, со страницы http://www.oreilly.com/
catalog/9780596529864. После загрузки перепишите файлы из zip-архива
в каталог или папку по своему выбору, туда, где вы работаете с Ruby. Пере-
ходите в каталог при помощи команды cd в командной строке.
Дублирование
Что делать, если вы хотите напечатать строку три раза? Как насчет *?
puts "Hello, Matz!" * 3
Получится:
Hello, Matz! Hello, Matz! Hello, Matz!
Можно просто напечатать одно слово три раза, а затем добавить к нему еще
текст с помощью +:
puts "Hello, " * 3 + "Matz!"
И вы получите:
Hello, Hello, Hello, Matz!
Использование переменной
Можно дать значению имя, присвоив это значение переменной:
hi = "Hello, Matz!"
puts hi # => Hello, Matz!
ЗАМЕЧАНИЕ
В примерах за символом комментария (#) всегда будет следовать
символ =>. То, что следует за ним, — ожидаемый результат работы
строки программы, программного блока или всей программы в целом.
Основные положения 15
Подстановка выражения
Вставить значение переменной в строку можно также при помощи подста-
новки выражения — весьма удобной возможности языка Ruby:
person = "Matz!"
puts "Hello, #{person}" # => Hello, Matz!
Форматирование строки
Выходные данные можно менять с помощью форматирующего флажка %s
и метода %:
hi = "Hello, %s"
puts hi % "Matz!" # => "Hello, Matz!"
puts hi % "people!" # => "Hello, people!"
puts hi % "universe!" # => "Hello, universe!"
Здесь % — метод из класса String, который форматирует строку. Вот как это
выглядит с методом sprintf:
sprintf("Hello, %s", "Маtz!") # => "Hello, Matz!"
Два параметра –e дают тот же результат, что и раньше (или то, что выглядит,
как тот же результат):
Hello, Matz!
Получится:
Matz! Matz! Matz!
Основные положения 17
Программа выводит сообщение "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, так чтобы он содержал единственный оператор
yield, затем обратитесь к новой версии hello с помощью блока (программ-
ного кода в фигурных скобках):
def hello
yield
18 Глава 1
end
Метод each
Сделаем еще один шаг. Выведем все элементы массива с помощью метода
each, за которым следует блок:
[ "Hello, ", "Matz!"].each { |e| print e }
Процедурный объект
Блок можно преобразовать в объект. Такой объект называется proc (читается
"прок") или процедурный объект (proc — procedure — процедура). Про-
цедурные объекты сохраняют среду выполнения программы, эта информация
упаковывается вместе с ними. Один из способов создания процедурного объ-
екта — это метод lambda. Я воспользовался им для формирования уже такого
знакомого вам приветствия.
prc = lambda { |name| puts "Hello, " + name }
XML
Для обработки XML (Extensible Markup Language, расширяемый язык разметки
гипертекста) в Ruby встроен REXML (Ruby Electric XML). Поприветствуйте
с его помощью уважаемого основателя, как показано в примерах 1.1 и 1.2.
Основные положения 19
<hello>Matz!</hello>
#!/usr/bin/env ruby
require "rexml/document"
file = File.new("matz.xml")
doc = REXML::Document.new file
puts doc.to_s
Класс
Поздоровайтесь с разработчиком, воспользовавшись классом Hello, как по-
казано в примере 1.3.
class Hello
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.
#!/usr/bin/env ruby
require 'tk'
hello = TkRoot.new
TkLabel.new(hello) do
text "\n Hello, Matz! \n"
pack
end
Tk.mainloop
Interactive Ruby
Interactive Ruby или irb — это интерактивная среда типа командной строки
для языка Ruby, позволяющая увидеть результаты (или ошибки) после ввода
каждого оператора. Установив Ruby, вы получили также irb.
Для начала работы с ним, наберите в командной строке:
$ irb –v
В ответ вы должны получить номер версии irb:
irb 0.9.5(05/04/13)
ЗАМЕЧАНИЕ
nil, помещенный после => в выходных данных, — это значение, воз-
вращенное методом puts. nil имеет особое значение в Ruby. Он
обозначает пустоту и всегда означает ложь.
ЗАМЕЧАНИЕ
Символ новой строки может быть разным в зависимости от платфор-
мы. В системах 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
Информационные ресурсы
На официальном сайте http://www.ruby-lang.org можно найти массу ин-
формации о Ruby. Там есть новости, файлы для загрузки, учебные пособия,
а также документация, списки рассылки и другие материалы. Компания Ruby
Central, Inc. проводит ежегодную Международную конференцию по языку
24 Глава 1
Установка Ruby
Ruby доступен на большинстве платформ. В этом разделе вы узнаете, как ус-
тановить Ruby под Mac OS X, Windows и Linux. Основная страница для за-
грузки Ruby находится по адресу: //www.ruby-lang.org/en/downloads. Веро-
ятно, большинство из вас смогло бы разобраться, как установить Ruby,
руководствуясь лишь приведенными там указаниями, но, тем не менее, в ма-
териалах этого раздела вы найдете кое-какие дополнительные инструкции.
26 Глава 1
3. Перейдите в каталог:
$ cd readline-5.2
или
$ sudo make install-doc
8. Укажите путь, если он еще не указан. Если не знаете, как это сделать, см.
врезку "Как настроить путь" далее в этой главе.
9. Теперь убедитесь, что Ruby занял свое место:
$ ruby -v
4. Добавьте каталог bin нового Ruby к своим путям; например, если Ruby
находится в каталоге C:\Ruby, добавьте к своим путям C:\Ruby\bin (см.
врезку "Как настроить путь" далее в этой главе, если не знаете, как это
сделать; указать путь можно и после установки).
5. После установки Ruby откройте окно DOS (командную строку) и наберите:
ruby –v
В разрешении отказано
Если вы впервые используете командную оболочку в Mac OS X или Linux,
то что вам делать при получении такого сообщения?
-bash: ./matz.rb: Permission denied
Скорее всего, оно означает, что файл не установлен как исполняемый. Чтобы
исправить такое положение, измените управление доступом к файлу, приме-
нив команду chmod:
chmod 755 matz.rb
ЗАМЕЧАНИЕ
Если для установки Ruby в Windows вы использовали One-Click Ruby
Installer, то все приведенные далее команды были выполнены неглас-
но, автоматически.
В Ruby почти все представляет собой объект; фактически, все, что Ruby мо-
жет связать с именем переменной, является объектом.
Многое можно узнать о классах, и вы найдете эту информацию в главе 9. Те-
перь же вполне можно обойтись основами. В примере 2.1 показана програм-
ма на языке Ruby, friendly.rb, в которой имеются два класса: Hello и Goodbye.
Вы найдете ее в архиве программ Ruby на странице http://www.oreilly.com/
catalog/learningruby. Запустите эту программу из командной строки, из ка-
талога, где установлен архив. Если примера с кодом нет в файле, наберите
его в irb, чтобы самому увидеть, что он делает. Я призываю вас выполнять
как можно больше программ.
class Hello
def howdy
greeting = "Hello, Matz!"
puts greeting
end
end
friendly = Goodbye.new
friendly.howdy
friendly.solong
Класс 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.
Зарезервированное Описание
слово
BEGIN Код, заключенный в { и }, выполняется до выполнения
программы
END Код, заключенный в { и }, выполняется, когда программа
заканчивается
alias Создает альтернативное имя (псевдоним) для сущест-
вующего метода, оператора или глобальной переменной
Обзорная экскурсия по Ruby 39
Зарезервированное Описание
слово
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
Зарезервированное Описание
слово
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 есть два основных стиля комментирова-
ния. Знак # может находиться в начале отдельной строки:
# Я комментарий. Меня нужно игнорировать.
Переменные
Переменная — это идентификатор или имя, которому может быть при-
своено значение, и это значение имеет или будет иметь тип во время вы-
полнения (когда программа выполняется). В следующем операторе пере-
менной x присвоено значение 100 при помощи знака присваивания:
x = 100
Теперь локальная переменная x содержит значение 100. Но, эй, какого оно
типа? По-моему, оно выглядит как целое — а как вы думаете? И что об этом
думает Ruby?
Большинство современных языков программирования, таких как C++ и Java,
статически типизировано. В основном это означает, что переменной при-
сваивается тип в тот момент, когда она объявляется, и, т. к. эти языки к тому
же строго типизированы, переменная остается того же самого типа до тех
пор, пока не будет приведена к другому типу, если это вообще возможно.
42 Глава 2
По желанию можно поставить в конце строки точку с запятой, но все, что вам
действительно нужно, — это символ новой строки.
Очевидно, что значения в x, months и year целого типа, но вам не пришлось
задавать их тип, потому что Ruby автоматически сделал это за вас. Это
называется динамической типизацией или "утиной" типизацией (duck
typing).
Вот как работает динамическая типизация: если вы увидели приспособив-
шуюся к воде птицу, и она ходит как утка, крякает как утка, летает как утка и
плавает как утка, то, скорее всего, это утка. Ruby подобным же образом
смотрит на присвоенное переменной значение, и если оно "ходит", "кря-
кает", "летает" и "плавает" как целое, то Ruby предполагает, что и в об-
щем оно может действовать как целое.
Давайте спросим Ruby, что он думает об x, т. е. целая ли это переменная,
с помощью метода kind_of? (это метод из класса Object).
x.kind_of? Integer # => true
Так и есть, значение x ведет себя как целое! Собственно говоря, это экземп-
ляр класса Fixnum, который наследует от класса Integer.
x.class # => Fixnum
ЗАМЕЧАНИЕ
Как я уже отмечал в главе 1, когда бы вы ни увидели стрелку => в коде
примера, она всегда следует за символом комментария (#). То, что
следует за =>, это результат вычисления строки или блока кода или
всей программы.
Обзорная экскурсия по Ruby 43
Локальные переменные
Ранее я обращался к x как к локальной переменной. Что это означает? Это
означает, что переменная имеет локальную область видимости (контекст).
Например, когда локальная переменная определена внутри метода или цикла,
ее область видимости находится внутри того метода или цикла, где она оп-
ределена. За его пределами ей нет применения.
Имена локальных переменных должны начинаться со строчной буквы или
с символа подчеркивания (_), например, alpha или _beta. Другой признак, по
которому в Ruby можно определить локальную переменную, состоит в том,
что ее имени не предшествует никакой специальный символ или знак, кроме _.
Любые другие типы переменных можно легко распознать по предшествую-
щему символу. В эти другие типы входят глобальные переменные, перемен-
ные экземпляра и переменные класса.
Переменные экземпляра
Переменная экземпляра — это переменная, к которой обращаются через эк-
земпляр класса и которая, следовательно, принадлежит заданному объекту.
Имя переменной экземпляра начинается с единичного знака "эт" (@), вот так:
@hello = hello
Переменные класса
Переменная класса совместно используется всеми экземплярами класса. Для
заданного класса существует только одна копия переменной класса. В Ruby
ей предшествуют два знака "эт" (@@). Вы должны проинициализировать пе-
ременную класса (объявить для нее значение) до того, как ее использовать.
@@times = 0
Глобальные переменные
Глобальные переменные доступны в программе глобально, внутри любой
структуры. Их областью видимости является вся программа целиком. Их
имена начинаются со знака доллара ($).
$amount = "0.00"
44 Глава 2
Константы
Константы на протяжении жизни программы на языке Ruby содержат посто-
янные значения. Константы — это переменные, чьи имена начинаются
с заглавной буквы или содержат только заглавные буквы. Далее приведено
описание константы с именем Matz:
Matz = "Yukihiro Matsumoto"
puts Matz # => Yukihiro Matsumoto
Параллельное присваивание
Мне нравится способность Ruby выполнять параллельное присваивание (как
в языках Perl, Python и JavaScript 1.7). Что это такое? Это способ присвоить
значение группе или серии переменных в одном операторе, на одной строке.
Часто мы присваиваем значения переменным по одному на каждой строке:
x = 100
y = 200
z = 500
Можно присваивать даже значения различных типов, таких как строка, число
с плавающей точкой и целое число:
a, b, c = "cash", 1.99, 100
Строки
Строка — это последовательность букв, цифр и других символов. В Ruby
есть несколько способов создания строки, но, пожалуй, простейший из них —
непосредственно написать ее, заключив в кавычки (годятся и двойные, и оди-
нарные). Тут у нас цитата из "Уолдена" Генри Торо:
thoreau = "If a man does not keep pace with his companions, perhaps it is
because he hears a different drummer."
ЗАМЕЧАНИЕ
Если вы в своей программе хотите использовать что-нибудь еще кроме
символов ASCII, вам следует прочесть это замечание; в противном
случае, эта информация вам, возможно, не нужна. Должен признать,
что полагать, будто символ синонимичен байту, по крайней мере, ста-
ромодно. В более широком смысле, в мире, основанном на Unicode,
символы могут быть представлены более чем одним байтом. На-
пример, кодировка символов UTF-8 представляет символы длиной от
одного до четырех байтов. По умолчанию, Ruby использует кодировку
символов ASCII, но вы можете сменить ее, установив (в начале про-
граммы) значение переменной $KCODE равным "u" (для UTF-8), "e"
(для EUC), "s" (для SJIS) и "a" или "n" (для ASCII или NONE).
46 Глава 2
Регулярные выражения
Регулярное выражение — это специальная последовательность символов,
которая сопоставляется со строками или множеством строк. Регулярные вы-
ражения часто применяются для поиска образца в строке, с тем чтобы вы
могли сделать что-то еще с этой строкой или выполнить какие-то другие опе-
рации. Регулярные выражения также служат для извлечения строки или под-
строки (части строки) и применения ее в другом месте.
Регулярные выражения используют элементы (один или несколько симво-
лов), чтобы проинструктировать механизм регулярных выражений, как ис-
кать заданную строку. Комбинация специальных символов, заключенная ме-
жду двумя косыми чертами (//), составляет шаблон регулярного выражения.
Вот некоторые примеры таких элементов:
^ — сопоставляется с началом строки;
$ — сопоставляется с концом строки;
\w — сопоставляется с символом слова;
[...] — сопоставляется с любым символом в квадратных скобках;
[^...] — сопоставляется с любым символом не в квадратных скобках;
Обзорная экскурсия по Ruby 47
Числа и операторы
Почти в любом объектно-ориентированном языке программирования числа
считаются фундаментальными элементарными объектами, называемыми
примитивами. Они не связаны напрямую ни с каким классом; они просто
есть. Но не так обстоят дела в 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 имеются условные операторы,
в которых проверяется, является ли условие истинным или ложным. Затем,
в зависимости от ответа, выполняется блок кода. Вот на скорую руку пример-
Обзорная экскурсия по Ruby 49
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"]
Методы
Методы обеспечивают средства сбора кода (операторов и выражений) в од-
ном месте, так чтобы воспользоваться им было легко и, при необходимости,
многократно. Вы можете определять методы для выполнения любого рода
вещей. В действительности, большая часть математических операторов в Ruby
является методами.
ЗАМЕЧАНИЕ
Это самое активное обсуждение методов, какое только можно найти
в книге, так что, вполне вероятно, вам захочется позднее вернуться
обратно в этот раздел.
Метод hello просто выводит строку при помощи puts. Обратная сторона за-
ключается в том, что с помощью undef можно сделать метод неопределенным.
undef hello # делает неопределенным метод с именем hello
Возвращаемые значения
У методов есть возвращаемые значения. В других языках вы можете явно
доставить возвращаемое значение при помощи оператора 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
Если имя метода заканчивается знаком вопроса (?), как в eql?, то метод воз-
вращает булево значение — true или false. Например:
x = 1.0
y = 1.0
x.eql? y # => true
n = Name.new
n.family_name= "Matsumoto" # => "Matsumoto"
n.given_name= "Yukihiro" # => "Yukihiro"
p n # => <Name:0x1d441c @family_name="Matsumoto",
# @given_name="Yukihiro">
Параметры по умолчанию
Метод repeat, показанный ранее, имеет два параметра. Вы можете присвоить
этим параметрам значения по умолчанию при помощи знака равенства, за
которым следует значение. Когда метод вызывается без параметров, значения
по умолчанию выбираются автоматически.
Переопределите repeat со значениями по умолчанию: Hello для word и 3 для
times. Затем вызовите его без параметров и с параметрами.
def repeat( word="Hello! ", times=3 )
puts word * times
end
puts num_args
puts num_args(1)
puts num_args( 100, 2.5, "three" )
Псевдонимы методов
В 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
Можно заменить do/end парой фигурных скобок, как это обычно и делают,
чтобы получить более компактную запись (между прочим, фактически, фи-
гурные скобки имеют более высокий приоритет, чем do/end):
pacific.each { |e | puts e }
Метод each есть в десятках классов, таких как Array, Hash и String. Но пусть
у вас не возникнет неправильное представление. Выполнение итераций над
структурами данных — не единственный способ применения блоков. По-
звольте привести вам простой пример использования yield, ключевого слова
языка Ruby.
Оператор yield
Прежде всего, определим крошечный метод gimme, в котором нет ничего,
кроме оператора yield:
def gimme
yield
end
Вы получили здесь ошибку, потому что работа yield состоит в том, чтобы
выполнять блок кода, связанный с методом. В вызове gimme таковой отсутст-
вовал. Этой ошибки можно избежать, воспользовавшись методом
block_given? из модуля Kernel. Переопределите gimme, добавив оператор if:
def gimme
if block_given?
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 ("проках").
#!/usr/bin/env ruby
Программа, после того как даст вам знать, что каждый из созданных вами
объектов является объектом класса Proc, выполнит следующий вывод, вы-
звав каждую процедуру с помощью метода call:
12345
Lurch: 'You rang?'
Morticia: 'Who was at the door, Lurch?'
#! /usr/local/bin/ruby
def return_block
yield
end
Вот результат:
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
ЗАМЕЧАНИЕ
Если вы опытны в программировании на языках 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.
_produces:_
(выводит:)
cat12399
cat, 1, 2, 3, 99
ЗАМЕЧАНИЕ
Две связанные друг с другом структуры rescue и ensure, которые
служат для обработки исключений, здесь не рассматриваются. Они
обсуждаются в главе 10.
Оператор if
Давайте начнем с самого простого и усложнять будем постепенно.
if 1 == 1 then
print "True!"
end
Если правда, что 1 равно (==) 1, а так оно и есть, то оператор if возвра-
щает true, что приводит к выполнению блока кода, состоящего из одного
66 Глава 3
Сумма будет напечатана, если все эти выражения истинны. Можно вместо &&
поставить ключевое слово 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
if height >= 6 then print "L or XL" end # больше или равен (не меньше)
print "shrimpy" if weight <= 100 # меньше или равен (не больше)
68 Глава 3
Здесь сказано, что если queue не равно true, то значение оператора вычисля-
ется как истинное, и оператор print печатает "The queue is empty!". Альтер-
нативой для ! является ключевое слово not.
if not queue then print "The queue is empty." end
ЗАМЕЧАНИЕ
Вокруг слов true или false нет кавычек, потому что они не являются
строками. Фактически, true — единственный экземпляр класса
TrueClass. Его дополнение, false, является единственным экземп-
ляром класса FalseClass. Еще true и false считаются псевдопе-
ременными, которые выглядят, как переменные, а ведут себя, как
константы, и которым не могут быть присвоены значения.
Ключевое слово elsif обеспечивает вас после начального if одним или не-
сколькими промежуточными вариантами, в которых можно протестировать
различные операторы (выражения).
Любовь к условным операторам 69
ЗАМЕЧАНИЕ
Обратите внимание, в elsif только одна буква e, не две. Мои пальцы
все время забывают об этом, и я оказываюсь в отладочном режиме.
СОВЕТ
Не ставьте после else (последнего оператора) двоеточие.
Трехместный оператор
Трехместный оператор (?:) или оператор с основанием три — это сжатая
структура, проникшая в Ruby из С. В языке С он назывался условным выра-
жением. Условное выражение разбито на три части.
70 Глава 3
Оператор 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
Цикл while
Цикл while выполняет содержащийся в нем код до тех пор, пока условие ос-
тается истинным. Приведенный далее фрагмент кода задает начальное значе-
ние счетчика равным 0 и создает массив breeds, содержащий четыре элемента
с названиями пород лошадей. Он также создает временный массив с именем
temp. (О массивах вы узнаете в главе 6.)
Несколько следующих абзацев до некоторой степени относятся к фундамен-
тальным знаниям и предназначены для начинающих программистов. Но если
72 Глава 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?"
Так что 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"]
В сущности, в этом примере говорится, что пока значение lang не равно de,
переменной dog будет присваиваться значение "dog"; в противном случае dog
будет присвоено значение "Hund".
Видите, как операторы поменялись местами? В операторе if присвоение
"Hund" переменной dog идет первым; в примере с unless первым идет при-
своение "dog" переменной dog.
Как в случае с if, можно применять unless в качестве модификатора опера-
тора:
puts age += 1 unless age > 29
Метод loop
Метод loop происходит из модуля Kernel. Он позволяет выполнять цикл не-
прерывно, — как for(;;) в С — пока вы или программа не сделаете что-
нибудь, чтобы вырваться из него.
Выполните код из примера 3.1.
loop do
print "Type something: "
line = gets
break if line =~ /q|Q/
puts line
end
Цикл for
Цикл for — знакомая структура для опытных программистов. В этом приме-
ре в for для распечатки списка чисел от 1 до 5 используется диапазон (1..5).
for i in 1..5 do
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 есть конкуренты в лице методов 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, как
вы можете видеть, использует блок, и он немного проще для набора. Он при-
меняется широко, и он в стиле 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 для своего волшебства применяет блок. Цикл 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 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
Строки
или
ri String.chop
Между именами класса и метода можно набрать # или точку (.). Само собой
разумеется, что у вас установлен пакет документации по языку Ruby и к нему
указан путь (см. разд. "Установка Ruby" главы 1).
Создаем строки
Можно создавать строки с помощью метода new. Например, в этой строке
создается новая, пустая строка, названная title:
title = String.new # => ""
Теперь у вас есть новая строка, но она наполнена только "виртуальным" воз-
духом. Можно проверить строку, не пустая ли она, с помощью метода empty?:
title.empty? # => true
82 Глава 4
Вы, вероятно, захотите убедиться, что строка не пустая, до того, как возьме-
тесь обрабатывать ее, или вам понадобится завершить процесс обработки,
когда очередь дойдет до пустой строки. Можно также проверить длину стро-
ки или ее размер:
title.length
или
title.size # => 0
Но есть еще более простой способ. Для генерации новой строки не нужны
методы new или String. Прекрасно подойдут оператор присваивания и пара
двойных кавычек:
sad_love_story = "Romeo and Juliet"
Конкатенация строк
В Ruby можно дополнить существующую строку, применяя различные спо-
собы конкатенации. С Ruby вам не придется скакать через обруч, как при-
шлось бы, если бы вы писали на языке с неизменными строками.
Строки 85
Соседние строки могут быть сцеплены просто потому, что они стоят рядом
друг с другом:
"Hello, " " " "Matz" "!" # => "Hello, Matz!"
# объект заморожен?
greet.frozen? # => true
Сравниваем строки
Время от времени вам необходимо протестировать две строки, чтобы по-
смотреть, одинаковые они или нет. Можно проделать это с помощью ==.
Например, вы хотели бы проверить строку перед тем, как напечатать что-то:
print "What was the question again?" if question == ""
Результат равен 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
Введите строку как параметр к методу []=, и он, если найдет ее, вернет но-
вую, откорректированную строку; и nil в противном случае.
speaker[", 2007"]= "III" # => "III"
p speaker # => "King Richard III"
Уже лучше.
Если вы определите Fixnum (целое) в качестве индекса, метод вернет строку
с корректировкой, которую вы поместили по указанному индексу. (Длины
строк Ruby подгоняет автоматически, если замещающая строка имеет длину,
отличную от оригинала.)
cite[13]= "IV" # => "IV"
p cite # => "Act V, Scene IV"
90 Глава 4
Теперь применим его снова, и chomp! вернет nil без изменения строки, по-
тому что в конце строки больше нет разделителя записей:
joe.chomp! # => nil
Метод 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"
Заменяем подстроку
Попробуйте gsub (или gsub!). Этот метод замещает подстроку (первый па-
раметр) замещающей строкой (второй параметр):
"That's alll folks".gsub "alll", "all" # => "That's all folks"
# другой объект
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
Ущерб невелик. Даже несмотря на то, что reverse! изменил строку по месту.
Подумайте немного об этом.
От строки к массиву
Метод split без труда преобразует строку в массив. Первый вызов split
обойдется без параметров:
"0123456789".split # => ["0123456789"]
ЗАМЕЧАНИЕ
В этом примере подразумевается, что символ представляется един-
ственным байтом, что происходит не всегда. Для Ruby набором сим-
волов по умолчанию является ASCII, символ которого может быть
представлен байтом. Однако в UTF-8 представление одного символа
занимает от одного до четырех байтов. Можно изменить набор симво-
лов с ASCII на UTF-8, определив $KCODE='u' в начале программы.
Какова длина строки? Это может оказаться для вас важным (length и size —
синонимы).
title.size # => 19
96 Глава 4
Что произошло? Ничего! И все потому, что параметр должен быть больше
длины строки, чтобы что-нибудь делалось. Добавляемые пробелы рассчиты-
ваются на основе длины строки и значения параметра. Смотрите:
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"
Метод добавляет символ, когда достигает границы, или добавляет цифру или
десятичный разряд в подходящих случаях, как показано в этих примерах:
"z".next # => "aa" два a после одного z
"zzzz".next # => "aaaaa" пять a после четырех z
98 Глава 4
Вам решать, что проще. Цикл for требует не намного больше ударов по кла-
вишам (29 против 31, включая пробелы). Но я предпочитаю upto.
Преобразуем строки
Можно преобразовать строку в число с плавающей точкой (Float) или в це-
лое число (Fixnum). Для преобразования строки в число с плавающей точкой,
Строки 99
Преобразуем объект в строку при помощи 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"]
Привязки привязывают шаблон к началу (^) или концу ($) строки текста:
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
ЗАМЕЧАНИЕ
Можно также определить количество цифр "по крайней мере" с помощью
{m,}> и минимальное/максимальное количество с помощью {m,n}.
В классе String есть также метод =~ и оператор !~. Если метод =~ обна-
руживает совпадение, он возвращает смещение, т. е. позицию, с которой
в строке началось совпадение:
color =~ /colou?r/ # => 13
Шаблон Описание
/pattern/опции Шаблон pattern между двумя косыми чертами, за которым
следуют необязательные опции, т. е. один или несколько сим-
волов: i — независимость от регистра; о — подстановка; x —
игнорирование пробельных символов, допускаются коммента-
рии; m — сопоставление нескольких строк текста, символы пе-
ревода строки считаются обычными символами
%r!pattern! Основная строка с разделителями для регулярного выражения,
где ! — произвольный символ
^ Соответствует началу строки текста
$ Соответствует концу строки текста
. Соответствует любому символу
\1...\9 Соответствует n-ому групповому подвыражению
\10 Соответствует n-ому групповому подвыражению, если соответ-
ствие уже найдено; в противном случае ссылается на восьме-
ричное представление кода символа
\n, \r, \t и т. д. Соответствует символу в обозначении с обратной косой чертой
Строки 103
Шаблон Описание
\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
Шаблон Описание
? Соответствует нулевому количеству или одному предыдущему
регулярному выражению
| Чередование, как 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 внутри этой неохвачен-
ной группы
Математика
Object
Matrix
Numeric
Integer
Rational
Fixnum Bignum
Complex
Math Precision
module module
Преобразуем числа
Можно преобразовать число в целое из другой формы с помощью метода
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
Многие из этих методов родились, как методы класса 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
ЗАМЕЧАНИЕ
В Ruby нет операторов инкремента (++) или декремента (--), как в С
или других языках.
Операторы
В табл. 5.1 перечислены математические операторы языка Ruby по старшин-
ству операций. Если оператор определен как метод, это указывается в колон-
ке "Метод", и этот метод может быть заменен.
Таблица 5.1. Математические операторы языка Ruby
Диапазоны
Как было рассмотрено ранее, в 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, вне диапазона, для оператора диапазона ...
Слишком очевидно. (Но именно это мне нравится в 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
else
puts "Only whole persons can come to this party."
# (Только целый субъект может прийти на этот прием.)
end
или так:
10.times do |i| print 5*i, " " end
118 Глава 5
Получите следующее целое число при помощи next (или его псевдонима
succ):
-24.next # => -23
1.next # => 2
999.next # => 1000
Математические функции
Модуль Math поставляет многие математические функции (через методы
класса). Я покажу вам, как применять некоторые из них, чтобы можно было
начать работать.
В Math есть также две константы с соответствующими методами. Чтобы ус-
тановить, какие константы определены в Math (или любом другом модуле
или классе), воспользуйтесь рефлексией, вызвав метод constants:
Math.constants # => ["E", "PI"]
В табл. 5.2 показаны все математические функции (все методы класса), до-
ступные из модуля Math. Запомните, что по договоренности, методы Ruby,
заканчивающиеся !, производят изменения по месту (или с разрушением)
объекта, а не его копии.
120 Глава 5
Метод Описание
Рациональные числа
Рациональное число — это число, которое может быть выражено в виде дро-
би, числитель и знаменатель которой являются целыми числами. Ruby под-
держивает применение рациональных чисел посредством класса Rational.
Чтобы воспользоваться классом Rational, вы должны затребовать его в про-
грамме. Если к тому же затребовать библиотеку mathn, библиотека Rational
будет работать лучше. Теперь я расскажу вам вкратце, как в Ruby обрабаты-
ваются дроби.
Математика 121
require 'rational'
require 'mathn'
ЗАМЕЧАНИЕ
Когда вы используете Rational, все операции над числами в програм-
ме приводят к созданию рациональных результатов.
Простые числа
В библиотеке mathn, которая оказывает содействие работе математических
классов, имеется класс Prime, который позволит вам последовательно гене-
рировать простые числа, начиная с 2. В действительности в качестве началь-
ного числа он выбирает 1, но вычисляет первое простое как 2, как и должно
быть. В Prime есть четыре метода: new, который создает новый объект Prime;
next и succ (синонимы), которые производят следующее простое число;
и each, который перечисляет простые числа до тех пор, пока что-нибудь его
не остановит.
Программа в примере 5.2 покажет вам, как генерировать простые числа, одно
за другим.
require 'mathn'
Код в примере 5.3 генерирует 25 простых чисел — все простые числа от 2 до 97.
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
Массивы
Создаем массивы
Существует много средств для создания или инициализации массива. Одно
из них — метода new этого класса:
months = Array.new
Здесь создан пустой массив, представленный как [], с именем months. Чего-
то не хватает, не так ли? Фактически можно проверить, пуст массив или нет,
методом empty? (он возвращает true, если массив, несомненно и совершен-
но, пуст, false — в противном случае):
months.empty? # => true
или так:
months = Array.new 12
или:
months.length # => 12
Но что за элементы были до сих пор в months? Все они были nil, потому что
никто (а это должен был быть я) не позаботился определить, что они собой
представляют. На этот момент массив months содержит 12 значений nil.
Чтобы проинспектировать массив, т. е. взглянуть на массив, как на массив,
воспользуйтесь:
puts months.inspect
или:
p months
Массивы 127
Драим палубу
Чуть лучше, но еще не то. Знайте, если вам не нравится то, что вы получили,
вы всегда можете очистить массив с помощью clear:
month.clear # => []
month.empty? # => true
Или вот так, если опустить точку (.) и круглые скобки (()), что возможно
благодаря гибкому синтаксису методов Ruby:
month_abbrv = Array[ "jan", "feb", "mar", "apr", "may", "jun", "jul",
"aug", "sep", "oct", "nov", "dec" ]
128 Глава 6
ЗАМЕЧАНИЕ
Почему этот массив начинается с nil? Я воспользовался искусст-
венным заполнителем. Это первый элемент в массиве months, и, как
таковой, он связан с индексом 0. Я хочу связать первый месяц года
с индексом 1, а не 0, поэтому я и вставил nil в качестве первого
элемента. Таково мое предпочтение, но оно не обязано быть вашим.
Вы не этого хотели, да? Ну, хорошо, есть способ даже еще проще определить
массив строк — воспользоваться нотацией %w. Этот способ подразумевает,
что все элементы являются строками (даже nil), но он определенно экономит
удары по клавишам (не надо набирать кавычки и запятые):
months = %w[ nil January February March April May June July August Sep-
tember October November December]
Правда, я не хочу, чтобы nil был представлен как строка. Как мне восполь-
зоваться своей любимой нотацией (%w) и одновременно решить эту пробле-
му? Да вот так:
months[0] = nil;
Массивы 129
У вас даже может быть массив, который содержит объекты из других клас-
сов, т. е. не все одного типа. Например, вот массив, в котором содержатся
четыре элемента, все — объекты различных типов:
hodge_podge = ["January", 1, :year, [2006,01,01]]
или такой:
q1[-2]
Можно увидеть обратную сторону с помощью метода index. Этот метод воз-
вращает индекс, а не элемент, основываясь на параметре (объекте). Он вер-
нет индекс первого элемента, соответствующего объекту:
q1.index "March" # => 2
Напомню, что две точки означают "включить оба элемента", а три точки —
"не включать последний элемент". (Между прочим, вы не сможете указать
диапазоны в методе 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]
Конкатенация
Давайте немного поиграем с приведенными далее массивами:
q1 = %w[ January February March ]
q2 = %w[ April May June ]
q3 = %w[ July August September ]
q4 = %w[ October November December ]
Результат говорит о том, что я планирую делать в оба этих дня (я не буду
читать).
Разность (-) создает новый массив, удаляя элементы, которые обнаружились
в обоих массивах:
wed - tue # => ["read"]
Уникальные элементы
Метод 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"]
С этим методом близко связан метод eql?. Он возвращает true, если объекты
одинаковы, или если их содержимое одинаково. В чем разница между ==
и eql?. Метод eql? проверяет, равны ли значения (как ==), но он также про-
веряет, имеют ли значения один и тот же тип.
bob == schlomo # => true
bob.eql?( "full, 40, yes" ) # => false, bob — не строка
Изменяем элементы
Ruby предоставляет массу способов воздействия на элементы массивов,
например, способы изменения их значений, способы их представления.
Начнем с самых простых изменений. Давайте вернемся к нашему масси-
ву months:
months = %w[ nil January February March April May June July August Sep-
tember October November December ]
Как строка
С помощью метода to_s можно извлечь элементы массива как отдельные
строки. Метод to_s является общим для многих классов.
greeting = [ "Hello! ", "Bonjour! ", "Guten Tag!" ]
puts greeting.to_s # => Hello! Bonjour! Guten Tag!
136 Глава 6
Не совсем то, что вы имели в виду? Давайте вставим между элементами запя-
тую и пробел:
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, который добавляет объекты (один или несколь-
ко) в массив. Он подобен 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.delete("noon") {"noon wasn't found. What are you going to do
about it?"}
Массивы и блоки
В классе 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"]
Примените к нему sort (или sort! для изменений по месту), и ваш сбивший-
ся с пути массив выстроит свои элементы по порядку:
x.sort! # => [1, 2, 5, 7, 14, 23, 27, 99]
138 Глава 6
ЗАМЕЧАНИЕ
Для сортировки массива необходимо, чтобы его элементы были срав-
нимы (больше, меньше или равны). Это легко проделать со строками
и числами. Но т. к. массивы в Ruby могут хранить объекты любого типа,
те могут оказаться несравнимыми, и, в этом случае, вы не сможете
отсортировать элементы при помощи sort или sort!.
Многомерные массивы
Многомерный массив — это массив массивов. Вы создаете такой мас-
сив, задавая элементы, которые сами являются массивами. Вот двумерный
массив:
d2 = [ ["January", 2007],
["February", 2007],
["March", 2007] ]
в:
d2.transpose
# => => [["January", "February", "March"], [2007, 2007, 2007]]
или
ri Array.map
или
ri "Array.&"
Хэши
Создаем хэш
Как и в случае с массивами, создать хэш можно различными способами. Пус-
той хэш вы можете создать с помощью метода new класса:
months = Hash.new
Можно проверить, пустой ли хэш, при помощи empty?:
months.empty? # => true
Или насколько он велик, при помощи length или size:
months.length
months.size # => 0
142 Глава 7
или так:
months = Hash.new "month"
или:
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"}
Самое простое средство создания хэша, как мне кажется, — это фигурные
скобки:
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" }
Далее у нас есть методы keys и values. При помощи keys вернем массив, со-
держащий все ключи, имеющиеся в хэше:
zip.keys
# => [83110, 83127, 82336, 83112, 82084, 83025, 82442, 82443, 82240]
Выполняем итерации
Как вы уже видели, 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
Изменяем хэши
Метод []= из Hash замещает или добавляет пары "ключ-значение" в сущест-
вующий хэш. Например:
rhode__island = { 1 => "Bristol", 2 => "Kent", 3 => "Newport",
4 => "Providence", 5 => "Washington" }
Между прочим, в этом хэше в качестве ключей указаны целые числа, подоб-
но тому, как индексируется массив, но в нем не используется 0, который
в массиве является первым индексом.
Для добавления пары можно применить метод []=:
rhode_island[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
Сортируем хэш
Если вы сортируете хэш методом 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.delete( 6 ) { |key| puts "not found, bubba" }
Метод delete_if передает в блок всю пару, так что вы можете выполнить
уничтожение, основываясь или на ключе, или на значении. Вот пример унич-
тожения, основанного на значении:
rhode_island.delete_if { |key, value| value == "Kent" }
# => { 5 => "Washington", 1 => "Bristol", 3 => "Newport",
# 4 => Providence"}
Замещаем хэш
Для того чтобы полностью заменить содержимое хэша, применяйте метод
replace. В этом примере содержимое хэша counties замещается содержи-
мым temp:
temp = {"Delaware" => 3 }
counties.replace( temp )
Когда вы преобразуете хэш в хэш (сам в себя) с помощью 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
или:
ri Hash::[]
или:
ri Hash#keys
Работа с файлами
Каталоги
Перемещаться по структуре каталогов своего компьютера вы сможете с по-
мощью методов из класса Dir. Здесь я выделю три метода: Dir.pwd,
Dir.chdir (или Dir.getwd) и Dir.mkdir.
Прежде всего, я сменю каталог (использую абсолютный путь доступа), а за-
тем сохраню в переменной значение пути к каталогу.
Dir.chdir( "/Users/mikejfz" )
home = Dir.pwd # => "/Users/mikejfz/"
p home # => "/Users/mikejfz"
152 Глава 8
Если вам необходим каталог, создайте его при помощи mkdir; впоследствии
удалите его при помощи rmdir (или delete, это тезка rmdir):
Dir.mkdir( "/Users/mikejfz/sandbox" )
Dir.rmdlr( "/Users/mikejfz/sandbox" )
755 означает, что владелец или пользователь каталога может читать из него,
писать в него и исполнять программы; группа может читать из каталога
и исполнять программы; и все остальные могут читать и исполнять програм-
мы (см. табл. 8.2).
Заглянем в каталог
Метод entries класса Dir возвращает массив, который содержит все элемен-
ты, найденные в каталоге, включая файлы, скрытые файлы и другие катало-
ги, по одному элементу массива на элемент каталога. Я применил метод each
из Array к результату работы entries:
Dir.entries( "/usr/local/src/ruby-1.8.6" ).each { |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 # => закрывает поток
Режим Описание
r Только для чтения. Стартует с начала файла (режим по умолчанию)
r+ Чтение/запись. Стартует с начала файла
w Только для записи. Усекает существующий файл до нулевой длины или
создает новый файл для записи
w+ Чтение/запись. Усекает существующий файл до нулевой длины или соз-
дает новый файл для чтения и записи
154 Глава 8
Режим Описание
a Только для записи. Стартует с конца файла, если файл существует;
в противном случае, создает новый файл для записи
a+ Чтение/запись. Стартует с конца файла, если файл существует;
в противном случае, создает новый файл для чтения и записи
b (Только для DOS/Windows.) Режим двоичного файла. Может появляться
с любыми ключевыми символами, перечисленными выше
ЗАМЕЧАНИЕ
Можно также создавать файлы при помощи new с флажками и битами
полномочий. Дополнительную информацию ищите на
http://www.ruby-doc.org/core/classes/File.html.
ЗАМЕЧАНИЕ
Методы 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
ARGV и ARGF
Другой интересный способ организовать то же самое мероприятие состоит
в применении ARGV и всего лишь двух строк кода (пример 8.2).
Как это работает? Напомню, что 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
ARGF ($<) является, еще раз напомню, виртуальной конкатенацией всех фай-
лов, появившихся в командной строке. Сравните программу argf.rb из приме-
ра 8.3 с argv.rb.
Открываем URI
Этот вопрос напрямую не связан с классом File, но я думаю, что и такой
связи достаточно, и он вызовет неподдельный интерес у некоторых из вас.
(Я должен поблагодарить Райана Уолдрона (Ryan Waldron) за то, что он об-
ратил на него мое внимание. Спасибо, Райан.)
Питер Сцинек (Peter Szinek) написал блог, где использовал Ruby для выпол-
нения "зачистки" (scraping — анализ и обработка экранных данных для из-
влечения интерфейсной информации) экрана. Он — создатель scRubyt, на-
бора инструментальных средств (web scraping toolkit), написанного на Ruby
(см. http://www.scrubyt.org). Я позаимствовал его самый простой пример
(пример 8.4), чтобы дать вам некоторое представление о том, как это работает.
Работа с файлами 157
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}
}
Файловые запросы
С помощью методов из File можно выполнять любые файловые запросы.
Проверки такого типа часто выполняются перед другими файловыми про-
цедурами. Например, приведенная далее команда проверяет, существует ли
файл, перед тем, как открывать его:
File::open("file.rb") if File::exists?( "file.rb" )
Можно выяснить, имеет ли файл нулевую длину (0) при помощи zero?:
system("touch chap.txt") # Создайте файл нулевой длины с помощью
# команды system
File.zero?( "chap.txt" ) # => true
Узнайте, когда файл был создан, модифицирован или когда к нему послед-
ний раз обращались, при помощи методов 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
или:
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
Все могут читать файл, но только владелец может записывать в него, и никто
не может исполнять его.
Документацию по работе команды chmod в Mac OS X ищите на
http://www.hmug.org/man/2/chmod.php.
Маска Описание
0700 Маска rwx для владельца
0400 r для владельца
0200 w для владельца
0100 x для владельца
160 Глава 8
Маска Описание
Можно изменить владельца или группу для файла методом chown, который
подобен команде chown в UNIX/Linux. Чтобы воспользоваться этим методом,
необходимы права привилегированного пользователя или root.
file = File.new( "books.txt", "r" )
file.chown( 109, 3333 )
или:
file = File.new( "books.txt", "r" ).chown( 109, 3333 )
Класс IO
В Ruby основным классом для всего ввода и вывода является класс IO, кото-
рый представляет входные/выходные (I/O) потоки данных в форме байтов.
В стандартные потоки входят: стандартный входной поток ($stdin) с клавиа-
туры, стандартный выходной поток ($stdout) на дисплей и стандартный
Работа с файлами 161
Режим Описание
r Только для чтения. Стартует с начала файла (режим по умолчанию)
r+ Чтение/запись. Стартует с начала файла
w Только для записи. Усекает существующий файл до нулевой длины
или создает новый файл для записи
w+ Чтение/запись. Усекает существующий файл до нулевой длины или
создает новый файл для чтения и записи
a Только для записи. Стартует с конца файла, если файл существует,
в противном случае создает новый файл для записи
162 Глава 8
Режим Описание
a+ Чтение/запись. Стартует с конца файла, если файл существует,
в противном случае создает новый файл для чтения и записи
b (Только для DOS/Windows.) Режим двоичного файла. Может появ-
ляться с любым из режимов, перечисленных в этой таблице
$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
Классы
Определяем класс
Класс определяется при помощи ключевого слова class, за которым следует
end. Идентификатор класса является константой, поэтому он должен начи-
наться с заглавной буквы (в норме), но он также может быть целиком состав-
лен из заглавных букв — Hello или HELLO вместо hello.
В примере 9.1 показан класс Hello, который вы видели в главе 1, теперь я
расскажу о нем подробнее.
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
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
h = Horse.new
h.name # => "Easy Jet"
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
Аксессоры
Если вы знакомы с созданием классов в других языках программирования,
вы, без сомнения, создавали также методы-геттеры и методы-сеттеры. Эти
методы устанавливают и получают (возвращают) для класса значения. Ruby
упрощает создание геттеров и сеттеров с помощью капельки метапрограм-
мирования и методов attr, attr_reader, attr_writer и attr_accessor из
класса Module. Метапрограммирование — это условное обозначение способа
170 Глава 9
#!/usr/bin/env ruby
class Dog
attr :bark, true
end
При вызове 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
class Dog
attr_reader :bark
attr_writer :bark
end
dog = Dog.new
dog.bark="Woof!"
puts dog.bark # => Woof!
Как показано в примере 9.5, метод attr_accessor выполняет для одного или
более методов экземпляра класса ту же самую работу, что и методы
attr_reader и attr_writer вместе взятые.
#!/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 переменная класса поделена между всеми экземплярами класса, так
что для данного класса существует только одна копия переменной класса.
В Ruby имя переменной класса начинается двумя "коммерческими at" (@@).
Вы обязаны проинициализировать атрибут класса перед использованием:
@@times = 0
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
puts data.repeat # => ack ack ack ack ack ack ack ack
puts data.total # => Total times, so far: 8
Методы класса
Метод класса — это метод, который ассоциируется с классом (а в Ruby
и с модулем), а не с экземпляром класса. Активизировать методы класса
можно, указав имя метода вместе с именем класса, которому он принадле-
жит. Методы класса известны также как статические методы.
В Ruby вы можете к тому же связать с именем метода имя модуля, как в слу-
чае класса, но чтобы воспользоваться таким методом, вы обязаны включить
модуль в класс. В этой строке имени метода sqrt предшествует имя модуля
Math, о котором вы читали в главе 5.
Math.sqrt(36) # => 6.0
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
Одноэлементные классы
Можно также определять методы класса путем использования класса внутри
класса — одноэлементного (singleton) класса — как в коде примера 9.8.
174 Глава 9
class Area
end
end
s = Singleton.new
def s.handle
puts "I'm a singleton method!"
end
(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).
#!/usr/bin/env ruby
class Name
attr_accessor :given_name, :family_name
176 Глава 9
end
a = Address.new
puts a.respond_to?(:given_name) # => true
class Name
attr_accessor :given_name, :family_name
end
#!/usr/bin/env ruby
require 'name'
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 имеются также модули. Модуль подобен
классу, но для него нельзя создать экземпляр, как для класса. Чем он удобен?
Итак, класс может включать модуль, так что когда для класса создается эк-
земпляр, он получает собственность включенного модуля. Методы из вклю-
ченного модуля становятся методами экземпляра класса в классе, который
включает модуль. Это называется смешиванием, а на модуль ссылаются как
на mixin. Смешивание помогает преодолеть проблемы, проистекающие из
множественного наследования.
Модуль в Ruby является формой пространства имен. Пространство имен —
это множество имен, таких как имена методов, которые имеют область види-
мости или контекст. Модуль в Ruby связывает одно имя с набором имен ме-
тодов и констант. Имя модуля можно использовать в классах в других моду-
лях. Обычно областью видимости или контекстом такого пространства имен
является класс или модуль, в который включено пространство имен (имя мо-
дуля). Класс в Ruby тоже может рассматриваться как пространство имен.
Имя модуля должно быть константой, т. е. оно должно начинаться с заглав-
ной буквы. Модуль может содержать методы, константы, другие модули
и даже классы. Модуль может наследовать от другого модуля, но он не мо-
жет наследовать от класса. Так как класс может включать модуль, он может
также включать модули, которые унаследовали другие модули.
В коде примера 9.12 демонстрируется, как создать модуль (Dice), а затем
включить его в класс (Game). Метод roll доступен из экземпляра класса Game,
который называется g. (Метод rand из модуля Kernel генерирует псевдослу-
чайное число — между 0.0 и 1.0, если параметра нет, или между 0
и argument. Метод roll использует rand с небольшим коленцем, обеспечи-
вающим уверенность, что тот не вернет 0. Надо отметить, это не самый эф-
фективный способ гарантировать ненулевой результат, но он работает.)
#!/usr/bin/env ruby
module Dice
178 Глава 9
end
class Game
include Dice
end
g = Game.new
g.roll
Если бы модуль был в отдельном файле (см. пример 9.13), аналогично слу-
чаю с классом, вам пришлось бы просто затребовать (require) файл, содер-
жащий модуль, чтобы он смог работать (и снова require ожидает, что имя
находится по пути загрузки).
module Dice
end
Классы 179
#!/usr/bin/env ruby
require 'dice'
class Game
include Dice
end
g = Game.new
g.roll
#!/usr/bin/env ruby
module Binary
end
class Names
def family
@family
end
@pet
end
end
При изменении доступа к методам, как в примере 9.16, вам придется опреде-
лить эти методы после применения методов public, private или protected.
Вы можете также вызвать методы после определения (для имени метода не-
обходимо использовать символ):
def pet
@pet
end
protected :pet
С Ruby не соскучишься
Если вам нужны восемь цифр, вы должны это указать, плюс дополнить ре-
зультат нулями:
sprintf("%08b", 14) # => "00001110"
Поле Описание
Поле Описание
p То же самое, что argument.inspect, где inspect предоставляет печа-
таемую версию параметра, с удаленными специальными символами
s Подставляет параметр как строку. Если форматирующая строка содержит
точность, то в подстановку копируется не менее указанного количества
символов
u Трактует параметр как десятичное число без знака. Отрицательные числа
для базовой архитектуры показываются как 32-битовое дополнение до
двух плюс единица (например, 2**32+n). Так как в Ruby нет собственного
лимита на количество битов, используемых для представления целого
числа, отрицательным значениям предшествуют две точки, обозначающие
бесконечное количество лидирующих знаковых битов
x Преобразует числовой параметр в шестнадцатеричное число со строчными
буквами от a до f. Отрицательные числа показываются с двумя предшест-
вующими точками, обозначающими бесконечную строку лидирующих ff
1$ дает методу понять, что вы хотите, чтобы он искал только первый пара-
метр.
Для числа с плавающей точкой используйте тип поля f. Приведенная далее
строка показывает сумму в долларах:
sprintf( "$%.2f", 100 ) # => "$100.00"
Это все равно, что применять метод % из класса String, который был показан
в главе 1.
"Hello, %s" % "Matz!" # => "Hello, Matz!"
Обработка 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, а затем записывает его на стан-
дартное устройство вывода.
#!/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
#!/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
given.add_attribute("nickname", "false")
given.text = "Mondo"
family.text = "Mangrove"
document.write( $stdout, 0 )
Builder
XML Builder Джима Вейриха (Jim Weirich) (http://rubyforge.org/projects/
builder) — еще одно средство создания XML. В настоящее время оно по-
ставляется в версии 2.0.0. Впервые оно привлекло мое внимание, когда я об-
наружил его упакованным в Rails. Лично я считаю, что пользоваться им про-
ще, чем REXML, и вы, возможно, тоже будете так думать.
Сравните пример 10.2 с примером 10.3, составленным в Builder.
#!/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
#!/usr/bin/env ruby
require 'rubygems'
require_gem 'builder'
include Builder
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: год, месяц, день, час, минуты,
секунды. Можно вызвать 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)
Сделайте запрос для объекта класса Time при помощи utc? (или gmt?), чтобы
определить, представляет ли он собой Coordinated Universal Time (UTC; уни-
версальное (глобальное) время по Гринвичу), также известное как Greenwich
Mean Time (GMT; Гринвичское время):
local_time.utc? # => false
Проверьте, равны ли два объекта Time, при помощи eql? или оператора <=>:
# создайте еще один новый объект temp класса Time
temp = stop # => Tue Jan 30 04:13:00 -0700 2007
stop.object_id # => 1667650
temp.object_id # => 1667650
Класс 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"
Как и в классе Time, можно сравнить два объекта класса Date на равенство
при помощи eql? или оператора <=>:
# создайте новый объект temp класса Date
temp = date
temp.object_id # => 2708130
date.object_id # => 2708130
Календарные формы
Григорианский календарь (с 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" )
Можно получить юлианский день (день с 1 января 4713 года до н. э., начиная
с 0) с помощью метода экземпляра класса jd:
date.jd # => 2454048
Можно даже на основе юлианского дня создать год при помощи метода клас-
са jd:
nd = Date.jd( 2454048 )
nd.to_s # => "2006-11-08"
Рефлексия
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"
Выяснить имена всех включенных модулей экземпляра класса или его класса
можно при помощи метода included_modules из Module.
asiponder.class.included_modules # => [Enumerable, Comparable, Kernel]
asiponder.class.superclass.included_modules # => [Kernel]
Эти объекты идентичны и имеют один и тот же ID, намек на то, что Ruby бе-
режно расходует ресурсы. (Метод id из Object был резко осужден; приме-
няйте вместо него object_id.)
Вы можете также удостовериться, является ли объект экземпляром данного
класса, с помощью метода instance_of? из Object:
asiponder.instance_of? String # => true
asiponder.instance_of? Fixnum # => false
Хотите узнать, какие константы есть в классе Object (или каком-нибудь другом
классе)? Примените метод constants из Module (выходные данные обрезаны):
irb(main):008:0> Object.constants.sort
# => ["ARGF", "ARGV", "ArgumentError", "Array", ... ]
Я добавил в конец метод sort (из Array), чтобы результат получился удобо-
читаемым.
Float
Integer
String
...
class A
attr_accessor :x
end
a = A.new
Применение 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.
#!/usr/bin/env ruby
require 'tk'
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
#!/usr/bin/env ruby
require 'tk'
require "tkextlib/tkimg/jpeg"
require "open-uri"
Рис. 10.2. Утренняя Заря, моя лошадь породы quarter horse, на закате
Метапрограммирование
Метапрограммирование — это условное обозначение способа написания
программы, или части программы, с помощью другой программы. В преды-
дущей главе вы познакомились с метапрограммированием на практике, когда
вызывали семейство методов attr (attr, attr_reader, attr_writer и
attr_accessor из класса Module), чтобы создать для классов геттеры и сетте-
ры. Теперь у вас есть шанс заняться метапрограммированием самому.
Ключ к решению проблем — метод define_method из класса Module, ко-
торый позволяет создавать методы на лету. Взгляните на программу в приме-
ре 10.7, которая создает метод, выбирая имена из элементов массива.
#!/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
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 --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
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
Кажется, его нет. Продолжим и установим его при помощи команд 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
Обработка исключений
Исключение возникает, когда программа "откалывает номер" и ее нормаль-
ное течение прерывается. Ruby подготовлен к решению таких проблем по-
средством собственных встроенных исключений, но вы можете управиться
с ними по-своему, с помощью обработки исключений.
Модель обработки исключений в Ruby подобна моделям в C++ и Java.
В табл. 10.3 показано сравнение ключевых слов или методов, используемых
для выполнения обработки исключений в этих трех языках. Если вы умуд-
ренный жизнью программист, эта таблица станет для вас пробным камнем.
begin
eval "12 / 0"
rescue ZeroDivisionError
puts "Oops. You tried to divide by zero again."
exit 1
ensure
puts "Tsk. Tsk."
end
Вот краткий анализ. Метод 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
#!/usr/bin/env ruby
def limit( n )
puts n
throw :done if n <= 0
limit( n-1 )
end
ЗАМЕЧАНИЕ
Если вы беженец из лагеря Java, то будете рады узнать, что RDoc
подобен Javadoc в Java (http://java.sun.com/j2se/javadoc).
Основы RDoc
Я представлю здесь основы RDoc, воспользовавшись файлом ratios.rb, в ко-
тором содержится класс Ratios. Методы этого класса вычисляют некоторые
финансовые коэффициенты.
Сначала я покажу файл по частям, а затем весь целиком. Я расскажу вам, как
размечать исходные файлы Ruby и как обрабатывать эти файлы, чтобы полу-
чить выходные данные XHTML или др. Конечно, я не охвачу всего, что мож-
но проделать с RDoc, а только некоторые из самых важных вещей.
Комментарий перед началом описания класса интерпретируются как общая
документация для класса и помещаются перед любой другой документацией.
В примере 10.10 показано начало ratios.rb.
class Ratios
# === 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
или выполнить:
$ rdoc --version
RDoc V1.0.1 - 20041108
С Ruby не соскучишься 223
или:
$ rdoc -v
RDoc V1.0.1 - 20041108
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
ratios.rb: c...
Generating RI...
Files: 1
Classes: 1
Modules: 0
Methods: 4
Elapsed: 0.342s
С Ruby не соскучишься 225
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, вы не
удалите исходные файлы, только сгенерированные. Не удаляйте ис-
ходные файлы!
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.
#!/usr/bin/env ruby
require 'erb'
person = "Matz!"
temp = ERB.new( "Hello, <%= person %>" )
puts temp.result( binding ) # => Hello, Matz!
Теги <%= и %> — только одна из возможных пар тегов. Все теги-шаблоны
ERB приведены в табл. 10.4.
Тег Описание
<% ... %> Код на Ruby; встраивается в выходные данные
<%= ... %> Выражение на Ruby; замещается результатом вычисления
<%# ... %> Комментарий; игнорируется; удобен при тестировании
% Строка кода на Ruby; обрабатывается как <% .. %>; устанав-
ливается с помощью параметра trim_mode в ERB.new
%% Замещается %, если стоит в начале строки и если используется
обработка %
<%% ... %%> Замещается <% и %>, соответственно
#!/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>
<h2>Foals</h2>
228 Глава 10
</body>
</html>
]
class Horse
def context
binding
end
end
output.run( horse.context )
Создается новый экземпляр класса ERB с именем output, а также новый эк-
земпляр класса Horse с соответствующими параметрами. Метод foal вызы-
вается несколько раз для добавления имен в конец массива @foals. Эти име-
на извлекаются при помощи метода each и блока. Обратите внимание на теги
<% и %>. В них содержится код Ruby, тогда как теги <%= и %> возвращают ре-
зультат вычисления выражения.
<h2>Foals</h2>
<ul><% @foals.each do |foals| %>
<li><%= foals %></li> <% end %>
</ul>
<h2>Foals</h2>
<ul>
<li>Dash</li>
<li>Pepper</li>
</ul>
</body>
</html>
Место, где вы, несомненно, встретите такие теги, это файлы с расширением
rhml, произведенные Ruby on Rails, предметом разговора в главе 11.
230 Глава 10
Почему 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
Не повторяйтесь
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),
ну и довольно об этом.
Скрипты
Скрипты в 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
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
Basecamp, 43things и Blinksale являются примерами того, на что похож Web 2.0:
ориентированная на пользователя, готовая к сотрудничеству, децентрализо-
ванная. Они прекрасно демонстрируют, на что способны настоящие, приме-
няющие интернет-технологии приложения. В ближайшие годы вы увидите,
как настольные прикладные системы переходят в сеть и как там появляются
новые неслыханные приложения. Изменятся модели, и я предпочел бы быть
в курсе происходящих изменений, а не быть застигнутым ими врасплох, а вы?
Если хотите взглянуть на длинный и все растущий список реальных приложений
Rails, отправляйтесь на http://wiki.rubyonrails.org/rails/pages/RealWorldUsage
или http://happycodr.com и следуйте по указанным ссылкам, сколько душе
угодно. Там масса многообещающих проектов.
Краткий курс по Ruby on Rails 241
Установка Rails
Перед установкой Rails необходимо установить Ruby версии 1.8.6 или выше
(1.8.4 или 1.8.5 тоже приемлемы, но 1.8.6 лучше). Вероятно, к этому моменту
Ruby у вас уже установлен. Если нет, то я просто раздавлен. Придется воз-
вращаться к главе 1. Пожалуйста, не говорите мне, что вам придется это
сделать!
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)
Изучаем 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
ЗАМЕЧАНИЕ
Весь изобразительный ряд выполнен в формате QuickTime Movie (mov)
для Apple.
Краткое руководство
Существуют и другие обучающие руководства по 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
create app/controllers
create app/helpers
create app/models
create app/views/layouts
create config/environments
create components
create db
create doc
create lib
...
ЗАМЕЧАНИЕ
Обратите внимание на Mongrel — если вы много работаете с Rails,
вам, вероятно, вскоре захочется воспользоваться им. Mongrel — не-
большой быстрый перспективный сервер HTTP, написанный по боль-
шей части на Ruby. Он может выполнять функции сетевой среды, такой
как Rails, непосредственно с HTTP, без использования FastCGI или
SCGI. Дополнительную информацию ищите на странице проекта
Mongrel http://rubyforge.org/projects/mongrel на RubyForge.
ЗАМЕЧАНИЕ
Символ & в конце команды переводит процесс в фоновый режим, по-
этому я могу продолжать использовать командную оболочку. Я пред-
почитаю так и делать. Но не обязываю вас. Между прочим, это не
будет работать в Windows, если только вы не установили что-то вроде
Cygwin (см. http://www.cygwin.com). Чтобы закрыть WEBrick, наберите
fg, затем нажмите комбинацию клавиш <Ctrl>+<C>.
| information_schema |
| addressbook_development |
| mysql |
| test |
+--------------------------+
4 rows in set (0.00 sec)
| 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
Справочник по Ruby
Интерпретатор Ruby
Синтаксис интерпретатора Ruby:
ruby [ключи] [--] [имя файла с программой] [параметры]
Зарезервирован- Описание
ное слово
BEGIN Код, заключенный в { и }, выполняется до выполнения про-
граммы
END Код, заключенный в { и }, выполняется, когда программа
заканчивается
alias Создает альтернативное имя (псевдоним) для существующе-
го метода, оператора или глобальной переменной
and Логический оператор; то же самое, что &&, только у and бо-
лее низкий приоритет (ср. с or)
Приложение 1. Справочник по Ruby 259
Зарезервирован- Описание
ное слово
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 Приложения
Зарезервирован- Описание
ное слово
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
Escape-символы
В табл. П1.3 перечислены все escape-символы языка Ruby.
262 Приложения
Предопределенные переменные
В табл. П1.4 перечислены все предопределенные переменные языка Ruby.
Предопределенная Описание
переменная
$! Сообщение об исключении, содержащее информацию о
последнем возникшем исключении. Эту переменную уста-
навливает raise. Доступна с помощью => в операторе
rescue
$@ Обратная трассировка стека для последнего исключения,
восстанавливается через Exception#backtrace
Приложение 1. Справочник по Ruby 263
Предопределенная Описание
переменная
$& Строка, соответствующая последнему успешному сравне-
нию с шаблоном в этой области видимости, или 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 Приложения
Предопределенная Описание
переменная
$\ Разделитель выводимой записи для печати и 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
Предопределенная Описание
переменная
$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.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 Приложения
Шаблон Описание
[..] Соответствует любому единичному символу в квадратных
скобках
[^..] Соответствует любому единичному символу не в квадратных
скобках
* Соответствует нулевому (или большему) количеству предыду-
щих регулярных выражений
*? Соответствует нулевому (или большему) количеству предыду-
щих регулярных выражений (не поглощающий)
+ Соответствует одному или нескольким предыдущим регуляр-
ным выражениям
+? Соответствует одному или нескольким предыдущим регуляр-
ным выражениям (не поглощающий)
{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
Шаблон Описание
(?-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
Директива Описание
Директива Описание
P Указатель на структуру (строка фиксированной длины)
p Указатель на строку, заканчивающуюся нулевым символом
Q, q 64-битовое число
S Короткое целое без знака
s Короткое целое
U UTF-8
u Строка в кодировке UU
V Длинное целое, прямой порядок байтов (сначала наименьшие зна-
чащие)
v Короткое целое, прямой порядок байтов (сначала наименьшие зна-
чащие)
w Сжатое по BER целое\fnm
X Резервное копирование байта
x Нулевой байт
Z То же самое, что a, но нулевой символ добавляется со *
Поле Описание
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
Поле Описание
u Трактует параметр как десятичное число без знака. Отрицательные
числа для базовой архитектуры показываются как 32-битовое дополне-
ние до двух плюс единица (например, 2**32+n). Так как в Ruby нет соб-
ственного лимита на количество битов, используемых для представле-
ния целого числа, отрицательным значениям предшествуют две точки,
обозначающие бесконечное количество лидирующих знаковых битов
x Преобразует числовой параметр в шестнадцатеричное число со строч-
ными буквами от a до f. Отрицательные числа показываются с двумя
предшествующими точками, обозначающими бесконечную строку лиди-
рующих ff
X То же самое, что x, но в результате используются заглавные буквы от A
до F. Отрицательные числа показываются с двумя предшествующими
точками, обозначающими бесконечную строку лидирующих FF
Файловые тесты
В табл. П1.11 и П1.12 перечислены файловые тесты из Kernel#test для од-
ного и двух файлов, соответственно.
Директива Описание
Опции RDoc
Опции RDoc применяются таким образом:
rdoc [опции] [имена...]
Rake
Этот встроенный инструмент, средство построения, поможет вам создать,
скомпилировать и иными способами обработать файлы, количество которых
в проекте иногда бывает весьма значительным. Rake — подобен make
(http://www.gnu.org/software/make) и Apache Ant (http://ant.apache.org),
Приложение 1. Справочник по Ruby 281
показать использование
--usage (-h)
Ответы на вопросы
для самопроверки
Глава 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 Приложения
Глава 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
Глава 7
1. В чем разница между хэшем и массивом?
Ответ: хэш — это неупорядоченная совокупность, с ключами и значе-
ниями. Массив — это упорядоченная совокупность, с индексом, начи-
нающимся с 0, и значениями, называемыми элементами.
2. Когда хэш более предпочтителен, чем массив?
Ответ: когда порядок не важен и когда имеется связь ключа со значением.
3. Как бы вы проверили, есть ли в хэше заданный ключ или заданное значе-
ние?
Ответ: has_key?, key?, has_value?, value?.
288 Приложения
Глава 8
1. Для чего пригодна константа ARGV?
Ответ: она представляет имена всех файлов, указанных в командной
строке.
2. Как бы вы с помощью Ruby получили тип файла для файла на диске?
Ответ: ftype.
3. Что маска 0700 делает с правами доступа к файлу?
Ответ: создает для владельца маску rwx.
4. Как бы вы получили доступ к дате и времени создания файла?
Ответ: ctime, mtime, atime.
5. Какой тип объекта возвращает метод entries класса Dir?
Ответ: массив.
Глава 9
1. Да или нет: вы не можете добавлять методы или переменные во встроен-
ные классы.
Ответ: нет.
2. Имени переменной экземпляра предшествует символ _________.
Ответ: символ коммерческое "at" (@).
3. Что является отличительной характеристикой метода класса?
Ответ: ему предшествует имя класса.
Приложение 2. Ответы на вопросы для самопроверки 289
Глава 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 Приложения
Глава 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 Глоссарий
е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.
proc
В языке Ruby это процедура, хранящаяся как объект, вместе с контекстом;
объект класса Proc. См. lambda.
protected (защищенный)
Метод, помеченный как protected, доступен или видим только внутри сво-
его собственного класса или порожденного класса. Ср. с private, public.
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.
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)
Метод доступа к данным в классе, обычно недоступном иным способом.
Также носит название "геттер" и "сеттер".
Библиотека (library)
См. стандартная библиотека.
Блок (block)
Безымянная функция, всегда связанная с вызовом метода и заключенная
в пару фигурных скобок ({}) или do/end.
296 Глоссарий
Выражение (expression)
Содержит ключевые слова, математические операторы, переменные и тому
подобное, и возвращает значение.
Диапазон (range)
В языке Ruby это способ представления включающих (..) и исключающих
(...) диапазонов объектов, обычно чисел. Например, 1..10 — это диапазон
Глоссарий 297
Замыкание (closure)
Безымянная функция или метод. Замыкание подобно методу в методе, кото-
рый обращается или совместно использует переменные в скобках или внеш-
ний метод. В языке Ruby замыкание, как и блок, заключено в фигурные скоб-
ки ({}) или скобки do/end, и его работа зависит от связанного с ним метода.
Индекс (index)
Целое число, начиная с 0, которое нумерует или идентифицирует элементы
массива. См. массив.
298 Глоссарий
Исключение (exception)
Позволяет в процессе программирования отловить и обработать ошибки пе-
риода исполнения программы, а также другие ошибки. Обработка ведется
с помощью rescue, ensure и raise. Ср. с ошибкой.
Класс (class)
Коллекция кодов, включающая методы и переменные, называемые членами
класса. Код в классе устанавливает правила для объектов данного класса.
См. экземпляр класса, модуль, объект.
Ключ (key)
Ключ связан со значением в хэше. Ключи можно использовать для доступа
к значениям в хэше. См. хэш.
Комментарий (comment)
Текст программы, пропускаемый интерпретатором с языка Ruby. Если ему
предшествует знак # и он не заключен в двойные кавычки, то он не учитывается
интерпретатором. Блок комментария, заключенный в скобки =begin/=code,
может содержать несколько строк текста. Он также называется вложенным
документом.
Конкатенация (concatenation)
Соединение или сцепление двух символьных строк, выполняемое в языке
Ruby с помощью методов +, << и concat.
Константа (constant)
В языке Ruby имя константы начинается с заглавной буквы или пишется за-
главными буквами. Константа не фиксируется, как в других языках. Впро-
чем, если поменять значение константы, интерпретатор Ruby предупредит,
что константа уже инициализирована.
Массив (array)
Структура данных, содержащая упорядоченный список элементов — любых
объектов языка Ruby, — начинающийся с индекса 0. Ср. с хэш.
Метапрограммирование (metaprogramming)
Программирование, которое создает и/или манипулирует другими програм-
мами. В языке Ruby одним из инструментов, находящихся на службе мета-
программирования, является метод define_method. Рефлексия — другое
свойство Ruby, играющее роль в метапрограммировании. См. рефлексия.
Метод (method)
Именованная совокупность операторов, с параметрами или без параметров,
и возвращаемое значение. Член класса. См. класс.
Метод-геттер (getter)
См. аксессор.
Метод-сеттер (setter)
См. аксессор.
Модуль (module)
Модуль подобен классу, но невозможно создать экземпляр модуля. Класс
может включать модуль, так что, когда создается экземпляр класса, он полу-
чает методы и все прочее из включенного модуля. Методы из включенного
модуля становятся экземплярами методов в классе, который включает мо-
дуль. Этот процесс называется смешиванием, а модуль именуется mixin.
См. класс, смешивание.
300 Глоссарий
Наследование (inheritance)
Способность класса наследовать свойства другого класса с помощью опера-
тора <. См. множественное наследование, единичное наследование.
Объект (object)
Экземпляр класса, вещь, сущность или концепт, расположенный в непрерыв-
ной области памяти компьютера. См. экземпляр класса, класс.
ООП (OOP)
См. объектно-ориентированное программирование.
Оператор (statement)
Инструкция программе для приведения в исполнение.
Операторы (operators)
Выполняют такие математические операции, как сложение и вычитание.
Операторы в языке Ruby включают, как и в других языках, + для сложения, -
для вычитания, * для умножения, / для деления, % для деления по модулю и
т. д. Многие операторы в языке Ruby являются методами.
Ошибка (error)
Трудность или дефект в коде, который обычно приводит к останову про-
граммы. В программах на языке Ruby распространенные ошибки отождеств-
ляются с такими классами, как ArgumentError, EOFError и ZeroDivisionError.
Ср. с исключением.
Глоссарий 301
Пакет (package)
См. RubyGems.
Параметр (argument)
Переменная, передаваемая методу. В вызове метода hello ( name ) пере-
менная name является параметром. См. метод.
Перегрузка (overloading)
Перегрузка метода или функции — обычная практика в объектно-
ориентированном программировании, она позволяет методам с одинаковыми
именами оперировать различного вида данными (методам или функциям
с одинаковыми именами, но разными отличительными признаками). В языке
Ruby, по правде говоря, нельзя перегрузить методы без ветвления логики
внутри метода. См. подмена.
Переменная (variable)
Имя, которому может быть присвоено количество или значение. См. перемен-
ная класса, глобальная переменная, переменная экземпляра, локальная пере-
менная.
Подмена (overriding)
Переопределение метода. Последнее определение — это то, которое опозна-
но интерпретатором Ruby. Ср. с перегрузкой.
Подстановка (substitution)
См. подстановка выражения.
Поток (thread)
В Ruby поддерживается поточная обработка. Она позволяет программам од-
новременно (или почти одновременно) выполнять многочисленные задания
при помощи расщепления времени на тактовом генераторе, синхронизирую-
щем деятельность процессора. В языке Ruby потоки не зависят от операци-
онной системы (ОС), поэтому поточная обработка возможна на всех плат-
формах, даже в тех ОС, где она не поддерживается.
Псевдоним (alias)
Посредством ключевого слова alias в языке Ruby можно дать другое имя
методу, оператору или глобальной константе, указав старое и новое имя.
Глоссарий 303
Псевдопеременная (pseudovariable)
Объект, который выглядит как переменная и ведет себя как константа, но
которому нельзя присвоить значение.
Путь (path)
Местонахождение файла в файловой системе. Используется для упрощения
локализации файлов для открытия, выполнения и тому подобных операций.
Содержится в переменной среды PATH.
Расширение, С (extension, C)
См. С-расширение.
Ресивер (receiver)
Объект, который получает или является контекстом для действия, выполняе-
мого методом. В вызове метода str.length, str — ресивер метода length.
304 Глоссарий
Рефлексия (reflection)
Способность языка, такого как Ruby, проверять себя и совершать над собой
манипуляции.
Смешивание (mixin)
Когда модуль включается в класс, он как бы смешивается с классом, отсюда
и его название mixin. Использование mixin помогает преодолеть проблемы,
возникающие из-за множественного наследования.
Совпадение (match)
При обнаружении заданного регулярного выражения метод сообщает, что
произошло совпадение. См. регулярное выражение.
Строка (string)
Последовательность объектов, обычно символов.
Суперкласс (superclass)
Родительский класс. Дочерний класс получается из родительского класса или
суперкласса. Ср. с дочерним классом.
Точность (precision)
Определяется точностью, с которой выражаются численные величины. В языке
Ruby модуль Precision позволяет преобразовывать числа (числа с плаваю-
щей точкой в целые, целые числа в числа с плавающей точкой).
Хэш (hash)
Неупорядоченная совокупность данных, в которой отображены ключи и зна-
чения. Ср. с массивом.
Цикл (loop)
Повторяющееся выполнение одного или нескольких операторов. В Ruby ис-
пользуются циклы for и даже есть метод loop для решения такой задачи.
306 Глоссарий
Член (member)
Переменные и методы считаются членами класса или объекта. См. класс, ме-
тод, объект, переменная.
Шаблон (pattern)
Последовательность ординарных и специальных символов, дающая возмож-
ность механизму регулярных выражений обнаружить строку. См. регулярное
выражение.
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 Предметный указатель
А В
Аналогия с ведром 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
О П