<b>Ruby.new</b>
Большинство книг по программированию одинаковы. Они начинаются главами посвященными базовым типам: числам, строкам и др. Затем рассматриваются выражения, далее управляющие структуры <code>if</code> и <code>while</code>. Затем, возможно в 7 или 8 главе, переходят к классам. Все это представляется весьма скучным.
Вместо этого, когда мы придумывали эту книгу, у нас были большие планы (тогда мы были моложе).
Мы собирались описать язык сверху в низ, начиная с классов и объектов и заканчивая утомительными деталями синтаксиса. Это казалось хорошей идеей в то время. В конце-концов, почти все в Ruby является объектом, и по этому имеет смысл рассказать вначале об объектах. Мы так думали.
К сожалению, оказалось сложно описывать язык таким методом. Если не описать строки, операторы, присвоения и другие детали, то становится сложно придумывать примеры классов. С использованием нашего описания сверху-вниз, мы одновременно рассматриваем и низкоуровневые детали которые нуждаются в описании и по этому примеры кода имеют смысл.
Итак, у нас появился новый грандиозный план (не зря нас называют прагматиками). Мы продолжим описывать Ruby сверху. Но перед этим необходимо добавить короткую главу в которой описываются все общие возможности языка на примерах вместе со специальным словарем Ruby, своего рода мини-тренировка для старта вашего погружения в книгу. И вашему вниманию представляется такая глава.
<b>Ruby это объектно-ориентированный язык программирования</b>
Давайте скажем это опять! Ruby это настоящий объектно-ориентированный язык. Все все чем вы манипулируете(управляете) это объект, и результат этих манипуляций также являются объекты. Но как-бы то ни-было, множество языков имеют всякие требования, и их пользователи имеют разное понятие что-такое объектно-ориентированный и используют разную терминологию. Итак, перед тем как тонуть глубоко в детали, давайте просто коротко посмотрим на правила и нотацию которые мы можем использовать.
Когда вы пишите объектно-ориентированные программы, вы обычно смотрите на ее концептуальную модель в реальном мире. Обычно проводя процесс моделирования вы открываете категории вещей нужных для представления в коде. В музыкальном автомате концепт "песня" может быть такой категорией. В Ruby, Вы определите класс для представления этих объектов. Класс это комбинация состояний (к примеру название песни) и методов которые используют это состояние(возможно метод для воспроизведения песни).
Как только у вас есть эти классы вы типично собираетесь создать некоторое количество экземпляров. Для системы музыкального автомата содержащей класс Song(Песня), у вас будут разные экземпляры для популярных хитов типа “Ruby Tuesday,” “Enveloped in Python,” “String of Pearls,” “Small Talk,” и так далее. Слово объект используется как синоним экземпляра класса ( но потому что нам лень печатать, мы скорее всего будем использовать слово объект чаще).
В Ruby эти объекты создаются вызовом конструктора-специального метода ассоциированного с классом. Стандартный конструктор new вызван сейчас.
<code>song1 = Song.new("Ruby Tuesday")</code>
<code>song2 = Song.new("Enveloped in Python")</code>
<code># and so on</code>
Эти экземпляры сделаны из одного класса но имеют уникальные характеристики. Во-первых каждый объект имеет уникальный объектный идентификатор(кратко ID). Во-вторых, вы можете определять переменные экземпляров, переменные со значениями уникальны для каждого экземпляра. эти переменные экземпляров содержат состояние объекта. Каждая из наших песен к примеру может содержать переменные экземпляра с названием песни.
Внутри каждого класса вы можете определить методы экземпляра. Каждый метод это часть функциональности которая может быть вызвана в контексте класса и (в зависимости от ограничений доступа) снаружи класса. Эти методы экземпляров в свою очередь имеют доступ к переменным экземпляра объекта и следовательно к состоянию объекта. Класс Song, к примеру, может определять метод экземпляра под названием "play". Если переменная my_way (мой_путь) ссылается на особый экземпляр Song то у вас будет возможность вызвать этот метод экземпляра play и воспроизвести особую песню.
Методы вызываются отправкой сообщения (команды) объекту. Сообщение содержит в себе имя метода вместе с любыми нужными параметрами для метода (Эта идея выражения вызовов метода в форме сообщения пришла из Smalltalk.). Когда объект получает сообщение то ищет в его собственном классе соответствующий метод. Если находит то этот метод выполняется. Ну а если метод не найден...мы вернемся к этому позже.
Такое функционирование методов и сообщений может выглядеть сложным, но на практике оно совсем естественное. Теперь взглянем на некоторые вызовы методов. В этом коде мы используем puts, стандартный метод Ruby который выводит аргументы в консоль, Добавляя новую пустую строку после каждого.
<code>puts "gin joint".length</code>
<code>puts "Rick".index("c")</code>
<code>puts 42.even?</code>
<code>puts sam.play(song)</code>
<i>выводит</i>
<code>9</code>
<code>2</code>
<code>true</code>
<code>duh dum, da dum de dum ...</code>
Каждая строчка показывает, что метод вызывается как аргумент для puts. Вещь перед точкой названа получателем и имя после точки это тот метод который вызывается. Первый пример запрашивает длину строки, а второй запрашивает другую строку найти индекс буквы "с". И третья строчка запрашивает число 42 если оно четное (знак вопроса это часть названия метода even?). Да, и наконец мы просим Сэма проиграть нам песню (при том что это имеющаяся переменная sam которая ссылается на соответствующий объект).
Здесь практически нет большой разницы между Ruby и большинством других языков. В Java например вы найдете абсолютное значение какого-то числа вызовом отдельной функции и передавая это число в метод. Это выглядит где-то так:
<code>num = Math.abs(num) // Java code</code>
В Ruby возможность определять абсолютные значения встроена в числа - они самостоятельно заботятся о деталях изнутри. Вам проще послать сообщение abs числовому объекту и заставить его работать:
<code>num = 1234</code>
<code># => 1234</code>
<code>positive = num.abs # => 1234</code>
Тоже самое примениме ко всем объектам Ruby. В C используется strlen(name), но в Ruby это name.length, и так далее. Это какраз та часть которую мы имели ввиду когда говорили что Ruby объектно-ориентированный язык.
<b>Некоторые начала Ruby</b>
Не много людей любит читать кучи надоедливых синтаксических правил когда они начинают изучать новый язык, так-что мы собираемся схитрить. В этой секции мы покажем самое важное - то что только вам необходимо если вы собираетесь писать программы на Ruby. И только в 22 главе, которая начинается на 325 странице мы перейдем к мелким деталям. Давайте начнем с простенькой программы на Ruby. Мы напишем метод который возвращает персональное радостное приветствие. И потом мы вызовем метод несколько раз:
<code>def say_goodnight(name)</code>
<code>result = "Good night, " + name</code>
<code>return result</code>
<code>end</code>
<code># Time for bed...</code>
<code>puts say_goodnight("JohnBoy")</code>
<code>puts say_goodnight("MaryEllen")</code>
Как показывают примеры, синтаксис Ruby чист. Вам не нужны точка с запятой в конце выражений пока вы пишете каждое выражение на новой строчке. Комментарии в Ruby начинаются с символа # и появляются в конце строчки. Разметка кода более проста для вас; отступы не имеют значения (но использование двух символьного отступа сделает вас друзьями в если вы планируете заняться дистрибуцией вашего кода).
Методы определяются ключевым словом def, за ним следует имя метода (здесь как say_goodnight) и параметры между круглыми скобками. (Факт тот что скобки не обязательны, но мы любим использовать их.) Ruby не использует фигурные скобки для ограничения тел составных выражений и определений. И так, вы просто заканчиваете тело с ключевым словом end. Метод нашего тела очень простой. Первая линия объединяет строку символов "Good night, " и имя параметра и присваивает результат результату переменной. Следующая линия возвращает результат вызывавшему. Кстати нам не нужно декларировать результат переменной, она начинает существовать когда мы назначаем ее.
Определив метод, мы вызываем его дважды. В обоих примерах, мы передавали результат в метод <i>puts</i>, который просто выводит аргумент следующий за новой строкой (переходя на следующую строку вывода):
<code>Good night, JohnBoy</code>
<code>Good night, MaryEllen</code>
Cтрока
<code>puts say_goodnight("JohnBoy")</code>
содержит вызов двух методов, один вызов метода say_goodnight и другой вызов метода puts. Почему в одном случае аргументы метода заключены в скобки, а в другом - нет? Это дело вкуса. Нижеследующие строки эквивалентны:
<code>puts say_goodnight("JohnBoy")</code>
<code>puts(say_goodnight("JohnBoy"))</code>
Однако , жизнь-это не всегда так просто, правила приоритета могут повлечь некоторые сложности с тем какой аргумент используется при вызове метода, так-что мы рекомендуем использовать скобки во всех простых случаях.
Этот пример так-же показывает некоторые строчные объекты Ruby.
В Ruby есть множество путей для создания строчных объектов, но возможно самым известным является использование строчных литералов, которые представляют последовательность символов между одинарными или двойными кавычками.Эти две формы различаются лишь объемом работы, который выполняет Ruby со строкой при создании литерала. Двойные кавычки используются в Ruby очень редко. За некоторым исключением, то что вы набираете в строчном литерале, становится строчным значением.
В случае с двойными кавычками, Ruby делает больше работы. Сначала интерпретатор ищет подстановки (последовательности, которые начинаются с символа "обратный слэш") и заменяет их некоторым двоичным значением. Чаще всего используется \n которая замещается символом перехода на новую строку. Когда строка выводится в консоли, \n становится концом строки.
<code> puts "And good night,\nGrandma"</code>
Выводит:
<code> And good night,
Grandma</code>
Второе, что Ruby делает со строками в двойных кавычках это интерполяция выражения. В строке, последовательность #{выражение} заменяется значением выражения. Мы могли бы использовать это, чтобы переписать предыдущий метод:
<code>def say_goodnight(name)</code>
<code>result = "Good night, #{name}"</code>
<code>return result</code>
<code>end</code>
<code>puts say_goodnight('Pa')</code>
Выводит:
<code>Good night, Pa</code>
Когда Ruby создает строковый объект, интерпретатор ищет текущее значение name и подставляет его в строку. Любое сложное выражение разрешается в конструкции #{...}. В следующем примере вызываем метод capitalize, определенный для всех строк, чтобы вывести наш параметр с заглавной буквы.
<code>def say_goodnight(name)</code>
<code>result = "Good night, #{name.capitalize}"</code>
<code>return result</code>
<code>end</code>
<code>puts say_goodnight('uncle')</code>
Выводит:
<code>Good night, Uncle</code>
Для большей информации о строках, а также о других стандартных типах Ruby, смотрите Главу 6, которая начинается на странице 106.
Наконец, мы могли бы упростить этот метод еще немного. Значение, возвращаемое методом Ruby является значением последнего вычисленного выражения, поэтому мы вообще можем избавиться от временной переменной и оператора return:
<code>def say_goodnight(name)</code>
<code>"Good night, #{name.capitalize}"</code>
<code>end</code>
<code>puts say_goodnight('ma')</code>
Выводит
<code>Good night, Ma</code>
Мы обещали, что этот раздел будет кратким. Мы должны рассмотреть еще одну тему: Ruby names. Для краткости, будем использовать некоторые термины (такие как "переменная класса"), которые здесь не будут объясняться. Однако, говоря о правилах сейчас, вы будете во всеоружии, когда мы позже действительно подойдем к обсуждению переменных класса и т.п.
Ruby использует соглашение, которое сначала может показаться странным: первый символ имени показывает как имя используется. Локальные переменные, параметры методов и имена методов должны начинаться с маленькой буквы или с подчеркивания. Глобальные переменные начинаются с префикса ($), а переменные экземпляра с символа @ ("at"). Переменные класса начинаются с @@. (И хотя мы говорим здесь о глобальных переменных и переменных класса для полноты описания, вы увидите, что они редко используются в программах Ruby. Существует много доказательств того, что глобальные переменные делают программы сложными для поддержки. Переменные класса не так опасны - но их стараются не использовать.).
Наконец, имена классов, имена модулей и константы должны начинаться с заглавной буквы. Примеры различных имен даны в Таблице 2.1 на следующей странице. После первого символа имя может быть комбинацией букв, цифр и подчеркиваний (при условии, что символ, следующий за @, не может быть цифрой). Однако, по соглашению, имена переменных экземпляра, состоящие из нескольких слов, пишутся с подчеркиванием между словами, а составные имена классов пишутся в MixedCase-стиле (каждое слово с заглавной буквы).
Имя метода может заканчиваться символами "?", "!" и "=" .
<b>Массивы и хеши</b>
Массивы и хэши Ruby являются индексированными коллекциями. Оба хранят коллекции объектов, доступных по ключу. В массивах ключ является целым числом, тогда как хэши поддерживают любой объект в качестве ключа. Оба растут при добавлении новых элементов. Более эффективен доступ к элементам массива, но хэши предоставляют большую гибкость. Как мы увидим через минуту, любой массив или хэш может содержать объекты разных типов; у вас может массив, содержащий целое число, строку и число с плавающей запятой.
Вы можете создать и инициализировать новый объект массива с помощью литерала масива - набор элементов, заключенных в квадратные скобки. Создав объект массива, вы можете получить доступ к отдельным элементам, подставляя индексы в квадратных скобках, как показывает следующий пример. Отметим, что индексы массива Ruby начинаются с нуля.
<code> a = [ 1, 'cat', 3.14 ] # array with three elements
puts "The first element is #{a[0]}"
# set the third element
a[2] = nil
puts "The array is now #{a.inspect}"</code>
выводит:
The first element is 1
The array is now [1, "cat", nil]
Возможно, вы заметили, что мы использовали специальное значение nil в этом примере. Во многих языках, концепция nil (или null) означает "нет объекта". В Ruby, это не так; nil является объектом, как и любой другой, который, оказываетя, представляет "ничто" ('nothing'). Так или иначе, давайте вернемся к массивам и хэшам.
Таблица 2.1. Примеры имен переменных и классов
<table border="0" cellpadding="0" cellspacing="0" width="600px">
<tbody><tr><td colspan="4" width="80%">Variables </td><td rowspan="2" width="20%">Constants and Class Names</td></tr><tr><td>Local </td><td>Global </td><td>Instance </td><td>Class </td></tr><tr><td>name </td><td>$debug</td><td>@name</td><td>@@total</td><td>PI</td></tr><tr><td>fish_and_chips</td><td>$CUSTOMER</td><td>@point_1</td><td>@@symtab</td><td>FeetPerMile</td></tr><tr><td>x_axis</td><td>$_</td><td>@X</td><td>@@N</td><td>String</td></tr><tr><td>thx1138</td><td>$plan9</td><td>@_</td><td>@@x_pos</td><td>MyClass</td></tr><tr><td>_26</td><td>$Global</td><td>@plan9</td><td>@@SINGLE</td><td>JazzSong</td></tr></tbody></table>
Синтаксис создания массивов со всеми кавычками и запятыми в некоторых случаях является слишком громоздким.
К счастью, в Ruby есть краткая форма: %w она делает то что нам надо:
<code> a = [ 'ant', 'bee', 'cat', 'dog', 'elk' ]
a[0] # => "ant"
a[3] # => "dog"
# this is the same:
a = %w{ ant bee cat dog elk }
a[0] # => "ant"
a[3] # => "dog"</code>
Хеши в Ruby сходны с массивами. Хеши используют литералы фигурных скобок а не квадратных скобок.
Литерал должен предоставить два объекта для каждого элемента: один для ключа, другой в качестве значения.
Ключ и значение, как правило, разделяются с помощью =>.
Например, вы можете отобразить музыкальные инструменты на их оркестровые разделы. Вы могли бы сделать это при помощи хеша:
<code> inst_section = {
'cello' => 'string',
'clarinet' => 'woodwind',
'drum' => 'percussion',
'oboe' => 'woodwind',
'trumpet' => 'brass',
'trumpet' => 'brass',
'violin' => 'string'
}</code>
То, что слева от =>, является ключем, а то, что справа - соответствующим значением. Ключи в хеше должны быть уникальны - вы не можете иметь два вхождения для "drum". Ключи и значения в хеше могут быть произвольными объектами - у вас могут хеши, в которых значениями являются массивы, другие хеши и т.д.
Хеши индексируются с использованием тех же квадратных скобок как и массивы. В этом коде мы будем использовать метод р для вывода значений в консоль. Этот метод работает также как и puts, но явно выводит значения такие как nil.
<code> p inst_section['oboe']
p inst_section['cello']
p inst_section['bassoon']</code>
Выводит
<code> "woodwind"
"string"
nil</code>
Как показано в предыдущем примере, хеш по умолчанию возвращает nil при попытке получить значение по ключу, которого в хеше нет. Обычно это удобно, потому что nil означает false, когда используется в условных выражениях. Иногда вы можете захотеть изменить это значение по умолчанию. Например, если вы используете хеш, чтобы подсчитать, сколько раз каждое слово встречается в файле, удобно иметь значение по умолчанию 0. Тогда вы можете использовать слово как ключ и просто увеличивать соответствующее хеш-значение не беспокоясь о том, видели ли вы это слово до этого. Это легко можно сделать определяя значение по умолчанию при создании нового, пустого хеша. (Полный листинг "счетчика" на странице 72.)
<code> histogram = Hash.new(0) # The default value is zero
histogram['ruby'] # => 0
histogram['ruby'] = histogram['ruby'] + 1
histogram['ruby'] # => 1</code>
У объектов массивов и хешей есть множество полезных методов; смотрите обсуждение на странице 67, и опорные секции начинающиеся на страницах 447 и 533 для деталей.
<b>Символы</b>
Часто при программировании необходимо придумывать название для чего-то важного. Например, вы захотели обратиться к точкам на компасе по имени, поэтому написали следующее:
<code> NORTH = 1
EAST = 2
SOUTH = 3
WEST = 4</code>
Теперь вы можете использовать в своей программе эти константы, а не числа:
<code> walk(NORTH)
look(EAST)</code>
Большую часть времени, текущие числовые значения этих констант не имеют значения(пока они уникальны). Все что вам нужно это различать эти четыре направления.
Ruby предлагает более чистую альтернативу. Идентификаторы являются просто именами констант, которые вы не должны объявлять заранее и которые гарантированно уникальны. Литерал идентификатора начинается с двоеточия и обычно сопровождается некоторым именем.
<code> walk(:north)
look(:east)</code>
Нет необходимости присваивать значение идентификатору - Ruby позаботится об этом. Ruby также гарантирует, что независимо от того, где идентификатор появляется в вашей программе, его значение будет тем же самым. Т.е., вы можете написать следующее:
<code> def walk(direction)
if direction == :north
# ...
end
end
</code>
Символы часто используются в качестве ключей в хешах. Мы могли бы написать в нашем предыдущем примере, вот так:
<code> inst_section = {
:cello => 'string',
:clarinet => 'woodwind',
:drum => 'percussion',
:oboe => 'woodwind',
:trumpet => 'brass',
:violin => 'string'
}
inst_section[:oboe] # => "woodwind"
inst_section[:cello] # => "string"
# Note that strings aren't the same as symbols...
inst_section['cello'] # => nil
</code>
Фактически, идентификаторы так часто использовались как хеш-ключи, что Ruby 1.9 вводит новый синтаксис - вы можете использовать пары "имя: значение" чтобы создать хеш 1.9, если ключи являются идентификаторами.
<code> inst_section = {
cello: 'string',
clarinet: 'woodwind',
drum: 'percussion',
oboe: 'woodwind',
trumpet: 'brass',
violin: 'string'
}
puts "An oboe is a #{inst_section[:oboe]}"</code>
Выводит:
An oboe is a woodwind
<b>Управляющие структуры</b>
В Ruby есть все обычные управляющие структуры, такие как операторы if и while. Java, C, Perl программисты могут отметить отсутствие фигурных скобок вокруг тел этих операторов. Вместо этого, Ruby использует ключевое слово end чтобы обозначить конец тела оператора:
<code> if count > 10
puts "Try again"
elsif tries == 3
puts "You lose"
else
puts "Enter a number"
end</code>
Таким же образом while оканчивается вместе с end:
<code> while weight < 100 and num_pallets <= 30
pallet = next_pallet()
weight += pallet.weight
num_pallets += 1
end</code>
Большинство выражений в Ruby возвращают значение, что обозначает возможность их использования в качестве условий.
К примеру метод gets возвращает следующую строку из стандартного входного потока или nil когда доходит до конца файла. Так как Ruby воспринимает nil как <i>ложное</i> значение в условиях, вы можете напечатать следующие для вывода строк в файл:
<code> while line = gets
puts line.downcase
end</code>
Здесь, оператор присвоения приравнивает переменную line либо к следующей строке текста либо к nil и потом выражение while проверяет присвоенное значение, а за тем прерывает цикл когда переменная становится равной нулю.
Модификаторы выражений в Ruby имеют краткую форму если тело выражения <i>if</i> или <i>while</i> являются отдельно стоящими. Запишите выражение начав его с if или while и условия.
На пример, так выглядит простое выражение if:
<code> if radiation > 3000
puts "Danger, Will Robinson"
end</code>
Тоже самое с использованием модификатора выражения:
<code> puts "Danger, Will Robinson" if radiation > 3000</code>
Аналогично цикл while:
<code> square = 2
while square < 1000
square = square*square
end</code>
становится более осмысленной версией:
<code> square = 2
square = square*square while square < 1000</code>
Такие модификаторы выражений покажутся знакомыми Perl програмистам.
<b>Регулярные выражения</b>
Большинство встроенных типов Ruby знакомы всем программистам. Большинство языков имеют string, integer, float, массивы и т.д. Однако, поддержка регулярных выражений обычно встроена только в скриптовые языки, такие как Ruby, Perl, awk. Это позор, потому что регулярные выражения, несмотря на загадочность, являются мощным инструментом для работы с текстом.
Большая разница в том, что поддержка регулярных выражений встроена, а не прикреплена через интерфейс библиотеки.
Целые книги были написаны о регулярных выражениях (к примеру Mastering Regular Expressions [Fri02]) поэтому мы не собираемся описывать все в этом коротком разделе. Тем не менее мы собираемся рассмотреть несколько примеров регулярных выражений в действии. Вы найдете полное описание регулярных выражений на странице 117.
Регулярные выражения это простой путь для определения шаблона символов для поиска. В Ruby вы как правило создаете регулярное выражение вписывая шаблон между слешами (/pattern/). И Ruby остается Ruby регулярные выражения являются объектами которыми можно манипулировать.
К примеру вы можете написать шаблон который сопоставляет строку содержащую текст Perl или Python используя данное регулярное выражение:
<code>/Perl|Python/</code>
Прямые слеши разграничивают шаблон который содержит две соответствующие вещи и разделяются вертикальной чертой (|). Эта символ черты обозначает либо вещь справа либо вещь с лева в этом случае Perl или Python. Вы можете использовать скобки в шаблонах, так-же как в арифметических выражениях так что вы можете написать этот шаблон так:
<code>/P(erl|ython)/</code>
Вы также можете указать повторение в шаблоне.Строке /ab+c/ соответствует строка содержащая a и однo или более b, а за тем c. Измените плюс на знак умножения и /ab*c/ создаст регулярное выражение которое сопоставляет, один а, ноль или более b, и одно с.
Вы можете еще сопоставить одну группу символов без шаблона. Несколько частых примеров символов классов типа \s, который обозначает символ пробела(space, tab, newline и подобное); \d который обозначает число и \w который выводит любой символ появляющийся в данном слове. dot ( . ) сопоставляется почти с каждым символом. Таблица с этими символами находится на странице 125.
Мы можем сложить это все чтобы получить полезные регулярные выражения:
<code> /\d\d:\d\d:\d\d/ # a time such as 12:34:56
/Perl.*Python/ # Perl, zero or more other chars, then Python
/Perl Python/ # Perl, a space, and Python
/Perl *Python/ # Perl, zero or more spaces, and Python
/Perl +Python/ # Perl, one or more spaces, and Python
/Perl\s+Python/ # Perl, whitespace characters, then Python
/Ruby (Perl|Python)/ # Ruby, a space, and either Perl or Python</code>
Однажды освоив шаблоны,будет стыдно их не использовать.Оператор отожествления =~ может быть использован для отожествления строки после регулярного выражения. Если шаблон найден в строке,=~ возвращает его начальную позицию противополюжно возвращает nil. Это значит чтовы вы можеты использовать регулярные выражения как условие для выражений while . К примеру следующий фрагмент кода выводит if стоку содержащую Perl or Python:
<code> if line =~ /Perl|Python/
puts "Scripting language mentioned: #{line}"
end</code>
Часть строки сопоставленная регулярным выражением может быть заменена другим текстом с использованием одного из методов подстановки в Ruby:
<code> line.sub(/Perl/, 'Ruby') # replace first 'Perl' with 'Ruby'
line.gsub(/Python/, 'Ruby') # replace every 'Python' with 'Ruby'</code>
Вы можете заменить каждое совпадение Perl и Python с помощью Ruby таким образом:
<code>line.gsub(/Perl|Python/, 'Ruby')</code>
Мы будем еще много говорить регулярных выражениях в этой книге.
<b>Блоки и итераторы</b>
Эта секция кратко описывает одну из сильных сторон Ruby. Мы имеем ввиду блоки кода: куски кода которые можно ассоциировать с вызовом метода точно также если бы они были параметрами. И это невероятно мощная возможность, которую один из наших читателей прокомментировал так: "Это очень интересно и важно так что если вы не уделяли этому ни какого внимания то вам луче начать сейчас". Мы должны с этим согласится.
Вы можете использовать блоки кода для создания callback'ов (но они проще чем безымянные встроенные классы Java) для передачи кусков кода (но они более гибкие чем указатели функций С ) и также для создания итераторов.
Блоки кода это просто куски кода между скобочками или do. . . end. Вот это блок кода:
<code> { puts "Hello" }</code>
А также:
<code> do
club.enroll(person)
person.socialize
end</code>
Почему здесь два вида разграничителей? Иногда кажется более естественным выбрать один способ а не другой. Также это может зависеть от предыдущих строк кода: скобки легче отслеживать чем пары do/end. В этой книге мы попытаемся следовать тому что становится стандартом Ruby и будем использовать скобки для одно строчных блоков и do/end для много строчных блоков.
Все что вы можете делать с блоком это ассоциировать его с вызовом метода. Вы делаете все это выводя начало блока в конец линии кода содержащей метод call.
К примеру в следующем коде блок содержащий puts "Hi" ассоциируемый с call для метода greet (который мы не показывали):
<code>greet { puts "Hi" }</code>
Если метод содержит параметры то они выводятся перед блоком:
<code>verbose_greet("Dave", "loyal customer") { puts "Hi" }</code>
Метод может вызвать блок один или более раз используя выражение Ruby <i>yield</i>. Вы можете думать о <i>yield</i> как о чем то типа метода call который вызывает блок ассоциированный с методом содержащим <i>yield</i>.
Следующий пример пример показывает все это в действии. Мы определяем метод который вызывает yield дважды. За тем мы вызываем этот метод выводя блок на ту же линию после call (и после любых параметров метода). Некоторые люди любят думать о ассоциации блока с методом как о виде передачи параметров. Это работает на одном уровне но это не вся история. Вам будет луче думать о блоках и методах как о сопрограммах которые передают контроль и вперед между друг другом.
def call_block
puts "Start of method"
yield
yield
puts "End of method"
end
call_block { puts "In the block" }
выдаёт:
Start of method
In the block
In the block
End of method
Код в блоке (puts "In the block") выполняется дважды, по разу для каждого вызова yield.
Вы можете предоставить аргументы для вызова yield и они будут переданы в блок. В блоке вы составляете списки параметров для распознания этих аргументов между вертикальными барами (| параметры... |). Следующий пример показывает как метод вызывает ассоциированный с ним блок дважды передавая в блок два аргумента каждый раз:
<code> def who_says_what
yield("Dave", "hello")
yield("Andy", "goodbye")
end
who_says_what {|person, phrase| puts "#{person} says #{phrase}"}</code>
выдаёт:
Dave says hello
Andy says goodbye
Блоки кода используются посредством библиотеки Ruby для внедрения итераторов, которые являются методами, возвращающими соответствующие элементы из некоего набора данных, например, массива:
animals = %w( ant bee cat dog elk ) # create an array
animals.each {|animal| puts animal } # iterate over the contents
выдаёт:
<code> ant
bee
cat
dog
elk</code>
Многие из циклических конструкций, встроенных в языки типа С и Java, в Ruby реализованы в виде обычных вызовов методов, которые применяют связанный блок ноль или более раз:
<code> [ 'cat', 'dog', 'horse' ].each {|name| print name, " " }
5.times { print "*" }
3.upto(6) {|i| print i }
('a'..'e').each {|char| print char }</code>
Выводит:
<font face="verdana">
<table><tbody><tr><td>cat</td><td>dog</td><td>horse</td><td> </td><td> </td></tr><tr><td>*</td><td>*</td><td>*</td><td>*</td><td>*</td></tr><tr><td>3</td><td>4</td><td>5</td><td>6</td><td> </td></tr><tr><td>a</td><td>b</td><td>c</td><td>d</td><td>e</td></tr></tbody></table></font>
Здесь мы вызываем блок для каждого элемента массива. Вот объект 5 вызывает блок 5 раз. Вместо использования циклов, в Ruby мы запрашиваем цифру 3 вызывать блок до тех пор, пока она не достигнет 6. И, наконец, для набора символов от а до е блок вызывается с использованием метода each.
<b>Чтение и Запись</b>
Ruby имеет полноценную библиотеку ввода-вывода. Однако, в большинстве примеров в этой книге, мы будем опираться на несколько простых методов. Мы уже применяли два метода, которые выводят информацию: puts пишет каждый аргумент с переводом строки после него; print также пишет аргументы, но без перевода строки. Оба могут писать в любой объект ввода-вывода, но по умолчанию пишут в стандартный вывод.
Другой метод, который мы часто используем это printf, который выводит переданные ему аргументы согласно строке формата (примерно как в С или Perl):
printf("Number: %5.2f,\nString: %s\n", 1.23, "hello")
выдаёт:
Number: 1.23,
String: hello
В данном примере строка формата "Number: %5.2f,\nString: %s\n" говорит printf представить число с плавающей точкой (минимум 5 символов, с двумя после запятой) и строку. Заметьте, что переводы строки (\n) вписаны в строку, после каждого аргумента строка переводится.
Вы можете считывать входящие данные в свою программу многими способами. Возможно самый традиционный - использовать подпрограмму gets, которая выдаёт данные из входящего потока вашей программы построчно:
line = gets
print line
Так как gets возвращает nil при достижении конца входящих данных, вы можете использовать его в циклах с условием. Учтите, что в While условие является присвоением: мы помещаем выходные данные Gets в переменную line, а потом, перед тем как продолжить, проверяем выходное значение на nil или false:
while line = gets
print line
end
<b>Параметры командной строки</b>
Когда вы запускаете программу на языке Ruby из командной строки, вы можете передать параметры. Это можно сделать двумя путями.
Во-первых, массив ARGV сдодержит все параметры, передаваемые запускаемой программе. Создайте файл cmd_line.rb со следующим содержимым:
puts "You gave #{ARGV.size} arguments"
p ARGV
Когда мы запустим этот файл с параметрами, мы сможем увидеть что они переданы:
$ ruby cmd_line.rb ant bee cat dog
выдаёт:
You gave 4 arguments
["ant", "bee", "cat", "dog"]
Часто параметрами программы являются имена файлов, которые вы хотите обработать. В этом случае можно использовать второй путь: переменную ARGF - специальный тип объекта ввода-вывода, который действует как содержимое всех перечисленных в командной строке файлов (или в стандартном вводе, если ничего не перечислено). Мы рассмотрим это дальше на стр. 342.
<b>Движемся дальше</b>
Вот и подошел к концу наш молниеносный тур по некоторым базовым возможностям Ruby. Мы рассмотрели объекты, методы, строки, контейнеры и регулярные выражения; некоторые простые управляющие структуры; некоторые довольно изящные итераторы. Надеемся, что этт раздел предоставил вам достаточно патронов, чтобы расправиться с оставшейся частью этой книги. Время двигаться вперед и вверх - к более высокому уровню. Далее мы рассмотрим классы и объекты - вещи, которые одновременно являются конструкциями высшего уровня в Ruby и существенными основами всего языка.
Внимание! Этот перевод, возможно, ещё не готов.
Его статус: перевод редактируется
Переведено на Нотабеноиде
http://notabenoid.org/book/10995/35302
Переводчики: Droidos, white_rabbit, aist, tartuff22