<?xml version="1.0" encoding="windows-1251"?>
<FictionBook xmlns="http://www.gribuser.ru/xml/fictionbook/2.0" xmlns:l="http://www.w3.org/1999/xlink">
 <description>
  <title-info>
   <genre>comp_programming</genre>
   <author>
    <first-name>Крис</first-name>
    <last-name>Пайн</last-name>
   </author>
   <book-title>Учись программировать (на Ruby)</book-title>
   <annotation>
    <p>Начинающим программистам рекомендуется книга Криса Пайна "Учись программировать". Перевел на русский язык Михаил Шохирев.</p>
    <p>Очень легко читается. Посвящена самым азам программирования на популярном языке Ruby (Руби).</p>
    <p>Книга переведена на двенадцать языков! Русский, японский, французский, боснийский, немецкий, корейский и т.д. На английском языке издавалась четыре раза.</p>
   </annotation>
   <coverpage>
    <image l:href="#cover.png"/></coverpage>
   <lang>ru</lang>
   <translator>
    <first-name>Михаил</first-name>
    <last-name>Шокирев</last-name>
   </translator>
  </title-info>
  <document-info>
   <author>
    <nickname>navd</nickname>
   </author>
   <program-used>FictionBook Editor Release 2.6.6</program-used>
   <date value="2014-09-28">2014-09-28</date>
   <id>781C199F-186C-40CA-8199-D474C1F25491</id>
   <version>1.0</version>
   <history>
    <p>PDF to FB2</p>
   </history>
  </document-info>
  <publish-info>
   <book-name>Крис Пайн «Учись программировать»</book-name>
   <year>2007</year>
   <isbn>978-1-93435-636-4</isbn>
  </publish-info>
 </description>
 <body>
  <title>
   <p>Крис Пайн</p>
   <p>«Учись программировать»</p>
  </title>
  <section>
   <empty-line/>
   <image l:href="#img_01.png"/>
   <empty-line/>
   <image l:href="#img_02.png"/>
   <empty-line/>
   <p><strong>Улучшенная и РАСШИРЕННАЯ версия</strong></p>
   <p>Оригинальный учебник</p>
   <empty-line/>
   <image l:href="#img_03.png"/>
   <empty-line/>
  </section>
  <section>
   <title>
    <p>Отправная точка для будущего программиста</p>
   </title>
   <p>Полагаю, что всё это началось ещё в 2002 году. Я думал о преподавании программирования и о том, каким превосходным языком для обучения программированию стал бы Ruby. В том смысле, что мы все были в восхищении от Ruby, потому что это мощный, элегантный и действительно просто интересный язык. И мне подумалось, что было бы здорово начать знакомство с программированием именно с него.</p>
   <p>К сожалению, в то время было немного документации по Ruby, предназначенной для новичков. Некоторые из нашего сообщества говорили о том, что очень пригодился бы учебник наподобие «Ruby для новичка», или в более широком смысле – для обучения программированию вообще. Чем больше я думал обо всём этом, тем больше накапливалось того, что мне нужно было высказать (и это меня несколько удивило). Наконец, кто-то сказал: «Крис, почему бы тебе тогда просто не написать учебник вместо того, чтобы всё время говорить о нём?» Так я и сделал.</p>
   <p>Но получалось не слишком хорошо. У меня была масса идей, которые были хороши в теории, но в реальной задаче написать классный учебник для не-программистов таился гораздо больший вызов, чем я мог осознать. (Я имею в виду, что он казался хорошим для меня, но я-то уже знал, как программировать.)</p>
   <p>Спасло меня вот что: я устроил так, что людям было действительно легко связаться со мной, и я всегда старался помочь людям, когда они на чём-нибудь застревали. Когда я видел, что многие застревали на одном и том же месте, я переписывал его. Работы было много, но учебник потихоньку становился всё лучше и лучше.</p>
   <p>Спустя пару лет, он был уже весьма хорош. :-) В самом деле, настолько хорош, что я был готов сказать, что он закончен, и двигаться дальше к чему-то ещё. И как раз примерно тогда появилась возможность превратить этот учебник в книгу. Поскольку он был в основном почти готов, я посчитал, что трудностей не возникнет. Я только подчищу в нём некоторые места, добавлю несколько упражнений, ну, возможно, ещё несколько упражнений, и ещё несколько глав, и дам его на просмотр ещё 50-ти рецензентам…</p>
   <p>Это заняло у меня ещё один год, но теперь я думаю, что он действительно в самом деле хорош, в основном благодаря сотням храбрецов, что помогли мне написать его.</p>
   <p>То, что размещено на этом &lt;a href="http://pine.fm/LearnToProgram/"&gt; сайте, – это исходный вариант учебника, почти совсем не изменённый с 2004 года. Чтобы получить самую свежую и улучшенную версию, вам, возможно, захочется обратиться вот к &lt;a href="http://pragmaticprogrammer.com/titles/fr_ltp"&gt; этой книге.</p>
  </section>
  <section>
   <title>
    <p>Соображения для преподавателей</p>
   </title>
   <p>Было несколько руководящих принципов, которых я старался придерживаться. Я думаю, они делают процесс обучения гораздо более лёгким – ведь учиться программировать и так довольно тяжело. Если вы преподаёте или наставляете кого-то на путь благородного хакерства, то эти идеи могут помочь и вам.</p>
   <p>Во-первых, я старался как можно больше разделять понятия так, чтобы учащемуся требовалось изучать каждый раз только одно понятие. Это было трудно сначала, но уж слишком легко после того, как я приобрёл некоторый опыт. Некоторые вещи должны изучаться прежде других, но я был поражён, насколько мало в действительности имеется таких иерархических зависимостей. В конечном счёте, я просто выбирал порядок изложения и старался скомпоновать материал таким образом, чтобы каждый новый раздел основывался на предыдущих.</p>
   <p>Другой принцип, о котором я всё время помнил, – учить только одному способу делать что-либо. В этом очевидное преимущество учебника для тех, кто никогда не программировал ранее. С одной стороны, один способ делать что-то легче выучить, чем два. Хотя, возможно, более важная выгода от этого состоит в том, что, чем меньшему числу приёмов вы учите начинающего программиста, тем более изобретательным и сообразительным ему придётся быть в своих программах. Поскольку основная деятельность в программировании связана с решением задач, критически важным становится поощрять это насколько возможно на каждом этапе разработки.</p>
   <p>Я постарался переводить понятия программирования на те понятия, которые уже есть у начинающего программиста, с целью представить идеи таким образом, чтобы нагрузка ложилась более на его интуицию, нежели на учебник. Объектноориентированное программирование подходит для этого весьма хорошо. Мне можно было достаточно рано начать ссылаться в учебнике на «объекты» и различные «типы объектов», невинно роняя такого рода фразы в подходящие моменты. Я не говорил что-либо подобное «всё в Ruby является объектами,» или «числа и строки – это разновидности объектов», поскольку эти утверждения в действительности ничего не значат для начинающего программиста. Вместо этого я предпочёл говорить о строках (а не о «строковых объектах»), но иногда я упоминал «объекты», имея в виду просто «вот эти вещи в этих программах». А то, что все эти вещи в Ruby фактически являются объектами, позволило этим уловкам с моей стороны хорошо сработать.</p>
   <p>Хотя я желал избежать ненужного объектно-ориентированного жаргона, я хотел быть уверенным, что если им в самом деле нужно было узнать какой-то термин, они выучат правильное слово. (Я не хотел, чтобы им пришлось учить его дважды, верно?) Вот почему я применял слово «строки», а не «текст». Методы тоже нужно было как-нибудь назвать, и я называл их «методы».</p>
   <p>Что касается упражнений, думаю, что я приготовил несколько удачных, но их никогда не бывает слишком много. Если честно, могу поспорить, что я половину времени провёл, просто пытаясь подобрать забавные и интересные упражнения. Скучные упражнения напрочь убивают всякое желание программировать, в то время как от безупречно подходящих упражнений появляется профессиональный зуд, перед которым начинающий программист вряд ли сможет устоять. Короче говоря, невозможно потратить слишком много времени на подготовку хороших упражнений.</p>
   <p>Страницы этого учебника (и даже эта самая страница) сгенерированы &lt;a href="/home/mike/Desktop/Learn/Ruby/ltp/ltp-ru/ShowTutorialCode.rb"&gt; большой &lt;a href="/home/mike/Desktop/Learn/Ruby/ltp/ltp-ru/ShowTutorialCode.rb"&gt; программой – конечно, написанной на Ruby. :-) И поэтому, в оригинальном учебнике есть несколько тонкостей. Например, все примеры программного кода в действительности исполняются каждый раз, когда вы просматриваете страницу, и показанный результат – это результат, сгенерированный при выполнении. Думаю, это лучший, самый лёгкий и, конечно, самый крутой способ удостовериться, что весь представленный мной код отрабатывает в точности так, как я утверждаю. Вам не нужно беспокоиться о том, что я мог ошибочно скопировать выдачу какого-нибудь из примеров или забыл протестировать какую-то часть кода: он весь проверяется каждый раз, когда вы его просматриваете. Так, в разделе по генераторам случайных чисел, если вы перезагрузите страницу, то увидите, что числа каждый раз будут изменяться… Прекрасно. (Я применил похожий трюк для примеров кода, когда писал книгу, но очевидно, это наиболее заметно именно в этом учебнике.)</p>
  </section>
  <section>
   <title>
    <p>Благодарности</p>
   </title>
   <p>И наконец, мне бы хотелось поблагодарить всех в списке рассылки&lt;a href="mailto:ruby-talk@ruby-lang.org"&gt; ruby–talk за их мысли и ободрение; всех моих замечательных рецензентов за их помощь сделать эту книгу гораздо лучше, чем я сделал бы это один; в особенности – мою дорогую жену за то, что она была моим главным рецензентом / тестером / подопытным кроликом / музой; Мацумото – за создание этого сказочного языка программирования; издательство Pragmatic Programmers – за то, что сообщили мне об этом и, конечно, за публикацию моей книги!</p>
   <p>Если вы заметили какие-то ошибки или опечатки, или у вас есть замечания, предложения или хорошие упражнения, которые можно добавить, пожалуйста, &lt;a href="mailto:chris@pine.fm"&gt; сообщите мне.</p>
   <p>[А если у вас появятся замечания или уточнения по поводу перевода на русский язык, можете написать &lt;a href="mailto:mikhail@shokhirev.com"&gt; переводчику. – <emphasis>Прим. перев.</emphasis>]</p>
  </section>
  <section>
   <title>
    <p>0. Начинаем</p>
   </title>
   <p>Когда вы пишете программу для компьютера, вы должны «говорить» на языке, который ваш компьютер понимает: на языке программирования. Есть много, очень много разных языков, и многие из них – превосходные. В этом учебнике я выбрал для использования мой любимый язык программирования – Ruby.</p>
   <p>Помимо того, что Ruby – мой любимый язык, это также самый лёгкий язык программирования из всех, с которыми я знаком (а знаком я весьма со многими). На самом деле, это и есть настоящая причина, по которой я пишу этот учебник: не то чтобы я решил писать учебник и остановился на Ruby как на своём любимом языке; наоборот, я нахожу Ruby настолько лёгким, что решил: обязательно должен быть хороший учебник для начинающих и непременно с его использованием. Именно простота Ruby побудила меня написать этот учебник, а вовсе не то, что это – мой любимый язык. (Чтобы написать подобный учебник на примере другого языка, такого как C++ или Java, потребовались бы сотни и сотни страниц.) Но не думайте, что Ruby – это язык для начинающих, раз он очень лёгкий! Это мощный язык программирования такого профессионального уровня, который вряд ли существовал ранее.</p>
   <p>Когда вы что-нибудь пишете на естественном языке, написанное называется текстом. Когда вы пишете что-нибудь на компьютерном языке, написанное называется кодом. Я включил множество примеров кода на языке Ruby на протяжении учебника, большинство из них – это законченные программы, которые вы можете выполнять на своём компьютере. Чтобы легче было читать код, я окрасил части кода в различные цвета. (Например, числа всегда зелёные.) Всё, что предполагается вводить в программу, заключается в белую рамку, а всё, что выводит программа, помещается в голубую рамку.</p>
   <p>Если вам встретится что-либо, что вы не понимаете, или у вас возникнет вопрос, на который вы не находите ответа, запишите его и продолжайте читать! Вполне возможно, что ответ найдется в одной из следующих глав. Однако, если ваш вопрос останется без ответа до последней главы, я скажу вам, куда можно отправиться, чтобы задать его. Есть множество чудесных людей, которые с желанием помогут вам; нужно только знать, где их найти.</p>
   <p>Но сначала вам нужно загрузить и установить Ruby на ваш компьютер.</p>
   <empty-line/>
   <p><strong>Установка под Windows</strong></p>
   <p>Установить Ruby под Windows легче лёгкого. Сначала вам нужно загрузить &lt;a href="http://rubyinstaller.rubyforge.org/"&gt; установщик Ruby. Обычно имеется пара версий на выбор; в этом учебнике используется версия 1.8.4, так что удостоверьтесь, что вы загрузили версию как минимум не старее этой. (Я бы просто взял самую свежую версию из имеющихся.) Затем просто запустите программу-установщик. Он запросит у вас, куда вы хотите установить Ruby. Если у вас нет серьёзных причин для обратного, я бы посоветовал установить его в каталог по умолчанию.</p>
   <p>Чтобы программировать, вам нужно иметь возможность писать программы и выполнять программы. Для этого вам понадобится текстовый редактор и командная строка.</p>
   <p>Установщик Ruby поставляется с прекрасным текстовым редактором под названием SciTE (Scintilla Text Editor). Вы можете запустить SciTE, выбрав его из меню «Пуск». Если вы хотели бы расцветить код, как в примерах этого учебника, загрузите эти файлы и поместите их в каталог редактора SciTE (c:/ruby/scite, если вы выбрали каталог по умолчанию):</p>
   <p>• &lt;a href="http://pine.fm/LearnToProgram/SciTEGlobal.properties"&gt; Глобальные настройки</p>
   <p>• &lt;a href="http://pine.fm/LearnToProgram/ruby.properties"&gt; Настройки для Ruby</p>
   <p>Неплохой идеей будет создать где-нибудь каталог, чтобы хранить там все ваши программы. Убедитесь, что, когда вы сохраняете программу, вы сохраняете её именно в этот каталог.</p>
   <p>Чтобы вам добраться до командной строки, выберите «Командная строка» из подменю «Стандартные» в меню «Пуск». Вам захочется переходить в каталог, где вы храните ваши программы. Команда cd.. переместит вас в каталог уровнем выше, а по команде cd foldername вы окажетесь в каталоге под названием foldername. Чтобы увидеть все подкаталоги в текущем каталоге, введите команду dir/ad.</p>
   <p>Вот и всё! Вы готовы, чтобы учиться программировать.</p>
   <p><strong>Установка под Macintosh</strong></p>
   <p>Если у вас стоит <code>Mac OS X 10.2 (Jaguar)</code>, значит Ruby уже установлен в вашей системе! Что может быть проще? К сожалению, я не думаю, что вы сможете использовать Ruby под <code>Mac OS X 10.1</code> или более ранней версией.</p>
   <p>Чтобы программировать, вам нужно иметь возможность писать программы и выполнять программы. Для этого вам понадобится текстовый редактор и командная строка.</p>
   <p>Командная строка доступна посредством терминального приложения («<code>Terminal application</code>«), которое находится в разделе меню «Приложения / Утилиты» («<code>Applications / Utilities</code>«).</p>
   <p>В качестве текстового редактора вы можете использовать тот, что вам более знаком или более удобен. Однако, если вы используете TextEdit, убедитесь, что вы сохраняете ваши программы в виде обычного текста! Иначе ваши программы не будут работать. Другими альтернативами для составления программ могут быть редакторы emacs, vi или pico: все они доступны из командной строки.</p>
   <p><strong>Установка под Linux</strong></p>
   <p>Во-первых, вы захотите убедиться, не был ли Ruby уже установлен у вас. Наберите на консоли команду <code>which ruby</code>. Если она выведет что-нибудь наподобие <code>/usr/bin/which: no ruby in (…)</code>, значит вам нужно будет загрузить Ruby. Иначе посмотрите, какая версия Ruby установлена, набрав <code>ruby -v</code>. Если версия старее, чем последняя стабильная сборка с упомянутой выше страницы загрузки, то вам, возможно, захочется обновить её.</p>
   <p>Если вы работаете как пользователь root, тогда вам, наверное, не нужны будут дальнейшие указания по установке Ruby. Если это не так, вам нужно будет попросить вашего системного администратора установить его для вас. (При этом способе установки все пользователи в этой системе смогут пользоваться Ruby.)</p>
   <p>Или же вы можете просто установить его так, чтобы только вы могли использовать его. Переместите файл, который вы загрузили, во временный каталог, например, в <code>$HOME/tmp</code>. Если файл называется <code>ruby-1.6.7.tar.gz</code>, вы сможете открыть его командой tar zxvf ruby-1.6.7.tar.gz. Перейдите в каталог, который только что был вами создан (в нашем примере — в каталог <code>cd ruby-1.6.7)</code>. Сконфигурируйте вашу установку, набрав команду <code>./configure --prefix=$HOME)</code>. Затем наберите на консоли команду make, которая соберёт ваш интерпретатор Ruby. Это может занять несколько минут. После того, как всё будет выполнено, напечатайте <code>make install</code>, чтобы установить его. Потом вы пожелаете добавить каталог <code>$HOME/bin</code> в список путей для поиска команд, отредактировав ваш файл $HOME/.bashrc с настройками командного интерпретатора. (Вам нужно будет выйти из системы и зайти снова, чтобы изменения вступили в силу.) После того, как вы сделали это, проверьте успешность установки командой <code>ruby -v</code>. Если она сообщит, какая версия Ruby у вас установлена, тогда вы можете удалить файлы в каталоге <code>$HOME/tmp</code> (или там, куда вы их разместили).</p>
   <p>Вот и всё! Вы готовы, чтобы учиться программировать.</p>
   <p>Во-первых, вы захотите убедиться, не был ли Ruby уже установлен у вас. Наберите на консоли команду <code>which ruby</code>. Если она выведет что-нибудь наподобие <code>/usr/bin/which: no ruby in (…)</code>, значит вам нужно будет &lt;a href="http://www.ruby-lang.org/en/20020102.html"&gt; загрузить Ruby. Иначе посмотрите, какая версия Ruby установлена, набрав <code>ruby -v</code>. Если версия старее, чем последняя стабильная сборка с упомянутой выше страницы загрузки, то вам, возможно, захочется обновить её.</p>
   <p>Если вы работаете как пользователь root, тогда вам, наверное, не нужны будут дальнейшие указания по установке Ruby. Если это не так, вам нужно будет попросить вашего системного администратора установить его для вас. (При этом способе установки все пользователи в этой системе смогут пользоваться Ruby.)</p>
   <p>Или же вы можете просто установить его так, чтобы только вы могли использовать его. Переместите файл, который вы загрузили, во временный каталог, например, в <code>$HOME/tmp</code>. Если файл называется <code>ruby–i.6.7.tar.gz</code>, вы сможете открыть его командой <code>tar zxvf ruby–i.6.7.tar.gz</code>. Перейдите в каталог, который только что был вами создан (в нашем примере – в каталог <code>cd ruby–1.6.7</code>).</p>
   <p>Сконфигурируйте вашу установку, набрав команду <code>./configure --prefix=$HOME)</code>. Затем наберите на консоли команду make, которая соберёт ваш интерпретатор Ruby. Это может занять несколько минут. После того, как всё будет выполнено, напечатайте <code>make install</code>, чтобы установить его.</p>
   <p>Потом вы пожелаете добавить каталог <code>$HOME/bin</code> в список путей для поиска команд, отредактировав ваш файл <code>$HOME/.bashrc</code> с настройками командного интерпретатора. (Вам нужно будет выйти из системы и зайти снова, чтобы изменения вступили в силу.) После того, как вы сделали это, проверьте успешность установки командой <code>ruby –v</code>. Если она сообщит, какая версия Ruby у вас установлена, тогда вы можете удалить файлы в каталоге <code>$HOME/tmp</code> (или там, куда вы их разместили).</p>
   <p>Вот и всё! Вы готовы, чтобы учиться программировать.</p>
  </section>
  <section>
   <title>
    <p>1. Числа</p>
   </title>
   <p>А сейчас, когда вы всё установили, давайте напишем программу! Откройте ваш любимый текстовый редактор и наберите на клавиатуре следующее:</p>
   <p><code>puts 1+2</code></p>
   <p>Сохраните вашу программу (да, это программа!) под именем calc.rb (.rb – это то, что мы обычно пишем в конце имени программы, написанной на Ruby). А теперь выполните вашу программу, набрав <code>ruby calc.rb</code> в командной строке. Она должна вывести на экране число 3. Видите, программировать не так уж трудно, не правда ли?</p>
   <p><strong>Знакомство с puts</strong></p>
   <p>Так что же происходит в этой программе? Я уверен, что вы смогли догадаться, что делает 1+2, и наша программа, в принципе, такая же, как эта:</p>
   <empty-line/>
   <p><code>puts 3</code></p>
   <p>слово puts просто выводит на экран всё, что следует за ним.</p>
   <p><strong>Целые и плавающие</strong></p>
   <p>В большинстве языков программирования (и Ruby не является исключением) числа без десятичной точки называются целыми, а числа с десятичной точкой обычно называются числами с плавающей точкой или проще – плавающими. [По сути, это дробные десятичные числа, представленные в компьютере в двоичном виде. – <emphasis>Прим. перев.</emphasis>]</p>
   <p>Вот несколько целых чисел:</p>
   <p><code>5</code></p>
   <p><code>–205</code></p>
   <p><code>99 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 0</code></p>
   <p><code>0</code></p>
   <p>А вот несколько чисел с плавающей точкой:</p>
   <p><code>54.321 0.001 –205. 3884</code></p>
   <p><code>0.0</code></p>
   <p>На практике в большинстве программ плавающие числа не используются, только целые. (В конце концов, никто не хочет прочитать 7.4 сообщений электронной почты, просмотреть 1.8 web–страниц или послушать 5.24 любимых песен…) Числа с плавающей точкой больше используются для научных целей (физических экспериментов и тому подобное) и для ЗЭ-графики. Даже большинство программ для денежных расчётов применяют целые числа: в них просто учитываются суммы в копейках! [в оригинале: «в пенсах»– <emphasis>Прим. перев.</emphasis>]</p>
   <p><strong>Простая арифметика</strong></p>
   <p>К этому моменту у нас есть всё необходимое, чтобы сделать простой калькулятор. (В калькуляторах всегда используются плавающие числа, поэтому если вы хотите, чтобы ваш компьютер просто работал как калькулятор, вы также должны использовать числа с плавающей точкой.) Для сложения и вычитания мы используем + и -, что мы уже видели в программе. Для умножения мы используем *, а для деления мы используем /. На большинстве клавиатур эти клавиши располагаются среди цифровых клавиш в правой её части. Если у вас уменьшенная клавиатура или ноутбук, то вы можете просто нажать клавиши Shift и 8 или / (та же клавиша, что и клавиша ?). Давайте попробуем немного расширить нашу программу calc.rb. Наберите на клавиатуре, а затем выполните следующее:</p>
   <p><code>puts 1.0 + 2.0</code></p>
   <p><code>puts 2.0 * 3.0</code></p>
   <p><code>puts 5.0 – 8.0</code></p>
   <p><code>puts 9.0 / 2.0</code></p>
   <p>Вот что возвращает эта программа:</p>
   <p><code>3.0</code></p>
   <p><code>6.0  –3.0 4.5</code></p>
   <p>(Пробелы в программе не важны; они просто делают код легче для чтения.) Что ж, в том, что мы увидели, нет ничего удивительного. А теперь давайте испробуем на целых числах:</p>
   <p><code>puts 1+2 puts 2*3 puts 5–8 puts 9/2</code></p>
   <p>В основном, то же самое, правда?</p>
   <p><code>3</code></p>
   <p><code>6</code></p>
   <p><code>–3</code></p>
   <p><code>4</code></p>
   <p>Хм… кроме последнего! Но когда вы выполняете арифметические действия с целыми числами, вы получаете целочисленные ответы. Когда ваш компьютер не может получить «правильный» ответ, он всегда округляет его. (Конечно, 4 и есть правильный ответ в целочисленной арифметике для выражения 9/2; хотя, возможно, это не тот ответ, который вы ожидали.)</p>
   <p>Возможно, вы недоумеваете, зачем может понадобиться целочисленное деление. Ну, скажем, вы собираетесь в кино, но у вас только 9 долларов. У нас в Портленде вы можете посмотреть фильм в кинотеатре «Багдад» за 2 бакса. Сколько фильмов вы сможете посмотреть там? 9/2… 4 фильма. 4.5 – это в данном случае, конечно, неправильный ответ; вам не позволят посмотреть полфильма и не позволят половине вас посмотреть целый фильм… Некоторые вещи нельзя разделить.</p>
   <p>А теперь поэкспериментируйте сами с несколькими программами! Если вы хотите применить более сложные выражения, можете использовать скобки. Например:</p>
   <p><code>puts 5 * (12–8) + -15</code></p>
   <p><code>puts 98 + (59872 / (13*8)) * -52</code></p>
   <p><code>5</code></p>
   <p><code>–29802</code></p>
   <p><strong>Попробуйте ещё кое-что</strong></p>
   <p>Напишите программу, которая сообщит вам:</p>
   <p>• сколько часов в году?</p>
   <p>• сколько минут в десятилетии?</p>
   <p>• ваш возраст в секундах?</p>
   <p>• сколько шоколадок вы надеетесь съесть за свою жизнь?</p>
   <empty-line/>
   <p>Предупреждение: Вычисления в этой части программы могут потребовать очень много времени!</p>
   <empty-line/>
   <p>• А вот задание потруднее: Если я прожил 943 миллиона секунд, то каков мой возраст?</p>
   <p>Когда вы закончите развлекаться с числами, давайте взглянем на буквы.</p>
  </section>
  <section>
   <title>
    <p>2. Буквы</p>
   </title>
   <p>Итак, мы узнали всё о числах, а как же насчёт букв? слов? текста?</p>
   <p>Группы букв в программе мы называем строками. (Вы можете считать, что напечатанные буквы нанизаны друг за другом на бечёвку, как флажки.) Чтобы было легче увидеть, какие части кода – строки, я буду выделять их красным цветом. Вот несколько строк:</p>
   <empty-line/>
   <p><code>'Привет.'</code></p>
   <p><code>'Ruby – потрясающий.'</code></p>
   <p><code>'5 – это моё любимое число..</code></p>
   <p><code>а какое ваше?'</code></p>
   <p><code>'Снупи восклицает: «#%^?&amp;*@!' ', когда он запинается.'</code></p>
   <p><code>'            '</code></p>
   <p><code>' '</code></p>
   <p>Как видите, строки могут содержать знаки пунктуации, цифры, символы и пробелы… не только одни буквы. А в последней строке совсем ничего нет; такую строку называют пустой строкой.</p>
   <p>Мы использовали команду puts, чтобы напечатать числа; давайте опробуем её с несколькими строками:</p>
   <p><code>puts 'Привет, мир!' puts ''</code></p>
   <p><code>puts 'До свидания.'</code></p>
   <empty-line/>
   <p><code>Привет, мир!</code></p>
   <p><code>До свидания.</code></p>
   <empty-line/>
   <p>Всё отлично отработало. А теперь попробуйте вывести несколько своих строк.</p>
   <p><strong>Строковая арифметика</strong></p>
   <p>Точно так же, как вы выполняли арифметические действия с числами, вы можете выполнять арифметические действия со строками! Ну, почти так же… Во всяком случае, вы можете складывать строки. Давайте попробуем сложить две строки и посмотреть, что нам покажет puts.</p>
   <p><code>puts 'Я люблю' + 'яблочный пирог.'</code></p>
   <empty-line/>
   <p><code>Я люблюяблочный пирог.</code></p>
   <empty-line/>
   <p>Опаньки! Я забыл поместить пробел между 'Я люблю' и 'яблочный пирог.'. Пробелы обычно не имеют значения, но они имеют значение внутри строк. (Правду говорят: «компьютеры делают не то, что вы хотите, чтобы они делали, а только то, что вы велите им делать».) Давайте попробуем снова:</p>
   <empty-line/>
   <p><code>puts</code></p>
   <p><code>' Я</code></p>
   <p><code>люблю</code></p>
   <p><code>' + 'яблочный</code></p>
   <p><code>пирог.'</code></p>
   <p><code>puts</code></p>
   <p><code>' Я</code></p>
   <p><code>люблю'</code></p>
   <p><code>+ ' яблочный</code></p>
   <p><code>пирог.'</code></p>
   <empty-line/>
   <p><code>Я люблю яблочный пирог.</code></p>
   <p><code>Я люблю яблочный пирог.</code></p>
   <empty-line/>
   <p>(Как видите, неважно, к какой из строк добавлять пробел.)</p>
   <empty-line/>
   <p>Итак, вы можете складывать строки, но вы также можете умножать их! (На число, во всяком случае.) Посмотрите:</p>
   <p><code>puts 'миг ' * 4</code></p>
   <p><code>мигаю глазами</code></p>
   <p>(Шучу, конечно… на самом деле, она выводит вот что:)</p>
   <p><code>миг миг миг миг</code></p>
   <p>Если подумать, это имеет безупречный смысл. В конце концов, 7*3 действительно означает 7+7+7, поэтому 'му'*3 означает в точности 'му' + 'му' + 'му'.</p>
   <p><code>11 или ' 12 '</code></p>
   <p>Прежде, чем мы двинемся дальше, мы должны убедиться, что понимаем различие между числами и цифрами. 12 это число, а '12' это – строка из двух цифр.</p>
   <empty-line/>
   <p>Давайте немного поиграем с этим:</p>
   <empty-line/>
   <p><code>puts</code></p>
   <p><code>12</code></p>
   <p><code>+</code></p>
   <p><code>12</code></p>
   <empty-line/>
   <p><code>puts</code></p>
   <p><code>' 12 '</code></p>
   <p><code>+</code></p>
   <p><code>' 12 '</code></p>
   <p><code>puts</code></p>
   <p><code>' 12</code></p>
   <p><code>+</code></p>
   <p><code>12 '</code></p>
   <empty-line/>
   <p><code>24 1212 12 + 12</code></p>
   <p><code>А как насчёт этого:</code></p>
   <empty-line/>
   <p><code>puts 2 * 5 puts '2' * 5</code></p>
   <p><code>10 22222</code></p>
   <p><code>2 * 5</code></p>
   <p>Эти примеры были довольно простыми. Однако, если вы не будете очень осторожными, смешивая в своей программе строки и числа, у вас могут возникнуть…</p>
   <p><strong>Сложности</strong></p>
   <p>К этому моменту вы может быть попробовали некоторые вещи, которые не желают работать. Если ещё нет, то вот несколько из них:</p>
   <p><code>puts '12' + 12 puts '2' * '5'</code></p>
   <empty-line/>
   <p><code>#&lt;TypeError: can't convert Fixnum into String&gt;</code></p>
   <p>[#&lt;Ошибка типа: невозможно преобразовать Целое к Строке&gt; – <emphasis>Прим. перев.</emphasis>]</p>
   <empty-line/>
   <p>Мммдааа… сообщение об ошибке. Дело в том, что вы действительно не можете прибавить число к строке или умножить строку на другую строку. В этом не больше смысла, чем вот в таких выражениях:</p>
   <p><code>puts 'Бетти' + 12 puts 'Фред' * 'Джон'</code></p>
   <p>Вот ещё чего следует остерегаться: вы можете написать в программе ' поросёнок '*5, поскольку это просто обозначает 5 экземпляров строки ' поросёнок', соединённых вместе. Однако, вы не можете написать 5*'поросёнок', поскольку это обозначает 'поросёнок' экземпляров числа 5, что просто-напросто глупо.</p>
   <p>И, наконец: а что, если я хочу, чтобы программа напечатала 'Ты шикарная!'? Можно попробовать так:</p>
   <p><code>puts ''Ты шикарная!''</code></p>
   <p>Ну так вот, это не будет работать; я даже не буду пробовать выполнить это. Компьютер подумал, что мы закончили строку. [После второго апострофа. – <emphasis>Прим. перев.</emphasis>] (Вот почему хорошо иметь текстовый редактор, который расцвечивает синтаксис для вас.) Так как же дать понять компьютеру, что мы желаем остаться внутри строки? Нам нужно экранировать символ апострофа вот так:</p>
   <p><code>puts '\'Ты шикарная!\''</code></p>
   <empty-line/>
   <p>'Ты шикарная! '</p>
   <p>Обратная косая черта – это символ экранирования (escape character). Другими словами, если в строке стоит обратная черта и другой символ [которые образуют так называемую 'escape-последовательность». – <emphasis>Прим. перев.</emphasis>], то они оба иногда трансформируются в один новый символ. Но две вещи, которые обратная черта всё- таки экранирует, это апостроф и сама обратная черта. (Если хорошенько подумать, то символы экранирования должны всегда экранировать себя.) Ещё несколько примеров, я думаю, будут здесь к месту:</p>
   <empty-line/>
   <p><code>puts</code></p>
   <p><code>'\'Ты шикарная!\''</code></p>
   <empty-line/>
   <p><code>puts</code></p>
   <p><code>'обратная черта в конце строки:</code></p>
   <p><code>\\ '</code></p>
   <empty-line/>
   <p><code>puts</code></p>
   <p><code>'вверх\\вниз'</code></p>
   <empty-line/>
   <p><code>puts</code></p>
   <p><code>'вверх\вниз'</code></p>
   <empty-line/>
   <p><code>'Ты шикарная!'</code></p>
   <p><code>обратная черта в конце строки:</code></p>
   <p><code>\</code></p>
   <p><code>вверх\вниз</code></p>
   <p><code>вверх\вниз</code></p>
   <empty-line/>
   <p>Поскольку обратная черта не экранирует 'в', но экранирует себя, две последних строки идентичны. Они не выглядят одинаковыми в коде программы, но в вашем компьютере они действительно одинаковы.</p>
   <p>Если у вас есть другие вопросы, просто продолжайте читать дальше! В конце концов, я не могу отвечать на каждый вопрос на <emphasis>этой</emphasis> странице.</p>
  </section>
  <section>
   <title>
    <p>3. Переменные и присваивание</p>
   </title>
   <p>До сих пор, каждый раз, когда мы выводили с помощью puts строку или число, всё, что мы выводили, исчезало. Я имею в виду, если мы хотели напечатать что-то дважды, мы должны были вводить это дважды с клавиатуры:</p>
   <empty-line/>
   <p><code>puts '</code></p>
   <p><code>..ты</code></p>
   <p><code>можешь</code></p>
   <p><code>сказать</code></p>
   <p><code>это</code></p>
   <p><code>снова…'</code></p>
   <empty-line/>
   <p><code>puts '</code></p>
   <p><code>..ты</code></p>
   <p><code>можешь</code></p>
   <p><code>сказать</code></p>
   <p><code>это</code></p>
   <p><code>снова…'</code></p>
   <empty-line/>
   <p><code>…ты</code></p>
   <p><code>можешь</code></p>
   <p><code>сказать</code></p>
   <p><code>это</code></p>
   <p><code>снова…</code></p>
   <empty-line/>
   <p><code>…ты</code></p>
   <p><code>можешь</code></p>
   <p><code>сказать</code></p>
   <p><code>это</code></p>
   <p><code>снова…</code></p>
   <empty-line/>
   <p>Вот было бы прекрасно, если бы мы могли просто ввести что-то один раз и потом обращаться к нему… сохранить его где-нибудь. Ну, конечно же, мы можем это сделать, иначе я бы не заговорил об этом!</p>
   <p>Чтобы сохранить строку в памяти вашего компьютера, нам нужно дать строке какое-то имя. Программисты часто говорят об этом процессе как о присваивании, а имена они называют переменными. Имя переменной – это просто любая последовательность латинских букв и цифр, но первый символ должен быть буквой в нижнем регистре. Давайте снова испробуем нашу последнюю программу, но на этот раз я дам строке имя myString (хотя я с таким же успехом мог назвать её str или myOwnLittleString или henryTheEighth).</p>
   <empty-line/>
   <p><code>myString = '…ты можешь сказать это снова…' puts myString</code></p>
   <empty-line/>
   <p><code>puts myString</code></p>
   <p><code>…ты</code></p>
   <p><code>можешь</code></p>
   <p><code>сказать</code></p>
   <p><code>это</code></p>
   <p><code>снова…</code></p>
   <empty-line/>
   <p><code>…ты</code></p>
   <p><code>можешь</code></p>
   <p><code>сказать</code></p>
   <p><code>это</code></p>
   <p><code>снова…</code></p>
   <empty-line/>
   <p>Каждый раз, когда вы пытаетесь что-нибудь сделать с myString, программа вместо этого делает это со строкой '…ты можешь сказать это снова…'. Вы можете думать о переменной myString как об «указателе на» строку '…ты можешь сказать это снова…'. А вот немного более интересный пример:</p>
   <empty-line/>
   <p><code>name = 'Патриция Розанна Джессика Милдред Оппенгеймер'</code></p>
   <p><code>puts 'Меня зовут ' + name + '.'</code></p>
   <p><code>puts 'Ого! ' + name + ' – это правда длинное имя!'</code></p>
   <empty-line/>
   <p><code>Меня зовут Патриция Розанна Джессика Милдред Оппенгеймер.</code></p>
   <p><code>Ого! Патриция Розанна Джессика Милдред Оппенгеймер – это правда длинное имя!</code></p>
   <empty-line/>
   <p>Кроме того: так же просто, как мы можем присвоить объект переменной, мы можем переприсвоить другой объект этой же переменной. (Вот почему мы называем их переменными: потому что то, на что они указывают, может изменяться.)</p>
   <empty-line/>
   <p><code>composer = 'Моцарт'</code></p>
   <p><code>puts composer + ' был «сенсацией» в своё время.' composer = 'Бетховен'</code></p>
   <empty-line/>
   <p><code>puts 'Но мне лично больше нравится ' + composer + '.'</code></p>
   <p><code>Моцарт был «сенсацией» в своё время.</code></p>
   <empty-line/>
   <p>Но мне лично больше нравится Бетховен. Конечно, переменные могут указывать на объект любого типа, а не только на строки:</p>
   <empty-line/>
   <p><code>var = 'ещё одна</code></p>
   <p><code>+ 'строка'</code></p>
   <p><code>puts var</code></p>
   <p><code>var = 5 * (1+2)</code></p>
   <p><code>puts var</code></p>
   <p>ещё одна строка 15 Фактически переменные могут указывать почти на всё… кроме других переменных. А что же произойдёт, если мы попробуем?</p>
   <empty-line/>
   <p><code>var1</code></p>
   <p><code>= 8</code></p>
   <p><code>var2</code></p>
   <p><code>= vari</code></p>
   <p><code>puts</code></p>
   <p><code>vari</code></p>
   <p><code>puts</code></p>
   <p><code>var2</code></p>
   <p><code>puts</code></p>
   <p><code>' '</code></p>
   <p><code>var1</code></p>
   <p><code>= 'восемь'</code></p>
   <p><code>puts</code></p>
   <p><code>vari</code></p>
   <p><code>puts</code></p>
   <p><code>var2</code></p>
   <empty-line/>
   <p><code>8</code></p>
   <p><code>8</code></p>
   <p><code>восемь</code></p>
   <p><code>8</code></p>
   <empty-line/>
   <p>Сначала, когда мы попытались сделать, чтобы переменная var2 указывала на vari, она в действительности стала вместо этого указывать на 8 (на то же число, на которое указывала переменная vari). Затем мы сделали так, чтобы vari стала указывать на 'восемь', но поскольку var2 никогда не указывала на vari, она продолжает указывать на 8.</p>
   <empty-line/>
   <p>Ну а теперь, когда у нас есть переменные, числа и строки, давайте научимся, собирать их все вместе!</p>
  </section>
  <section>
   <title>
    <p>4. Собираем всё вместе</p>
   </title>
   <p>Мы рассмотрели несколько различных видов объектов (числа и буквы), мы создавали переменные, указывающие на них; а следующее, что мы хотим сделать – заставить их всех дружно работать вместе.</p>
   <p>Мы уже знаем, что если мы хотим, чтобы программа напечатала 25, то следующий код не будет работать, поскольку нельзя складывать числа и строки:</p>
   <empty-line/>
   <p><code>var1 = 2</code></p>
   <p><code>var2 = '5'</code></p>
   <p><code>puts var1 + var2</code></p>
   <empty-line/>
   <p>Частично трудность заключается в том, что ваш компьютер не знает, пытаетесь ли вы получить 7 (2 + 5), или вы хотите получить 25 ('2' + '5').</p>
   <empty-line/>
   <p>Прежде чем мы сможем сложить их вместе, нам нужно каким-то образом получить строковую версию значения var1 или целочисленную версию значения var2.</p>
   <empty-line/>
   <p><strong>Преобразования</strong></p>
   <empty-line/>
   <p>Чтобы получить строковую версию объекта, мы просто записываем после него.to_s:</p>
   <empty-line/>
   <p><code>var1 = 2 var2 = '5'</code></p>
   <p><code>puts var1.to_s + var2</code></p>
   <p><code>25</code></p>
   <empty-line/>
   <p>Подобным же образом to_i возвращает целочисленную версию значения объекта, а</p>
   <empty-line/>
   <p><code>to_ f возвращает плавающую версию. Давайте взглянем на то, что эти три метода</code></p>
   <empty-line/>
   <p>делают (и что не делают) чуть более пристально:</p>
   <empty-line/>
   <p><code>var1 = 2 var2 = '5'</code></p>
   <p><code>puts var1.to_s + var2 puts var1 + var2.to_i</code></p>
   <p><code>25</code></p>
   <p><code>7</code></p>
   <empty-line/>
   <p>Обратите внимание, что даже после того, как мы получили строковую версию var1,</p>
   <p>вызвав to_s, переменная vari продолжает постоянно указывать на 2, и никогда – на '2'. До тех пор, пока мы явно не переприсвоим значение vari (что требует применение знака =), она будет указывать на 2 до конца работы программы.</p>
   <p>А теперь давайте испробуем несколько более интересных (и несколько просто-таки странных) преобразований:</p>
   <empty-line/>
   <p><code>puts '15'.to_f</code></p>
   <p><code>puts '99.999'.to_f</code></p>
   <p><code>puts '99.999'.to_i</code></p>
   <p><code>puts ''</code></p>
   <p><code>puts '5 – это моё любимое число!'.to_i</code></p>
   <p><code>puts 'Кто вас спрашивал о 5 или о чём-нибудь подобном?'.to_i</code></p>
   <p><code>puts 'Ваша мамочка.'.to_f</code></p>
   <p><code>puts ' '</code></p>
   <p><code>puts 'строковое'.to_s puts 3.to_i</code></p>
   <empty-line/>
   <p>Итак, это, возможно, вызвало у вас некоторое удивление. Первый пример весьма обычен и даёт в результате 15.0. После этого мы преобразовали строку ' 99.999' в число с плавающей точкой и в целое. Плавающее получилось таким, как мы и ожидали; целое было, как всегда, округлено.</p>
   <p>Далее, у нас было несколько примеров, когда несколько … необычных строк преобразовывались в числа. Ьо^ игнорирует всё, начиная с первой конструкции, которая не распознана как число, и далее до конца строки. Таким образом, первая строка была преобразована в 5, а остальные, поскольку они начинались с букв, были полностью проигнорированы, так что компьютер вывел только ноль.</p>
   <empty-line/>
   <p>Наконец, мы увидели, что последние два наших преобразования не изменили ровным счётом ничего – в точности, как мы и предполагали.</p>
   <subtitle>Другой взгляд на puts</subtitle>
   <p>Есть что-то странное в нашем любимом методе… Посмотрите-ка вот на это:</p>
   <empty-line/>
   <p><code>puts 20 puts 20.to_s puts '20'</code></p>
   <empty-line/>
   <p><code>20</code></p>
   <p><code>20</code></p>
   <p><code>20</code></p>
   <empty-line/>
   <p>Почему эти три вызова puts выводят одно и то же? Ну, положим, последние два так и должны выводить, поскольку 20.to_s и есть '20'. А как насчёт первого, с целым числом 20? Собственно говоря, что же это значит: написать целое число 20? Когда вы пишете 2, а затем 0 на листе бумаги, вы записываете строку, а не целое. Число 20 – это количество пальцев у меня на руках и ногах; это не 2 с последующим 0.</p>
   <empty-line/>
   <p>Что ж, у нашего знакомого, puts, есть большой секрет: прежде, чем метод puts пытается вывести объект, он использует to_s, чтобы получить строковую версию этого объекта. Фактически, s в слове puts обозначает string; puts на самом деле значит put string [«вывести строку» – <emphasis>Прим. перев.</emphasis>].</p>
   <p>Сейчас это может показаться не слишком впечатляющим, но в Ruby есть много, много разнообразных объектов (вы даже научитесь создавать собственные объекты!), и было бы неплохо узнать, что произойдёт, если вы попытаетесь вывести с помощью puts действительно причудливый объект, например, фотографию вашей бабушки, музыкальный файл или что-нибудь ещё. Но об этом позже…</p>
   <empty-line/>
   <p>А тем временем, у нас есть для вас ещё несколько методов, и они позволят нам писать разнообразные забавные программы…</p>
   <empty-line/>
   <p><strong>Методы gets и chomp</strong></p>
   <empty-line/>
   <p>Если puts обозначает put string, уверен, что вы догадаетесь, что обозначает gets. И так же, как puts всегда «выплёвывает» строки, gets считывает только строки. А откуда он берёт их?</p>
   <p>От вас! Ну, по крайней мере, с вашей клавиатуры. Так как ваша клавиатура может производить только строки, всё это прекрасно работает. В действительности происходит вот что: gets просто сидит себе и считывает всё, что вы вводите, пока вы не нажмёте Enter. Давайте попробуем:</p>
   <empty-line/>
   <p><code>puts gets</code></p>
   <p><code>Здесь есть эхо?</code></p>
   <p><code>Здесь есть эхо?</code></p>
   <p>Конечно же, что бы вы ни вводили с клавиатуры, будет просто выведено вам обратно. Выполните пример несколько раз и попробуйте вводить разные строки.</p>
   <empty-line/>
   <p>Теперь мы можем делать интерактивные программы! Например, эта, когда вы введёте своё имя, поприветствует вас:</p>
   <empty-line/>
   <p><code>puts 'Приветик, ну и как Вас зовут?'</code></p>
   <p><code>name = gets</code></p>
   <p><code>puts 'Вас зовут ' + name + '? Какое прекрасное имя!'</code></p>
   <p><code>puts 'Рад познакомиться с Вами, ' + name + '. :)'</code></p>
   <p><code>Ммм-да! Я только что выполнил её – я ввёл своё имя, и вот что получилось:</code></p>
   <p><code>Приветик, ну и как Вас зовут?</code></p>
   <p><code>[Chris]</code></p>
   <p><code>Вас зовут Chris</code></p>
   <p><code>? Какое прекрасное имя!</code></p>
   <p>Рад познакомиться с Вами, Chris</p>
   <p><code>. : )</code></p>
   <p>Хммм… похоже, когда я ввел буквы «К», «р», «и», «с» и затем нажал на Enter, gets воспринял все буквы моего имени и символ Enter! К счастью, имеется метод как раз для подобных случаев: chomp. Он убирает все символы Enter, которые «болтаются» в конце вашей строки. Давайте снова проверим эту программу, но на сей раз призовём на помощь chomp:</p>
   <p><code>puts 'Приветик, ну и как Вас зовут?' name = gets.chomp</code></p>
   <p><code>puts 'Вас зовут ' + name + '? Какое прекрасное имя!' puts 'Рад познакомиться с Вами, ' + name + '. :)'</code></p>
   <p>Приветик, ну и как Вас зовут?</p>
   <p><code>Chris</code></p>
   <p>Вас зовут Chris? Какое прекрасное имя!</p>
   <p>Рад познакомиться с Вами, Chris. :)</p>
   <p>Гораздо лучше! Обратите внимание, что поскольку name указывает на gets.chomp, нам не требуется писать name. chomp; значение name уже было chomp–нуто.</p>
   <p>• Напишите программу, которая спрашивает у человека имя, затем отчество, затем фамилию. В результате она должна поприветствовать человека, называя его полным именем.</p>
   <p>• Напишите программу, которая спрашивает у человека его любимое число. Пусть ваша программа прибавит единицу к этому числу, а затем предложит результат в качестве большего и лучшего любимого числа. (Однако будьте при этом тактичными.)</p>
   <p>После того, как вы закончите эти две программы (и любые другие, которые вы пожелаете попробовать), давайте изучим ещё несколько методов (и узнаем о них ещё что-нибудь).</p>
  </section>
  <section>
   <title>
    <p>5. Ещё немного о методах</p>
   </title>
   <p>Пока что мы видели несколько различных методов: puts и gets и так далее (Быстрый тест: <emphasis>Перечислите все методы, которые мы узнали до сих пор! Их десять; ответ приводится ниже.</emphasis>), но мы совсем не говорили о том, что из себя представляют методы. Мы знаем, что они делают, но мы не знаем, «что они такое».</p>
   <p>И вот что они есть на самом деле: нечто, которое выполняет что-либо. Если объекты (такие как строки, целые и плавающие числа) являются существительными в языке Ruby, то методы подобны глаголам. И совсем также, как в английском [и в русском – <emphasis>Прим. перев.</emphasis>] языке, вы не используете глагол без существительного, чтобы выполнить действие, обозначаемое глаголом. Например, тиканье не совершается само по себе; настенные часы (или наручные или что-нибудь ещё) должны производить его. На естественном языке мы бы сказали: «Часы тикают.» На Ruby мы бы сказали clock.tick (естественно, предполагая, что clock – это объект Ruby). Программисты могли бы сказать, что мы «вызвали метод tick объекта clock» или что мы «вызвали tick у clock».</p>
   <p>Ну что, вы выполнили тест? Хорошо. Что ж, я уверен, что вы вспомнили методы puts, gets и chomp, так как мы только что разобрали их. Вы, возможно, также усвоили наши методы преобразования: to_i, to_f и to_s. Однако, знаете ли вы остальные четыре? Ну конечно же, это не что иное, как старые добрые арифметические действия: +, -, * и / !</p>
   <p>Как я уже говорил ранее, также как каждому глаголу нужно существительное, так и каждому методу требуется объект. Обычно легко сказать, какой объект выполняет метод: тот, что стоит непосредственно перед точкой, как в примере с clock.tick или в 101. to_s. Иногда же это не столь очевидно, например, в арифметических методах. Выясняется, что 5 + 5 это на самом деле просто сокращённый способ записи 5.+ 5. Например:</p>
   <p><code>puts 'привет '.+ 'мир' puts (10.* 9).+ 9</code></p>
   <p><code>привет мир 99</code></p>
   <p>Выглядит не слишком привлекательно, поэтому мы больше не будем записывать методы в таком виде. Но нам ведь важно понимать, что же происходит в действительности. (На моей машине, эта программа также выдаёт мне такое предупреждение:</p>
   <empty-line/>
   <p><code>warning: parenthesize argument(s)for future_version</code></p>
   <empty-line/>
   <p>[предупреждение: заключите аргумент(ы) в скобки для будущих версий – <emphasis>Прим. перев.</emphasis>].</p>
   <p>Этот код прекрасно выполнился, но мне было сказано, что возникли трудности при выяснении, что я имею в виду, поэтому на будущее рекомендуется использовать дополнительно скобки.) И это также даёт нам более глубокое понимание, почему мы можем выполнить 'pig'*5, но не можем выполнить 5*'pig': 'pig'*5 указывает 'pig' выполнить умножение, а 5*'pig' предписывает числу 5 выполнить умножение. Строка 'pig' знает, как сделать 5 собственных копий и объединить их вместе; однако, числу 5 будет затруднительно сделать 'pig' копий самого себя и сложить их вместе.</p>
   <p>И, конечно, нам всё ещё нужно выяснить про puts и gets. Где же их объекты? В английском [и в русском – <emphasis>Прим. перев.</emphasis>] языке, вы можете иногда опустить существительное; например, если злодей завопит «Умри!», неявным существительным будет тот, кому он кричит. В Ruby, если я говорю puts ' быть</p>
   <p>или не быть', на самом деле я говорю: self.puts 'быть или не быть'. Но что же такое self? Это специальная переменная, которая указывает на тот объект, в котором вы находитесь. Мы пока что не знаем, как находиться внутри объекта, но покуда мы это не выяснили, мы всегда будем находиться в большом объекте, которым является… вся наша программа! И к счастью для нас, у этой программы есть несколько собственных методов, наподобие puts и gets. Посмотрите:</p>
   <p><code>iCantBelieveIMadeAVariableNameThisLongJustToPointToA3 = 3 puts iCantBelieveIMadeAVariableNameThisLongJustToPointToA3 self.puts iCantBelieveIMadeAVariableNameThisLongJustToPointToA3 3 3</code></p>
   <p>Если вы не совсем въехали во всё это, это нормально. Самое важное, что нужно из всего этого уяснить, это то, что каждый метод выполняется некоторым объектом, даже если перед ним не стоит точка. Если вы понимаете это, то вы вполне готовы двигаться дальше.</p>
   <empty-line/>
   <p><strong>Забавные строковые методы</strong></p>
   <empty-line/>
   <p>Давайте изучим несколько забавных строковых методов. Вам не нужно их все запоминать; достаточно просто ещё раз взглянуть на эту страницу, если вы их позабудете. Я только хочу показать вам небольшую часть того, что могут делать строки. На самом деле, я и сам не могу запомнить даже половины строковых методов – но это нормально, потому что в Интернете есть замечательные справочники, где перечислены и объяснены все строковые методы. (Я покажу вам, где их найти в конце этого учебника.) Серьёзно, я даже не хочу знать все строковые методы: это всё равно, что знать каждое слово в словаре. Я прекрасно могу говорить по-английски, не зная всех слов в словаре… и ведь не в этом же заключается сам смысл словаря? Вам ведь не требуется знать всё, что в нём содержится?</p>
   <p>Итак, наш первый строковый метод это reverse, который выдаёт значение строки, перевёрнутое задом наперёд:</p>
   <p><code>varl = 'барк' var2 = 'телекс'</code></p>
   <p><code>var3 = 'Вы можете произнести это предложение наоборот?'</code></p>
   <p><code>puts varl.reverse</code></p>
   <p><code>puts var2.reverse</code></p>
   <p><code>puts var3.reverse</code></p>
   <p><code>puts varl</code></p>
   <p><code>puts var2</code></p>
   <p><code>puts var3</code></p>
   <p><code>краб</code></p>
   <p><code>скелет</code></p>
   <p><code>?торобоан</code></p>
   <p><code>еинежолдерп отэ итсензиорп</code></p>
   <p><code>етежом ыВ</code></p>
   <p><code>барк</code></p>
   <p><code>телекс</code></p>
   <p><code>Вы можете</code></p>
   <p><code>произнести это предложение</code></p>
   <p><code>наоборот?</code></p>
   <p>Как видите, reverse не переворачивает значение исходной строки, он просто создаёт её новую перевёрнутую копию. Вот почему в vari по-прежнему содержится 'барк' даже после того, как мы вызвали reverse у vari.</p>
   <p>Другой строковый метод это length, который сообщает нам количество символов (включая пробелы) в строке:</p>
   <p><code>puts 'Как Ваше полное имя?' name = gets.chomp</code></p>
   <p><code>puts 'Вы знаете, что Ваше имя состоит из '+name.length+' символов,</code></p>
   <p><code>'+name+'?'</code></p>
   <p><code>Как Ваше полное имя?</code></p>
   <p><code>Christopher David Pine</code></p>
   <p><code>#&lt;TypeError: can't convert Fixnum into String&gt;</code></p>
   <empty-line/>
   <p>Ой-ё-ёй! Что-то не сработало, и, кажется, это случилось где-то после строки name = gets.chomp… Вы понимаете, в чём дело? Поглядим, сможете ли вы разобраться с этим.</p>
   <p>Причина заморочки – в методе length: он выдаёт нам число, а нам нужна строка. Исправить это довольно просто: мы только воткнём to_s (и скрестим пальцы на удачу):</p>
   <p><code>puts 'Как Ваше полное имя?' name = gets.chomp</code></p>
   <p><code>puts 'Вы знаете, что Ваше имя состоит из '+name.length.to_s+' символов, '+name+'?'</code></p>
   <p><code>Как Ваше полное имя?</code></p>
   <p><code>Christopher David Pine</code></p>
   <p>Вы знаете, что Ваше имя состоит из 22 символов, Christopher David Pine?</p>
   <p>Нет, я этого не знал. Внимание: это количество символов в моём имени, а не количество букв (сосчитайте их). Думаю, мы могли бы написать программу, которая спрашивает ваше имя, отчество и фамилию по отдельности, а затем складывает их длины… эй, почему бы вам это не сделать? Давайте, я подожду.</p>
   <p>И что, сделали? Хорошо! Нравится программировать, не так ли? А вот после нескольких следующих глав вы сами изумитесь тому, что вы сможете делать.</p>
   <p>Итак, есть ещё несколько строковых методов, которые изменяют регистр букв (заглавных или строчных) в вашей строке. upcase изменяет каждую строчную букву на заглавную, а downcase изменяет каждую заглавную букву на строчную. swapcase переключает регистр каждой буквы в строке, и наконец, capitalize работает совсем как downcase за исключением того, что он переводит первую букву в заглавную (если это буква).</p>
   <empty-line/>
   <p><code>letters = 'aAbBcCdDeE'</code></p>
   <p><code>puts</code></p>
   <p><code>letters</code></p>
   <p><code>upcase</code></p>
   <p><code>puts</code></p>
   <p><code>letters</code></p>
   <p><code>downcase</code></p>
   <p><code>puts</code></p>
   <p><code>letters</code></p>
   <p><code>swapcase</code></p>
   <p><code>puts</code></p>
   <p><code>letters</code></p>
   <p><code>capitalize</code></p>
   <p><code>puts</code></p>
   <p><code>'a'.capitalize</code></p>
   <p><code>puts</code></p>
   <p><code>letters</code></p>
   <empty-line/>
   <p><code>AABBCCDDEE</code></p>
   <p><code>aabbccddee</code></p>
   <p><code>AaBbCcDdEe</code></p>
   <p><code>Aabbccddee</code></p>
   <p><code>a</code></p>
   <p><code>aAbBcCdDeE</code></p>
   <empty-line/>
   <p>Довольно обычные средства. Как видно из строки puts 'a'.capitalize, метод capitalize переводит в заглавную только первый символ, а не первую букву. И также, как мы уже видели раньше, при вызове всех этих методов, значение letters остаётся неизменным. Мне не хотелось бы слишком вас мучить этим, но это важно понимать. Есть ещё несколько методов, которые действительно изменяют ассоциированные с ними объекты, но мы их пока что не видели и не увидим ещё некоторое время.</p>
   <p>[Чтобы преобразовывать строки с русскими буквами потребуется установить одну из дополнительных библиотек, например, active_support, и тогда можно будет воспользоваться методами «cTpoKa».chars.downcase, «cTpoKa».chars.upcase, «cTpoKa».chars.capitalize. – <emphasis>Прим. перев.</emphasis>]</p>
   <p>Остальные из этих забавных строковых методов, рассматриваемых нами, предназначены для визуального форматирования. Первый из них, center, добавляет пробелы в начало и в конец строки, чтобы отцентрировать её. Однако, также как вам требовалось указать методу puts, что вы хотите напечатать, а методу +, что вы хотите сложить, вам нужно указать методу center, какой ширины должна быть ваша отцентрированная строка. Так, если бы мне захотелось расположить по центру строки стихотворения, я бы сделал это примерно так [вместо оригинального английского шестистишия приводится другой подходящий лимерик Эдварда Лира в переводе Е. В. Клюева – <emphasis>Прим. перев.</emphasis>]:</p>
   <empty-line/>
   <p><code>lineWidth = 50</code></p>
   <p><code>puts (</code></p>
   <p><code>'Вот вам юная мисс из России:'</code></p>
   <p><code>.center(lineWidth))</code></p>
   <p><code>puts (</code></p>
   <p><code>'Визг её был ужасен по силе.'</code></p>
   <p><code>.center(lineWidth))</code></p>
   <p><code>puts (</code></p>
   <p><code>'Он разил, как кинжал, – '</code></p>
   <p><code>.center(lineWidth))</code></p>
   <p><code>puts (</code></p>
   <p><code>'Так никто не визжал,'</code></p>
   <p><code>.center(lineWidth))</code></p>
   <p><code>puts('Как визжала та Мисс из России.'</code></p>
   <p><code>.center(lineWidth))</code></p>
   <empty-line/>
   <p><code>Вот вам юная мисс из России:</code></p>
   <p><code>Визг её был ужасен по силе.</code></p>
   <p><code>Он разил, как кинжал, – так никто не визжал,</code></p>
   <p><code>Как визжала та Мисс из России.</code></p>
   <empty-line/>
   <p>Хммм… Не думаю, что этот детский стишок звучит именно так, но мне просто лень уточнить по книге. (Кроме того, я хотел выровнять части строк программы, где встречается.center(lineWidth), поэтому я вставил эти лишние пробелы перед строками. Это сделано просто потому, что мне кажется, что так красивее. У программистов часто вызывает сильные чувства обсуждение того, что в программе является красивым, и они часто расходятся во мнениях об этом. Чем больше вы программируете, тем больше вы следуете своему собственному стилю.) Что касается разговоров о лени, то лень в программировании – это не всегда плохо. Например, видите, что я сохранил ширину стихотворения в переменной lineWidth? Это для того, чтобы, если я захочу позже вернуться к программе и сделать стих шире, мне нужно будет изменить только самую верхнюю строку программы вместо того, чтобы менять каждую из строк, где есть центрирование. При достаточно длинном стихотворении это может сэкономить мне немало времени. Вот такая разновидность лени – это действительно добродетель в программировании. [Однако автор не поленился назвать эту переменную достаточно длинным, но зато осмысленным именем lineWidth, так как он сознаёт, насколько важно для читающего программу правильно понимать назначение переменных. – <emphasis>Прим. перев.</emphasis>]</p>
   <p>Так вот, о центрировании… Как вы могли заметить, оно не столь прекрасно, как его мог бы сделать текстовый процессор. Если вы действительно хотите идеальное центрирование (и, возможно, более симпатичный шрифт), тогда вы просто должны использовать текстовый процессор! Ruby – это удивительный инструмент, но нет ни одного инструмента идеального для любой работы.</p>
   <p>Два других метода форматирования строк – это ljust и rjust, названия которых обозначают left justify (выровнять влево) и right justify (выровнять вправо). Они похожи на center за исключением того, что они добавляют к строке пробелы соответственно с левой или с правой стороны. Давайте посмотрим все три метода в действии:</p>
   <empty-line/>
   <p><code>lineWidth = 40 str = '–-&gt; текст &lt;--' puts str.ljust lineWidth puts str.center lineWidth puts str.rjust lineWidth</code></p>
   <p><code>puts str.ljust (lineWidth/2) + str.rjust (lineWidth/2)</code></p>
   <p><code>–&gt;</code></p>
   <p><code>текст</code></p>
   <p><code>&lt;–</code></p>
   <p><code>–-&gt; текст &lt;--</code></p>
   <p><code>–- &gt;</code></p>
   <p><code>текст</code></p>
   <p><code>&lt; –</code></p>
   <p><code>–&gt;</code></p>
   <p><code>текст</code></p>
   <p><code>&lt;–</code></p>
   <p><code>–- &gt;</code></p>
   <p><code>текст</code></p>
   <p><code>&lt; –</code></p>
   <subtitle>Попробуйте ещё кое-что</subtitle>
   <p>• Напишите программу «Злой Начальник». Он должен грубо спрашивать, чего вы хотите. Что бы вы ему ни ответили, Злой Начальник должен орать вам это же самое в ответ, а затем увольнять вас. Например, если вы введёте: Я хочу повышения зарплаты.,</p>
   <p>он должен прокричать в ответ:</p>
   <p>ЧТО ЗНАЧИТ: «Я ХОЧУ ПОВЫШЕНИЯ ЗАРПЛАТЫ.»?!? ВЫ УВОЛЕНЫ!!</p>
   <p>• А вот здесь для вас есть кое-что, чтоб ещё поиграть с center, ljust и rjust: напишите программу, которая будет отображать «Содержание» так, чтобы это выглядело следующим образом:</p>
   <empty-line/>
   <p>Содержание</p>
   <p>Глава 1: Числа page 1</p>
   <p><code>Глава 2 :</code></p>
   <p><code>Буквы</code></p>
   <p><code>page 72</code></p>
   <p><code>Глава 3:</code></p>
   <p><code>Переменные</code></p>
   <p><code>page 118</code></p>
   <subtitle>Высшая математика</subtitle>
   <p>(Этот раздел – совершенно необязательный. Он предполагает некоторый уровень математических знаний. Если вам не интересно, вы можете без малейших затруднений перейти прямо к Управлению выполнением. Однако, быстрый взгляд на раздел о случайных числах может весьма пригодиться.)</p>
   <p>Числовых методов не настолько много, как строковых методов (хотя я всё равно не держу их все в своей голове). Здесь мы рассмотрим оставшиеся арифметические методы, генератор случайных чисел и объект Math с его тригонометрическими и трансцендентальными методами.</p>
   <subtitle>Снова арифметика</subtitle>
   <p>Ещё два арифметических метода – это ** (возведение в степень) и % (деление по модулю). Так что, если вы хотите сказать на Ruby «пять в квадрате», вы просто запишите это как 5**2. Вы также можете использовать в качестве степени числа с плавающей точкой, так что если вам нужен квадратный корень из пяти, вы можете написать 5**0.5. Метод % (деление по модулю) выдаёт остаток от деления на число. Так, например, если я разделю 7 на 3, то получу 2 и 1 в остатке. Давайте посмотрим, как это работает в программе:</p>
   <empty-line/>
   <p><code>puts 5**2 puts 5**0.5 puts 7/3 puts 7%3</code></p>
   <p><code>puts 365%7</code></p>
   <empty-line/>
   <p>Из последней строки мы узнали, что любой (не високосный) год состоит из некоторого количества недель плюс один день. Так что, если ваш день рождения был во вторник в этом году, на следующий год он будет в среду. Вы также можете применять в методе деления по модулю числа с плавающей точкой. В основном, он выполняет вычисления наиболее возможным осмысленным способом… но я предоставляю вам самим поиграть с этим.</p>
   <p>Остаётся упомянуть ещё один метод прежде, чем мы проверим работу генератора</p>
   <p>случайных чисел: abs. Он просто берёт абсолютное значение указанного числа:</p>
   <p><code>puts((5–2).abs) puts((2–5).abs)</code></p>
   <p><code>3</code></p>
   <p><code>3</code></p>
   <subtitle>Случайные числа</subtitle>
   <p>Ruby поставляется с довольно хорошим генератором случайных чисел. Метод, возвращающий случайно выбранное число, называется rand. Если вы вызовете rand как есть (без аргументов), вы получите дробное число, большее или равное 0.0 и меньшее 1.0. Если вы дадите методу rand целое (например, 5), он вернёт вам целое число, большее или равное 0 и меньшее, чем 5 (то есть одно из пяти возможных чисел, от 0 до 4).</p>
   <p>Давайте посмотрим rand в действии. (Если вы перезагрузите эту страницу [на оригинальном англоязычном сервере – <emphasis>Прим. перев.</emphasis>], то эти числа будут каждый раз другими. Вы ведь знали, что я на самом деле выполнял все эти программы, не так ли?)</p>
   <empty-line/>
   <p><code>puts rand puts rand puts rand puts(rand(100)) puts(rand (100)) puts(rand(100)) puts(rand(1)) puts(rand(1)) puts(rand (1))</code></p>
   <p><code>puts(rand(99999999999999999999999999999999999999999999999999999999999))</code></p>
   <p><code>puts('Синоптик сказал, что с вероятностью в '+rand(101).to_s+'% пойдёт дождь,')</code></p>
   <p><code>puts('но никогда не стоит доверять синоптикам.')</code></p>
   <p><code>0.053950924931684</code></p>
   <p><code>0.975039266747952</code></p>
   <p><code>0.436084118016833</code></p>
   <p><code>38</code></p>
   <p><code>0</code></p>
   <p><code>0</code></p>
   <p><code>0</code></p>
   <p><code>5435049192 7962189206794015651522429182285732200948685516886</code></p>
   <p>Синоптик сказал, что с вероятностью в 22% пойдёт дождь, но никогда не стоит доверять синоптикам.</p>
   <p>Обратите внимание, что я использовал rand(101), чтобы получить числа от 0 до 100, и что rand (1) всегда возвращает 0. Непонимание того, каков диапазон возможных возвращаемых значений, является, по-моему, самой частой ошибкой, которую делают при работе с rand; даже профессиональные программисты и даже в завершённых программных продуктах, которые вы покупаете в магазине. У меня даже однажды был CD–проигрыватель, который в режиме «Случайное воспроизведение» проигрывал все песни, кроме последней… (Я гадал, что бы могло произойти, если я бы вставил в него CD с одной-единственной песней?)</p>
   <p>Иногда вы можете захотеть, чтобы rand возвращал те же самые случайные числа в той же последовательности при двух разных запусках вашей программы. (Например, я однажды использовал случайно сгенерированные числа для создания случайно сгенерированного мира в компьютерной игре. Если я обнаружил мир, который мне по- настоящему понравился, возможно, мне захочется снова сыграть с ним или отправить его другу.) Чтобы проделать это, вам нужно задать seed [зерно случайной последовательности – <emphasis>Прим. перев.</emphasis>], что можно сделать методом srand. Вот так:</p>
   <p><code>srand 1776 puts(rand (100)) puts(rand(100)) puts(rand(100)) puts(rand (100)) puts(rand(100)) puts '' srand 1776 puts(rand(100)) puts(rand(100)) puts(rand (100)) puts(rand(100)) puts(rand(100))</code></p>
   <p>Одно и то же будет выдаваться каждый раз, когда вы «посеете» то же самое число в качестве зерна. Если вы снова хотите получать различные числа (также, как происходит, если вы не применяли до этого srand), то просто вызовите srand 0. Этим вызовом в генератор «засевается» действительно причудливое число с использованием (кроме всего прочего) текущее время в вашем компьютере, с точностью до миллисекунды.</p>
   <empty-line/>
   <p><strong>Объект Math</strong></p>
   <empty-line/>
   <p>Наконец, давайте рассмотрим объект Math. Наверное, нам следует сразу окунуться в примеры:</p>
   <p><code>puts(Math::PI)</code></p>
   <p><code>puts(Math::E)</code></p>
   <p><code>puts(Math.cos(Math:</code></p>
   <p><code>:PI/3))</code></p>
   <p><code>puts(Math.tan(Math:</code></p>
   <p><code>:PI/4))</code></p>
   <p><code>puts(Math.log(Math:</code></p>
   <p><code>:E**2))</code></p>
   <p><code>puts((1 + Math.sqrt(5))/2)</code></p>
   <empty-line/>
   <p>Первое, что вы, возможно, заметили, это символы :: в обозначениях констант. Объяснение оператора пределов видимости (а это именно он) на самом деле выходит за, хм… пределы этого учебника. Я не хотел каламбурить. Честное слово. Достаточно сказать, что вы можете просто использовать Math::Pi в ожидаемом вами значении.</p>
   <p>Как видите, в Math есть всё, что вы предполагаете иметь в приличном научном калькуляторе. И как и прежде, дробные числа действительно близко представляют правильные результаты. [Точность вычислений десятичных чисел ограничена их двоичным представлением в компьютере. – <emphasis>Прим. перев</emphasis>.]</p>
   <p>А теперь перейдём к выполнению!</p>
  </section>
  <section>
   <title>
    <p>6. Управление выполнением</p>
   </title>
   <p>Ааааа, управление выполнением… Вот где всё соединяется воедино. И хотя эта глава короче и легче, чем глава о методах, она откроет вам целый мир программных возможностей. После этой главы мы сможем писать по-настоящему интерактивные программы; до этого мы создавали программы, которые выводили разные вещи в зависимости от вашего ввода с клавиатуры, но после этой главы они также будут действительно делать разные вещи. Но прежде, чем мы сможем сделать это, нам нужно иметь возможность сравнивать объекты в наших программах. Нам нужны…</p>
   <empty-line/>
   <p><strong>Методы сравнения</strong></p>
   <empty-line/>
   <p>Давайте быстро пробежимся по этому разделу, чтобы можно было перейти к следующему разделу, «Ветвления», где будут происходить самые классные вещи. Так, чтобы узнать, что один объект больше или меньше другого, мы применяем методы &gt; и &lt;, вот так:</p>
   <empty-line/>
   <p><code>puts 1 &gt; 2 puts 1 &lt; 2</code></p>
   <p><code>false</code></p>
   <p><code>true</code></p>
   <empty-line/>
   <p>Ничего сложного. Подобным же образом мы можем выяснить, что объект больше или равен другому (или меньше или равен) с помощью методов &gt;= и &lt;=.</p>
   <empty-line/>
   <p><code>puts 5 &gt;= 5 puts 5 &lt;= 4</code></p>
   <p><code>true</code></p>
   <p><code>false</code></p>
   <empty-line/>
   <p>И наконец, мы можем выяснить, равны ли два объекта или нет, используя == (что обозначает «они равны?») и != (что обозначает «они различны?»). Важно не путать = с ==. = используется, чтобы заставить переменную указывать на объект (присваивание), а == используется для ответа на вопрос: «Эти два объекта равны?»</p>
   <empty-line/>
   <p><code>puts 1 == 1 puts 2 != 1</code></p>
   <p><code>true</code></p>
   <p><code>true</code></p>
   <empty-line/>
   <p>Конечно, мы также можем сравнивать строки. Когда сравниваются строки, они сопоставляются в лексикографическом порядке, что обычно означает словарную упорядоченность. cat в словаре идёт перед dog, поэтому:</p>
   <p><code>puts 'cat' &lt; 'dog'</code></p>
   <p><code>true</code></p>
   <empty-line/>
   <p>Однако, здесь таится ловушка: обычно в компьютерах устроено так, что устанавливается такой порядок букв, в котором заглавные располагаются перед строчными буквами. (Так хранятся буквы в шрифтах, например: сначала все заглавные буквы, а за ними – строчные.) Это означает, что компьютер будет думать, что ' Zoo' располагается перед ' ant', так что, если вы хотите выяснить, какое слово идёт первым в настоящем словаре, обязательно примените метод downcase (или upcase или capitalize) к обоим словам прежде, чем вы попытаетесь их сравнить.</p>
   <p>Последнее замечание перед «Ветвлением»: методы сравнения не возвращают нам строки 'true' и 'false'; они возвращают нам специальные объекты true и false.</p>
   <p>(Конечно, true.to__ s вернёт нам ' true', именно поэтому puts напечатал ' true'.)</p>
   <p><code>true и false всегда используются для…</code></p>
   <subtitle>Ветвления</subtitle>
   <p>Ветвление – это простое, но очень мощное понятие. Фактически, оно настолько простое, что, ей-Богу, мне совсем даже и не нужно объяснять его; я просто покажу его вам:</p>
   <p><code>puts 'Привет, как Вас зовут?' name = gets.chomp puts 'Привет, ' + name + '.' if name == 'Chris'</code></p>
   <p><code>puts 'Какое милое имя!' end</code></p>
   <p><code>Привет, как Вас зовут?</code></p>
   <p><code>Chris</code></p>
   <p><code>Привет, Chris.</code></p>
   <p>Какое милое имя!</p>
   <p><code>Но если мы введём другое имя…</code></p>
   <p><code>Привет, как Вас зовут?</code></p>
   <p><code>Chewbacca Привет, Chewbacca.</code></p>
   <empty-line/>
   <p>Вот это и есть ветвление. Если то, что находится после if, имеет значение true, мы выполняем код между if и end. Если то, что находится после if, имеет значение false, то не выполняем. Ясно и просто.</p>
   <p>Я выделил отступом код между if и end просто потому, что, полагаю, таким образом легче отслеживать ветвление. Почти все программисты делают так, независимо от того, на каком языке они программируют. В этом простом примере может показаться, что от этого не слишком много пользы, но когда программа становится более сложной, это существенно меняет дело.</p>
   <p>Часто нам бы хотелось, чтобы программа выполняла что-то, если выражение равно true, и нечто другое, если оно равно false. Для этого имеется else:</p>
   <empty-line/>
   <p><code>puts 'Я – предсказатель судьбы. Скажите мне своё имя:' name = gets.chomp if name == 'Chris'</code></p>
   <p><code>puts 'Я предвижу у Вас в будущем великие дела.' else</code></p>
   <p><code>puts 'Ваше будущее… О Боже! Посмотрите-ка на часы!' puts 'На самом деле мне пора уходить, извините!' end</code></p>
   <p><code>Я предсказатель будущего. Скажите мне своё имя:</code></p>
   <p><code>Chris</code></p>
   <p><code>Я предвижу у Вас в будущем великие дела.</code></p>
   <p><code>А теперь давайте попробуем другое имя…</code></p>
   <p><code>Я предсказатель будущего. Скажите мне своё имя:</code></p>
   <p>Ringo</p>
   <p><code>Ваше будущее… О Боже! Посмотрите-ка на часы!</code></p>
   <p><code>На самом деле мне пора уходить, извините!</code></p>
   <empty-line/>
   <p>Ветвление – это как будто мы подошли к развилке в коде: мы выберем дорожку к людям, чьё имя – Крис (name == ' Chris ' ), или же (else) мы выберем другой путь.</p>
   <p>И совсем как ветви на дереве, у вас могут быть ветвления, которые сами содержат ветвления:</p>
   <empty-line/>
   <p><code>puts 'Здравствуйте и добро пожаловать в 7-й класс на урок английского.' puts 'Меня зовут миссис Габбард. А тебя зовут…?' name = gets.chomp</code></p>
   <p><code>if name == name.capitalize</code></p>
   <p><code>puts 'Садись, пожалуйста, ' + name + '.'</code></p>
   <p><code>else</code></p>
   <p><code>puts name + '? Ты имел в виду: ' + name.</code></p>
   <p><code>capitalize + '</code></p>
   <p><code>, не так ли?'</code></p>
   <p><code>puts 'Ты что, даже не знаешь, как пишется</code></p>
   <p><code>твоё имя??'</code></p>
   <p><code>reply = gets.chomp</code></p>
   <p><code>if reply == 'да'</code></p>
   <p><code>puts 'Хммм! Ну хорошо, садись!'</code></p>
   <p><code>else</code></p>
   <p><code>puts 'УБИРАЙСЯ ВОН!!'</code></p>
   <p><code>end</code></p>
   <p><code>end</code></p>
   <p><code>Здравствуйте и добро пожаловать в 7-й класс на урок английского.</code></p>
   <p><code>Меня зовут миссис Габбард. А тебя зовут…?</code></p>
   <p><code>chris</code></p>
   <p><code>chris? Ты имел в виду: Chris, не так ли?</code></p>
   <empty-line/>
   <p>Ты что, даже не знаешь, как пишется твоё имя??</p>
   <p>да</p>
   <p>Хммм! Ну хорошо, садись!</p>
   <p>Прекрасно, напишу его с заглавной буквы…</p>
   <p>Здравствуйте и добро пожаловать в 7-й класс на урок английского.</p>
   <p>Меня зовут миссис Габбард. А тебя зовут…?</p>
   <p>Chris</p>
   <p>Садись, пожалуйста, Chris.</p>
   <p>Иногда можно запутаться, пытаясь «вычислить», куда же ведут все эти if–ы, else–ы и end–ы. Я делаю так: пишу end сразу же, когда напишу if. Так, когда я писал приведённую выше программу, сначала она выглядела вот так:</p>
   <empty-line/>
   <p><code>puts 'Здравствуйте и добро пожаловать в 7-й класс на урок английского.' puts 'Меня зовут миссис Габбард. А тебя зовут…?' name = gets.chomp</code></p>
   <p><code>if name == name.capitalize</code></p>
   <p><code>else</code></p>
   <p><code>end</code></p>
   <empty-line/>
   <p>Затем я вставил комментарии – те вещи в коде, которые компьютер проигнорирует:</p>
   <p><code>puts 'Здравствуйте и добро пожаловать в 7-й класс на урок английского.'</code></p>
   <p><code>puts 'Меня зовут миссис Габбард. А тебя зовут…?'</code></p>
   <p><code>name = gets.chomp</code></p>
   <p><code>if name == name.capitalize</code></p>
   <p><code># Она говорит вежливо. else</code></p>
   <p><code># Она постепенно свирепеет. end</code></p>
   <empty-line/>
   <p>Всё, что стоит после знака #, считается комментарием (конечно, если только он не находится внутри строки). После этого я заменил комментарии работающим кодом. Некоторым нравится оставлять комментарии; лично я думаю, что хорошо написанный код обычно говорит сам за себя. Раньше я применял больше комментариев, но чем более «бегло» я пишу на Ruby, тем меньше я их использую. На самом деле я нахожу их в большинстве случаев отвлекающими внимание. Но это каждый выбирает для себя сам; и у вас сложится свой собственный (обычно развивающийся) стиль. И вот, мой следующий шаг выглядел так:</p>
   <empty-line/>
   <p><code>puts 'Здравствуйте и добро пожаловать в 7-й класс на урок английского.'</code></p>
   <p><code>puts 'Меня зовут миссис Габбард. А тебя зовут…?'</code></p>
   <p><code>name = gets.chomp</code></p>
   <p><code>if name == name.capitalize</code></p>
   <p><code>puts 'Садись, пожалуйста, ' + name + '.' else</code></p>
   <p><code>puts name + '? Ты имел в виду: ' + name.capitalize + ', не так ли?' puts 'Ты что, даже не знаешь, как пишется твоё имя??' reply = gets.chomp</code></p>
   <p><code>if reply == 'да' else end end</code></p>
   <empty-line/>
   <p>Снова я написал if, else и end одновременно. Это на самом деле помогает мне отслеживать, «где я нахожусь» в тексте программы. К тому же от этого задача кажется немного легче, поскольку я могу сфокусироваться на небольшой части программы – на вставке кода между if и else. Ести и другое преимущество от того, что я поступаю именно так. Оно состоит в том, что компьютер может понять программу на любом этапе разработки. Каждая из незаконченных версий программы, которые я показывал вам, будет выполняться. Они не были закончены, но это были работающие программы. Таким образом, я мог проверять её по ходу её написания, что помогало увидеть, как обстоят дела, и где она всё ещё нуждалась в доработке. Когда она прошла все проверки, я и выяснил, что я её закончил!</p>
   <p>Эти подсказки помогут вам писать программы с ветвлением, но они также помогут освоить другой основной тип управления выполнением:</p>
   <empty-line/>
   <subtitle>Циклы</subtitle>
   <empty-line/>
   <p>Довольно часто вам может захотеться, чтобы ваш компьютер выполнял одно и то же снова и снова – в конце концов, предполагается, что именно этим компьютеры занимаются лучше всего.</p>
   <p>Когда вы говорите вашему компьютеру повторять что-либо, вам также нужно сказать ему, когда остановиться. Компьютеру никогда не может наскучить, поэтому если вы не скажете ему остановиться, он и не остановится. Мы можем быть уверены, что подобное не случится, если скажем компьютеру повторять отдельные части программы пока (while) определённое условие является истинным. Это работает очень похоже на то, как работает if:</p>
   <p><code>command = ' ' while command != 'пока' puts command command = gets.chomp end</code></p>
   <p><code>puts 'Приходите ещё!'</code></p>
   <p><code>Ау?</code></p>
   <p><code>Ау?</code></p>
   <p><code>Привет!</code></p>
   <p><code>Привет!</code></p>
   <empty-line/>
   <p><code>Рад</code></p>
   <p><code>познакомиться.</code></p>
   <p><code>Рад</code></p>
   <p><code>познакомиться.</code></p>
   <p><code>О..,</code></p>
   <p><code>как приятно!</code></p>
   <empty-line/>
   <p><code>пока</code></p>
   <p><code>Приходите ещё !</code></p>
   <empty-line/>
   <p>Вот это и есть цикл. (Вы, наверное, заметили пустую строку в в начале вывода; она – от первого puts, перед первым gets. Как бы вы изменили программу, чтобы избавиться от этой пустой строки? Проверьте её! Она работает в точности, как программа выше, не считая первой пробельной строки?)</p>
   <p>Циклы позволяют вам делать самые разные интересные вещи, какие только можно себе вообразить. Они, однако, могут также вызвать и неприятности, если вы сделаете ошибку. Что если ваш компьютер попадётся в ловушку бесконечного цикла? Если вы думаете, что именно так, возможно, и случилось, то просто, удерживая клавишу Ctrl, нажмите на клавишу с. [Это прервёт выполнение вашей программы. – <emphasis>Прим. перев.</emphasis>]</p>
   <p>Но прежде, чем мы начнём забавляться с циклами, давайте изучим несколько вещей, которые облегчат нам жизнь.</p>
   <subtitle>Чуть-чуть логики</subtitle>
   <p>Давайте снова взглянем на нашу первую программу с ветвлением. Что если моя жена пришла домой, увидела эту программу, попробовала выполнить её, и она не сказала ей, какое милое имя у неё? Я не хотел бы обидеть её чувства (и спать на кушетке), так что давайте перепишем её:</p>
   <empty-line/>
   <p><code>puts 'Привет, как Вас зовут?' name = gets.chomp puts 'Привет, ' + name + '.' if name == 'Chris'</code></p>
   <p><code>puts 'Какое милое имя!' else</code></p>
   <p><code>if name == 'Katy'</code></p>
   <p><code>puts 'Какое милое имя!' end end</code></p>
   <empty-line/>
   <p>Привет, как Вас зовут?</p>
   <p>Katy</p>
   <p>Привет, Katy. Какое милое имя!</p>
   <empty-line/>
   <p>Ну да, она работает… но это не очень-то красивая программа. Почему не очень? Ну, потому, что лучшее правило, которое я когда-либо узнал в программировании, – это правило DRY (Don't Repeat Yourself), то есть «Не повторяйся!» Возможно. я бы мог написать небольшую книгу только о том, почему это такое хорошее правило. В нашем случае, мы повторили строку puts 'Какое милое имя! '. Почему это так важно? Ладно, а что если я сделал опечатку, когда переписывал её? Что если я хотел изменить с 'милое' на 'прекрасное' в обеих строках? Я же ленивый, помните? По сути, если я хочу, чтобы программа делала одно и то же, когда она получает 'Chris ' или ' Katy ', тогда она должна действительно делать одно и то же:</p>
   <empty-line/>
   <p><code>puts 'Привет, как Вас зовут?' name = gets.chomp</code></p>
   <p><code>puts 'Привет, ' + name + '.' if (name == 'Chris' or name == 'Katy')</code></p>
   <p><code>puts 'Какое милое имя!' end</code></p>
   <empty-line/>
   <p>Привет, как Вас зовут?</p>
   <p>Katy</p>
   <p>Привет, Katy.</p>
   <p>Какое милое имя!</p>
   <empty-line/>
   <p>Гораздо лучше. Чтобы заставить это заработать, я применил or. Другие логические операции это and и not. [«ИЛИ», «И» и «НЕ» – Прим. перев.] И когда работаешь с ними, лучшим решением будет всегда использовать скобки. Давайте посмотрм, как они работают:</p>
   <empty-line/>
   <p><code>iAmChris = true</code></p>
   <p><code>iAmPurple = false</code></p>
   <p><code>iLikeFood = true</code></p>
   <p><code>iEatRocks = false</code></p>
   <p><code>puts</code></p>
   <p><code>(iAmChris</code></p>
   <p><code>and</code></p>
   <p><code>iLikeFood)</code></p>
   <p><code>puts</code></p>
   <p><code>(iLikeFood</code></p>
   <p><code>and</code></p>
   <p><code>iEatRocks)</code></p>
   <p><code>puts</code></p>
   <p><code>(iAmPurple</code></p>
   <p><code>and</code></p>
   <p><code>iLikeFood)</code></p>
   <p><code>puts</code></p>
   <p><code>(iAmPurple</code></p>
   <p><code>and</code></p>
   <p><code>iEatRocks)</code></p>
   <p><code>puts</code></p>
   <p><code>puts</code></p>
   <p><code>(iAmChris</code></p>
   <p><code>or</code></p>
   <p><code>iLikeFood)</code></p>
   <p><code>puts</code></p>
   <p><code>(iLikeFood</code></p>
   <p><code>or</code></p>
   <p><code>iEatRocks)</code></p>
   <p><code>puts</code></p>
   <p><code>(iAmPurple</code></p>
   <p><code>or</code></p>
   <p><code>iLikeFood)</code></p>
   <p><code>puts (iAmPurple or iEatRocks) puts</code></p>
   <p><code>puts (not iAmPurple)</code></p>
   <p><code>puts (not iAmChris )</code></p>
   <p><code>true</code></p>
   <p><code>false</code></p>
   <p><code>false</code></p>
   <p><code>false</code></p>
   <p><code>true</code></p>
   <p><code>true</code></p>
   <p><code>true</code></p>
   <p><code>false</code></p>
   <p><code>true</code></p>
   <p><code>false</code></p>
   <p>Единственная из них, которая может обмануть вас, – это операция or. В английском языке мы часто используем «or» в значении «один или другой, но не оба». Например, ваша мама могла бы сказать: «На десерт ты можешь съесть торт или пирожное». Она не предполагала, что вы можете съесть и то и другое! Компьютер, напротив, использует or в значении «один или другой или оба». (Другой способ выразить это: «по крайней мере, один из них – истинный».) Вот почему с компьютерами гораздо веселее, чем с мамами.</p>
   <subtitle>Попробуйте ещё кое-что</subtitle>
   <p>• «99 бутылок пива на стене…» Напишите программу, которая печатает стихи этой излюбленной классической походной песни: «99 бутылок пива на стене».</p>
   <p>• Напишите программу «Глухая бабуля». Что бы вы ни говорили бабуле (чтобы вы ни вводили с консоли), она должна отвечать: АСЬ?! ГОВОРИ ГРОМЧЕ, ВНУЧЕК!, если только вы не кричите ей (вводите слова заглавными буквами). Если вы кричите, она вас слышит (или по крайней мере думает, что слышит) и вопит в ответ: НЕТ, НИ РАЗУ С 1938 ГОДА! Чтобы сделать вашу программу действительно правдоподобной, пусть бабуля кричит каждый раз другой год; например, любой случайный год между 1930 и 1950. (Эта часть необязательная, и вам будет гораздо легче, если вы прочтёте раздел о генераторе случайных чисел в Ruby в конце главы о методах.) Вы не можете остановить разговор с бабулей, пока не прокричите пока.</p>
   <empty-line/>
   <p>Подсказка: Не забывайте о chomp/ ' пока ' с символом Enter это не то же самое, что ' пока ' без него/</p>
   <p>Подсказка 2: Попробуйте обдумать, какие части вашей программы должны происходить снова и снова. Все они должны находиться внутри цикла while.</p>
   <empty-line/>
   <p>• Улучшите вашу программу «Глухая бабуля»: Что если бабуля не хочет, чтобы вы уходили? Когда вы кричите пока, она может притвориться, что не слышит вас. Измените вашу предыдущую программу так, чтобы вам нужно было прокричать пока три раза в одной строке. Удостоверьтесь в правильности вашей программы: если вы прокричите пока три раза, но не в одной строке, вы должны дальше разговаривать с бабулей.</p>
   <p>• Високосные годы. Напишите программу, которая будет спрашивать начальный год и конечный год, а затем выдавать с помощью puts все високосные годы между ними (и включая их, если они также високосные). Високосные годы – это годы, нацело делящиеся на 4 (как 1984 и 2004). Однако, годы, нацело делящиеся на 100, – не високосные (как 1800 и 1900) если только они не делятся нацело на 400 (как 1600 и 2000, которые действительно были високосными). (Да, это всё довольно запутанно, но не настолько запутанно, как если бы июль был в середине зимы, что иногда случалось бы.) [если бы не было високосных годов. – <emphasis>Прим. перев.</emphasis>]</p>
   <empty-line/>
   <p>Когда вы это закончите, сделайте перерыв! Вы уже многое изучили. Поздравляю! Вас удивляет, сколько разных вещей вы можете заставить делать компьютер? Ещё несколько глав, и вы сможете запрограммировать почти всё, что угодно. Серьёзно! Только взгляните на все эти штуки, что вы можете делать сейчас и которые не смогли бы сделать без циклов и ветвления.</p>
   <p>А теперь давайте изучим новую разновидность объектов, которые отвечают за списки других объектов: массивы.</p>
  </section>
  <section>
   <title>
    <p>7. Массивы и итераторы</p>
   </title>
   <p>Давайте напишем программу, которая просит нас ввести сколько угодно слов (по одному слову в строке до тех пор, пока мы не нажмём Enter на пустой строке) и которая затем повторяет нам эти слова в алфавитном порядке. Идёт?</p>
   <p>Так… сначала мы – ээ… ну… хммм… Хорошо, мы могли бы – ээ… ну…</p>
   <p>Вы знаете, я не думаю, что мы сможем это сделать. Нам нужен способ хранить неизвестное количество слов и как-то держать их все вместе, чтобы они не смешивались с другими переменными. Нам нужно поместить их все в какое-то подобие списка. Нам нужны массивы.</p>
   <p>Массив – это просто список в вашем компьютере. Каждая ячейка в списке ведёт себя как переменная: вы можете посмотреть, на какой объект указывает определённая ячейка, и вы можете сделать так, чтобы она указывала на другой объект. Давайте посмотрим на некоторые массивы:</p>
   <empty-line/>
   <p><code>[]</code></p>
   <p><code>#</code></p>
   <p><code>пустой массив</code></p>
   <p><code>[5]</code></p>
   <p><code>#</code></p>
   <p><code>массив из одного числа</code></p>
   <p><code>['Привет'</code></p>
   <p><code>, 'До свидания']</code></p>
   <p><code>#</code></p>
   <p><code>массив из 2–х строк</code></p>
   <p><code>flavor =</code></p>
   <p><code>'ванильный'</code></p>
   <p><code>#</code></p>
   <p><code>Это не массив, конечно…</code></p>
   <p><code>[89.9, flavor,[true, false]]</code></p>
   <p><code>#</code></p>
   <p><code>…но это – массив.</code></p>
   <p>Итак, сначала у нас есть пустой массив, затем массив, содержащий единственное число, затем массив, содержащий две строки. Потом у нас имеется простое присваивание; затем – массив, содержащий три объекта, последний из которых — это массив [true, false]. Помните, что переменные – это не объекты, поэтому наш последний массив в действительности указывает на число с плавающей точкой, на строку и на массив. Даже если бы мы сделали, чтобы переменная flavor указывала на что-нибудь другое, это не изменило бы этот массив.</p>
   <p>Чтобы помочь нам с поиском конкретных объектов в массиве, каждой ячейке даётся номер – индекс. Программисты (и, по случайному совпадению, большинство математиков) начинают считать их с нуля, так что первая ячейка в массиве – это ячейка номер ноль. Вот как мы должны адресоваться к объектам в массиве:</p>
   <empty-line/>
   <p><code>names =['Ада',</code></p>
   <p><code>'Белль',</code></p>
   <p><code>'Крис']</code></p>
   <p><code>puts names</code></p>
   <p><code>puts names[0]</code></p>
   <p><code>puts names[1]</code></p>
   <p><code>puts names[2]</code></p>
   <empty-line/>
   <p>Ада</p>
   <p>Белль</p>
   <p>Крис</p>
   <p>Ада</p>
   <p>Белль</p>
   <p>Крис</p>
   <p><code>nil</code></p>
   <p>Итак, мы видим, что puts names выводит каждое имя в массиве names. Затем мы используем puts names[0], чтобы напечатать «первое» имя в массиве и puts names[i], чтобы напечатать «второе»… Уверен, что это кажется запутанным, но вы непременно привыкните к этому. Вы просто должны действительно начать думать, что отсчёт начинается с нуля, и перестать использовать такие слова, как «первый» и «второй». Если вы идёте на обед из пяти блюд, не говорите о «первом» блюде; говорите о блюде ноль (а у себя в голове думайте о course[0]). На правой руке у вас пять пальцев с номерами 0, 1, 2, 3 и 4. Моя жена и я умеем жонглировать. Когда мы жонглируем шестью булавами, мы жонглируем булавами 0-5. Надеемся, что через несколько месяцев мы сможем жонглировать булавой номер 6 (и таким образом будем жонглировать между собой семью булавами). Вы поймёте, что привыкли к этому, когда начнёте использовать слово «нулевой». :-) Да, в самом деле есть такое слово: спросите у любого программиста или математика.</p>
   <p>Наконец, мы попытались выполнить puts names[3], просто чтобы посмотреть, что же получится. Вы ожидали ошибку? Иногда, когда вы задаёте вопрос, ваш вопрос не имеет смысла (по крайней мере для вашего компьютера); и тогда вам выдаётся ошибка. Иногда, однако, вы можете задать вопрос и ответ на него будет: ничего. Что в ячейке номер три? Ничего. Что в names[3]? nil: таким способом Ruby говорит «ничего». nil – это особенный объект, который обычно означает «никакой из объектов».</p>
   <p>Если вся эта смешная нумерация ячеек массивов начинает вас «доставать», не бойтесь! Часто мы сможем обойтись совершенно без неё, используя различные методы массивов, как вот этот:</p>
   <subtitle>Метод each</subtitle>
   <p>each позволяет нам делать что-нибудь (всё, что мы хотим) с каждым объектом, на который указывает массив. Так, если мы хотим сказать что-либо приятное о языке в приведённом ниже массиве, мы сделаем так:</p>
   <empty-line/>
   <p><code>languages = ['английский', 'немецкий', 'Ruby'] languages.each do |lang|</code></p>
   <p><code>puts 'Мне нравится ' + lang + '!'</code></p>
   <p><code>puts 'А вам?' end</code></p>
   <p><code>puts 'А теперь давайте послушаем мнение о C++!' puts '…'</code></p>
   <empty-line/>
   <p>Мне нравится английский!</p>
   <p>А вам?</p>
   <p>Мне нравится немецкий!</p>
   <p>А вам?</p>
   <p>Мне нравится Ruby!</p>
   <p>А вам?</p>
   <p>А теперь давайте послушаем мнение о C++!</p>
   <empty-line/>
   <p>Так что же сейчас произошло? Вот, мы смогли обойти каждый из объектов в массиве совсем без использования номеров, и это определённо приятно. В переводе на русский, приведённую выше программу можно прочитать примерно так: для каждого (each) объекта в languages, пусть переменная lang указывает на этот объект и затем выполнится (do) всё, что я скажу вам, пока вы не дойдёте до конца (end). (Чтобы вы знали: C++ это ещё один язык программирования. Его гораздо труднее изучить, чем Ruby; обычно, программа на C++ будет во много раз длиннее, чем программа на Ruby, которая делает то же самое.) Вы, должно быть, думаете: «Это очень похоже на циклы, о которых мы узнали до этого». Ну да, похоже. Одно важное отличие заключается в том, что метод each – это просто-напросто метод. while и end (также как do, if, else и все другие синие слова) это не методы. Они являются основополагающей частью языка Ruby, как и операция = или скобки; они похожи на знаки пунктуации в английском [или русском – <emphasis>Прим. перев.</emphasis>] языке.</p>
   <p>Но не each; each – это просто ещё один метод массива. Такие методы, как each, которые «ведут себя как» циклы, часто называют итераторами.</p>
   <p>Нужно отметить ещё одну вещь об итераторах: за ними всегда следует do…end. Около while и if никогда не бывает do; мы используем do только с итераторами.</p>
   <p>А вот другой маленький симпатичный итератор, но это не метод массива… Это метод целого числа!</p>
   <p><code>3.times do</code></p>
   <p><code>puts 'Гип-гип-ура!' end</code></p>
   <p>Гип-гип-ура! Гип-гип-ура!</p>
   <p>Другие методы массивов</p>
   <p>Итак, мы изучили each, но у массивов есть много других методов… почти столько же много, как методов у строк! В сущности, некоторые из них (такие, как length, reverse, + и *) работают так же, как и со строками, только они оперируют с ячейками массива, а не с буквами в строке. Другие, например, last и join, характерны только для массивов. Третьи, такие как push и pop, фактически изменяют массив. И так же, как с методами строк, вам не нужно помнить их все, покуда вы помните, где можно узнать о них (прямо здесь).</p>
   <p>Сначала давайте взглянем на to_s и join. Метод join работает во многом схоже с методом to__ s, за исключением того, что он добавляет строку между объектами массива. Давайте посмотрим:</p>
   <empty-line/>
   <p><code>foods = ['артишок',</code></p>
   <p><code>'бриошь',</code></p>
   <p><code>'карамель']</code></p>
   <p><code>puts foods</code></p>
   <p><code>puts</code></p>
   <p><code>puts foods.to s</code></p>
   <p><code>puts</code></p>
   <p><code>puts foods.join(',</code></p>
   <p><code>')</code></p>
   <p><code>puts</code></p>
   <p><code>puts foods.join('</code></p>
   <p><code>:) ') + '</code></p>
   <p><code>8) '</code></p>
   <p><code>200.times do</code></p>
   <p><code>puts[]</code></p>
   <p><code>end</code></p>
   <empty-line/>
   <p><code>артишок</code></p>
   <p>бриошь</p>
   <p>карамель</p>
   <p>артишокбриошькарамель</p>
   <p>артишок, бриошь, карамель</p>
   <p>артишок :) бриошь :) карамель 8)</p>
   <empty-line/>
   <p>Как видите, метод puts обращается с массивами не так, как с другими объектами: он просто вызывает puts для каждого из объектов в массиве. Вот почему вывод через puts пустого массива 200 раз ничего не делает: массив ни на что не указывает, так что нечего выводить с помощью puts. (Ничего не делать 200 раз – значит всё равно ничего не делать.) Попробуйте вывести методом puts массив, содержащий другие массивы: он делает то, что вы ожидали?</p>
   <p>Кроме того, вы заметили, что я не употреблял в puts пустые строки, когда хотел вывести чистую строку? Получилось то же самое.</p>
   <p>Теперь давайте посмотрим на push, pop и last. Методы push и pop в каком-то смысле противоположны, как + и -. push добавляет объект в конец вашего массива, а pop удаляет последний объект из массива (и сообщает вам, что это был за объект). last похож на pop в том, что он сообщает вам, что находится в конце массива, только он оставляет массив нетронутым. Повторю снова: push и pop действительно изменяют массив:</p>
   <empty-line/>
   <p><code>favorites = []</code></p>
   <p><code>favorites.push</code></p>
   <p><code>'капли дождя на розах'</code></p>
   <p><code>favorites.push</code></p>
   <p><code>'капли виски на котах'</code></p>
   <p><code>puts</code></p>
   <p><code>favorites[0]</code></p>
   <p><code>puts</code></p>
   <p><code>favorites</code></p>
   <p><code>. last</code></p>
   <p><code>puts</code></p>
   <p><code>favorites</code></p>
   <p><code>.length</code></p>
   <p><code>puts</code></p>
   <p><code>favorites</code></p>
   <p><code>.pop</code></p>
   <p><code>puts</code></p>
   <p><code>favorites</code></p>
   <p><code>puts</code></p>
   <p><code>favorites</code></p>
   <p><code>.length</code></p>
   <empty-line/>
   <p><code>капли</code></p>
   <p><code>дождя</code></p>
   <p><code>на</code></p>
   <p><code>розах</code></p>
   <p><code>капли</code></p>
   <p><code>виски</code></p>
   <p><code>на</code></p>
   <p><code>котах</code></p>
   <p><code>2</code></p>
   <empty-line/>
   <p><code>капли</code></p>
   <p><code>виски</code></p>
   <p><code>на</code></p>
   <p><code>котах</code></p>
   <p><code>капли</code></p>
   <p><code>дождя</code></p>
   <p><code>на</code></p>
   <p><code>розах</code></p>
   <p><code>1</code></p>
   <empty-line/>
   <p><strong>Попробуйте ещё кое-что</strong></p>
   <p>• Напишите программу, о которой мы говорили в самом начале этой главы.</p>
   <p>Подсказка: Есть прекрасный метод массива, который вернёт вам отсортированную версию массива: sort. Используйте его!</p>
   <p>• Попробуйте написать указанную программу без использования метода sort. Большая часть программирования – это преодоление сложностей, так что практикуйтесь чаще, насколько это возможно!</p>
   <p>• Перепишите вашу программу «Содержание» (из главы о методах). Начните программу с массива, содержащего всю информацию для вашей таблицы с содержанием (названия глав, номера страниц и т. д.). Затем напечатайте информацию из массива в виде красиво отформатированного содержания.</p>
   <p>До сих пор мы изучили довольно много разных методов. А сейчас пора научиться, как сделать свои собственные.</p>
  </section>
  <section>
   <title>
    <p>8. Пишем свои методы</p>
   </title>
   <p>Как мы уже видели, циклы и итераторы позволяют нам делать одно и то же (выполнять тот же самый код) снова и снова. Однако, иногда мы хотим сделать одно и то же несколько раз, но в разных частях программы. Например, мы бы разрабатывали, скажем, программу опроса для студента-психолога. Судя по разговорам со знакомыми студентами-психологами и по опросам, которые они мне предлагали, она, наверное, должна быть примерно такой:</p>
   <empty-line/>
   <p><code>puts 'Здравствуйте! И спасибо, что Вы нашли время, чтобы'</code></p>
   <p><code>puts 'помочь мне в этом исследовании. Мое исследование'</code></p>
   <p><code>puts 'связано с изучением того, как люди относятся к'</code></p>
   <p><code>puts 'мексиканской еде. Просто думайте о мексиканской еде'</code></p>
   <p><code>puts 'и попробуйте отвечать на все вопросы честно,'</code></p>
   <p><code>puts 'только словами «да» или «нет». Моё исследование'</code></p>
   <p><code>puts 'не имеет ничего общего с ночным недержанием мочи.' puts</code></p>
   <p><code># Мы задаём эти вопросы, но игнорируем ответы на них. goodAnswer = false while (not goodAnswer)</code></p>
   <p><code>puts 'Вам нравится есть такос?' answer = gets.chomp.downcase if (answer == 'да' or answer == 'нет') goodAnswer = true else</code></p>
   <p><code>puts 'Пожалуйста, отвечайте «да» или «нет».' end end</code></p>
   <p><code>goodAnswer = false while (not goodAnswer)</code></p>
   <p><code>puts 'Вам нравится есть бурритос?' answer = gets.chomp.downcase if (answer == 'да' or answer == 'нет')</code></p>
   <empty-line/>
   <p><code>goodAnswer = true</code></p>
   <p><code>else</code></p>
   <p><code>puts 'Пожалуйста, отвечайте «да» или</code></p>
   <p><code>«нет».'</code></p>
   <p><code>end</code></p>
   <p><code>end</code></p>
   <p><code># Мы, однако, обращаем внимание на *этот</code></p>
   <p><code>* вопрос.</code></p>
   <p><code>goodAnswer = false</code></p>
   <p><code>while (not goodAnswer)</code></p>
   <p><code>puts 'Вы мочитесь в постель?'</code></p>
   <p><code>answer = gets.chomp.downcase</code></p>
   <p><code>if (answer == 'да' or answer == 'нет')</code></p>
   <p><code>goodAnswer = true</code></p>
   <p><code>if answer == 'да'</code></p>
   <p><code>wetsBed = true</code></p>
   <p><code>else</code></p>
   <p><code>wetsBed = false</code></p>
   <p><code>end</code></p>
   <p><code>else</code></p>
   <p><code>puts 'Пожалуйста, отвечайте «да» или</code></p>
   <p><code>«нет».'</code></p>
   <p><code>end</code></p>
   <p><code>end</code></p>
   <p><code>goodAnswer = false</code></p>
   <p><code>while (not goodAnswer)</code></p>
   <p><code>puts 'Вам нравится есть чимичангас?'</code></p>
   <p><code>answer = gets.chomp.downcase</code></p>
   <p><code>if (answer == 'да' or answer == 'нет')</code></p>
   <p><code>goodAnswer = true</code></p>
   <p><code>else</code></p>
   <p><code>puts 'Пожалуйста, отвечайте «да» или</code></p>
   <p><code>«нет».'</code></p>
   <p><code>end</code></p>
   <p><code>end</code></p>
   <p><code>puts 'И ещё несколько вопросов…'</code></p>
   <p><code>goodAnswer = false while (not goodAnswer)</code></p>
   <p><code>puts 'Вам нравится есть сопапиллас?' answer = gets.chomp.downcase if (answer == 'да' or answer == 'нет') goodAnswer = true else</code></p>
   <p><code>puts 'Пожалуйста, отвечайте «да» или «нет».' end end</code></p>
   <p><code># Задайте много других вопросов о мексиканской еде. puts</code></p>
   <empty-line/>
   <p><code>puts 'ПОЯСНЕНИЕ:'</code></p>
   <p><code>puts 'Спасибо за то, что Вы нашли время, чтобы помочь'</code></p>
   <p><code>puts 'этому исследованию. На самом деле, это исследование'</code></p>
   <p><code>puts 'не имеет ничего общего с мексиканской едой. Это'</code></p>
   <p><code>puts 'исследование ночного недержания мочи. Мексиканская еда'</code></p>
   <p><code>puts 'присутствовала только затем, чтобы усыпить Вашу бдительность'</code></p>
   <p><code>puts 'в надежде, что Вы будете отвечать более'</code></p>
   <p><code>puts 'правдиво. Ещё раз спасибо.'</code></p>
   <p><code>puts</code></p>
   <p><code>puts wetsBed</code></p>
   <empty-line/>
   <p>Здравствуйте! И спасибо, что Вы нашли время, чтобы помочь мне в этом исследовании. Моё исследование связано с изучением того, как люди относятся к мексиканской еде. Просто думайте о мексиканской еде и попробуйте отвечать на все вопросы честно, только словами «да» или «нет». Моё исследование не имеет ничего общего с ночным недержанием мочи.</p>
   <empty-line/>
   <p>Вам нравится есть такос? да</p>
   <p>Вам нравится есть бурритос?</p>
   <p>Вы мочитесь в постель?</p>
   <p>никогда!</p>
   <p>Пожалуйста, отвечайте «да» или «нет». Вы мочитесь в постель?</p>
   <p>нет</p>
   <p>Вам нравится есть чимчангас?</p>
   <p>да</p>
   <p>И ещё несколько вопросов… Вам нравится есть сопапиллас?</p>
   <p>да</p>
   <p><strong>ПОЯСНЕНИЕ:</strong></p>
   <p>Спасибо за то, что Вы нашли время, чтобы помочь этому исследованию. На самом деле, это исследование не имеет ничего общего с мексиканской едой. Это исследование ночного недержания мочи. Мексиканская еда присутствовала только затем, чтобы усыпить Вашу бдительность в надежде, что Вы будете отвечать более правдиво. Ещё раз спасибо. false</p>
   <p>Это была довольно длинная программа со многими повторениями. (Все разделы программы с вопросами о мексиканской еде были одинаковыми, а вопрос о недержании мочи отличался совсем немного.) Повторение – это нехорошая штука. И всё же, мы не можем поместить его в один большой цикл или итератор, поскольку иногда нам нужно кое-что сделать между вопросами. В подобных ситуациях лучше всего написать метод. Вот так:</p>
   <p><code>def sayMoo # скажи: «Му» puts 'мууууууу…' end</code></p>
   <p>Ээ… наша программа не выполняет sayMoo. Почему же? Потому что мы не сказали ей это делать. Мы сказали ей, как мычать методом sayMoo, но мы фактически так и не сказали ей сделать это. Давайте попытаемся по-другому:</p>
   <p><code>def sayMoo # скажи: «Му'</code></p>
   <p><code>puts 'мууууууу…' end</code></p>
   <p><code>sayMoo</code></p>
   <p><code>sayMoo</code></p>
   <p><code>puts 'куан–куан'</code></p>
   <p><code>sayMoo</code></p>
   <p><code>sayMoo</code></p>
   <p><code>мууууууу…</code></p>
   <p><code>мууууууу…</code></p>
   <p><code>куан–куан</code></p>
   <p><code>мууууууу…</code></p>
   <p><code>мууууууу…</code></p>
   <empty-line/>
   <p>Ааа, гораздо лучше. (Если вы не говорите по-французски, поясняю: в середине программы была французская утка. Во Франции утки говорят: «куан-куан».)</p>
   <p>Итак, с помощью def мы определили метод sayMoo. (Имена методов, как и имена переменных, начинаются со строчной буквы. Есть, однако, несколько исключений таких, как + или ==.) Но разве методы не должны всегда ассоциироваться с объектами? Ну да, должны, и в этом случае (как и в случаях с puts и gets) метод просто ассоциируется с объектом, представляющим всю программу. В следующей главе мы увидим, как добавлять методы к другим объектам. Но сначала…</p>
   <subtitle>Параметры метода</subtitle>
   <p>Вы, должно быть, заметили, что некоторые методы (такие, как gets, to_s, reverse… ) просто вызываются у какого-нибудь объекта. Однако, другие методы (такие, как +, -, puts…) принимают параметры для указания объекту, как выполнять метод. Например, вы не скажете просто 5+, правда? Этим вы говорите числу 5 прибавить, но не говорите ему что прибавить.</p>
   <p>Чтобы определить параметр для метода sayMoo (скажем, количество мычаний), мы должны сделать так:</p>
   <p><code>def sayMoo numberOfMoos</code></p>
   <p><code>puts 'мууууууу…'*numberOfMoos end</code></p>
   <p><code>sayMoo 3 puts 'хрю-хрю'</code></p>
   <p><code>sayMoo # Это должно вызвать ошибку, потому что параметр отсутствует.</code></p>
   <p>мууууууу…мууууууу…мууууууу… хрю–хрю</p>
   <p><code>#&lt;ArgumentError: wrong number of arguments (0 for 1)&gt;</code></p>
   <p>(#&lt;Ошибка аргументов: неверное число аргументов (0 вместо 1)&gt;— <emphasis>Прим. перев.</emphasis>]</p>
   <p><code>numberOfMoos – это переменная, которая указывает на параметр, переданный в метод. Я повторю это ещё раз, хотя это всё равно звучит немного запутанно: numberOfMoos – это переменная, которая указывает на параметр, переданный в метод. Так, если я напишу sayMoo 3, то параметр равен 3, а переменная numberOfMoos указывает на 3.</code></p>
   <p>Как видите, параметр теперь обязателен. В конце концов, каким образом sayMoo должен повторять 'мууууууу…', если вы не передадите ему параметр? Ваш бедный компьютер не сообразит.</p>
   <p>Если объекты в Ruby подобны существительным в английском языке, а методы подобны глаголам, то вы можете думать о параметрах, как о наречиях (как в случае с sayMoo, где параметр говорит нам как выполнить sayMoo) или иногда, как о прямом дополнении (как в случае с puts, где параметр – это то, что выводится через puts).</p>
   <p>Локальные переменные В следующей программе имеется две переменные:</p>
   <p><code>def doubleThis num numTimes2 = num*2</code></p>
   <p><code>puts num.to_s+' дважды будет '+numTimes2.to_s end</code></p>
   <p><code>doubleThis 44</code></p>
   <p><code>44 дважды будет 88</code></p>
   <empty-line/>
   <p>Переменные – это пит и numTimes2. Обе они расположены внутри метода doubleThis. Эти (и все другие переменные, которые вы видели до сих пор) являются локальными переменными. Это означает, что они «живут» внутри метода и недоступны снаружи. А если вы попытаетесь выполнить следующий код, вам будет выдана ошибка:</p>
   <p><code>def doubleThis num numTimes2 = num*2</code></p>
   <p><code>puts num.to_s+' дважды будет '+numTimes2.to_s end</code></p>
   <p><code>doubleThis 44 puts numTimes2.to_s 44 дважды будет 88</code></p>
   <p><code>#&lt;NameError: undefined local variable or method 'numTimes2' for #&lt;StringI0:0x82ba924&gt;&gt;</code></p>
   <p>[#&lt;Ошибка имени: неопределённая локальная переменная или метод 'numTimes2' для #&lt;StringIO: 0x82ba924&gt;&gt; – <emphasis>Прим. перев.</emphasis>]</p>
   <p>Неопределённая локальная переменная… Фактически, мы определили эту локальную переменную, но она не является локальной там, где мы попытались её использовать; она локальная внутри метода.</p>
   <p>Это может показаться неудобным, но на самом деле это очень даже приятно. Хотя это означает, что у вас нет доступа к переменным внутри методов, это также означает, что у них нет доступа к вашим переменным, и, таким образом, их нельзя испортить:</p>
   <p><code>def littlePest var var = nil</code></p>
   <p><code>puts 'ХА–ХА! Я уничтожил твою переменную!' end</code></p>
   <p><code>var = 'Ты не можешь даже притронуться к моей переменной!' littlePest var puts var</code></p>
   <p>ХА-ХА! Я уничтожил твою переменную!</p>
   <p>Ты не можешь даже притронуться к моей переменной!</p>
   <p>Фактически, в этой маленькой программе две переменные var, а именно: та, что внутри метода littlePest, и та, что вне его. Когда мы вызвали littlePest var, мы в действительности просто передали строку из одной переменной var в другую так, что обе указывали на одну и ту же строку. Затем в методе littlePest его собственная локальная var стала указывать на nil, но это не повлияло на var вне метода.</p>
   <p>Возвращаемые значения</p>
   <p>Должно быть, вы заметили, что некоторые методы возвращают вам что-нибудь, когда вы их вызываете. Например, gets возвращает строку (ту строку, что вы ввели с клавиатуры), а метод + в выражении 5+3, (а это на самом деле 5. + (3)) возвращает 8. Арифметические методы чисел возвращают числа, а арифметические методы строк возвращают строки.</p>
   <p>Важно понять отличие между методами, возвращающими значение туда, где этот метод был вызван, и выводом вашей программой информации на экран монитора, как</p>
   <p>А что же тогда возвращает puts? Мы никогда до этого не задумывались об этом, но давайте взглянем сейчас:</p>
   <empty-line/>
   <p><code>returnVal = puts puts returnVal</code></p>
   <p><code>'Это вернул метод puts:'</code></p>
   <p><code>Это вернул метод nil</code></p>
   <p><code>puts:</code></p>
   <empty-line/>
   <p>Итак, первый puts вернул nil. И хотя мы этого не проверяли, второй puts вернул то же; puts всегда возвращает nil. Каждый метод должен возвращать что-нибудь, даже если это просто nil.</p>
   <p>Прервитесь ненадолго и напишите программу, чтобы выяснить, что же возвращает sayMoo.</p>
   <p>Вы удивлены? Хорошо, вот как это всё работает: значение, возвращаемое из метода,</p>
   <p><code>– это просто значение последней строки метода. В случае с sayMoo это означает, что он возвращает puts 'мууууууу… '*numberOfMoos, то есть просто nil, поскольку puts всегда возвращает nil. Если бы мы хотели, чтобы все наши методы возвращали строку 'жёлтая подводная лодка', нам бы просто нужно было поместить это в конце каждого из них:</code></p>
   <p><code>def sayMoo numberOfMoos</code></p>
   <p><code>puts 'мууууууу…'*numberOfMoos 'жёлтая подводная лодка' end</code></p>
   <p><code>x = sayMoo 2 puts x</code></p>
   <p>мууууууу…мууууууу… жёлтая подводная лодка</p>
   <empty-line/>
   <p>Итак, давайте снова вернёмся к нашему психологическому исследованию, но на этот раз мы напишем метод, который будет задавать для нас вопросы. Нужно, чтобы он принимал вопрос в качестве параметра и возвращал true, если ответ был да, или false, если ответ был нет. (Даже если в большинстве случаев мы просто игнорируем ответ, всё равно это неплохая идея, чтобы наш метод возвращал результат. Поступая так, мы сможем использовать его и для вопроса о ночном недержании.) Я также собираюсь сократить приветствие и пояснение просто для того, чтобы программу было легче читать:</p>
   <empty-line/>
   <p><code>def ask question # задать вопрос</code></p>
   <p><code>goodAnswer = false</code></p>
   <p><code>while (not goodAnswer)</code></p>
   <p><code>puts question</code></p>
   <p><code>reply = gets.chomp.downcase</code></p>
   <empty-line/>
   <p><code>if (reply == 'да' or reply == 'нет</code></p>
   <p><code>)</code></p>
   <p><code>goodAnswer = true</code></p>
   <p><code>if reply == 'да'</code></p>
   <p><code>answer = true</code></p>
   <p><code>else</code></p>
   <p><code>answer = false</code></p>
   <p><code>end</code></p>
   <p><code>else</code></p>
   <p><code>puts 'Пожалуйста, отвечайте «да»</code></p>
   <p><code>или «нет».'</code></p>
   <p><code>end</code></p>
   <p><code>end</code></p>
   <empty-line/>
   <p><code>answer # Это то, что мы возвращаем</code></p>
   <p><code>(true или false).</code></p>
   <p><code>end</code></p>
   <p><code>puts 'Здравствуйте! И спасибо, что Вы.</code></p>
   <p><code>puts</code></p>
   <p><code>ask 'Вам нравится есть такос?' # Мы игнорируем возвращаемое значение.</code></p>
   <p><code>ask 'Вам нравится есть бурритос?'</code></p>
   <p><code>wetsBed = ask 'Вы мочитесь в постель?' значение.</code></p>
   <p><code># Мы сохраняем возвращаемое</code></p>
   <p><code>ask 'Вам нравится есть чимичангас?'</code></p>
   <p><code>ask 'Вам нравится есть сопапиллас?'</code></p>
   <p><code>ask 'Вам нравится есть тамалес?'</code></p>
   <p><code>puts 'И ещё несколько вопросов…'</code></p>
   <p><code>ask 'Вам нравится пить хорчата?'</code></p>
   <p><code>ask 'Вам нравится есть флаутас?'</code></p>
   <p><code>puts</code></p>
   <p><code>puts 'Спасибо за то…'</code></p>
   <p><code>puts</code></p>
   <p><code>puts wetsBed</code></p>
   <p><code>Здравствуйте! И спасибо, что Вы…</code></p>
   <p><code>Вам нравится есть такое?</code></p>
   <p><code>да</code></p>
   <p><code>Вам нравится есть бурритос?</code></p>
   <p><code>да</code></p>
   <p><code>Вы мочитесь в постель?</code></p>
   <p><code>никогда!</code></p>
   <p><code>Пожалуйста, отвечайте «да» или «нет».</code></p>
   <p><code>Вы мочитесь в постель?</code></p>
   <p><code>нет</code></p>
   <p><code>Вам нравится есть чимичангас?</code></p>
   <p><code>да</code></p>
   <p><code>Вам нравится есть сопапиллас?</code></p>
   <p><code>да</code></p>
   <p><code>Вам нравится есть тамалес?</code></p>
   <p><code>да</code></p>
   <p><code>И ещё несколько вопросов…</code></p>
   <p><code>Вам нравится пить хорчата?</code></p>
   <p><code>да</code></p>
   <p><code>Вам нравится есть флаутас?</code></p>
   <p><code>да</code></p>
   <p><strong>ПОЯСНЕНИЕ:</strong></p>
   <p>Спасибо за то… false</p>
   <p>Неплохо, а? Мы смогли добавить больше вопросов (ведь добавлять вопросы теперь легко), но наша программа к тому же ещё и стала немного короче! Это значительное усовершенствование – мечта каждого ленивого программиста.</p>
   <p>Думаю, было бы очень полезно привести ещё один пример метода. Мы назовём его englishNumber. Он будет принимать число, например, 22, и возвращать его английское название (в данном случае, строку 'twenty–two'). Для начала, пусть он работает только с целыми числами от 0 до 100.</p>
   <p>(ПРИМЕЧАНИЕ: Этот метод использует новую хитрость для преждевременного возврата из метода с помощью ключевого слова return, а также представляет новый поворот в ветвлении: elsif. Из контекста должно быть ясно, как они работают.)</p>
   <p><code>def englishNumber number</code></p>
   <p><code># Нам нужны только числа в диапазоне 0-100. if number &lt; 0</code></p>
   <p><code>return 'Пожалуйста, введите число ноль или больше.' end</code></p>
   <p><code>if number &gt; 100</code></p>
   <p><code>return 'Пожалуйста, введите число 100 или меньше.' end</code></p>
   <p><code>numString = '' # Эту строку мы будем возвращать.</code></p>
   <p><code># «left» – сколько от числа нам ещё осталось вывести.</code></p>
   <p><code># «write» – часть числа, которую мы выводим сейчас.</code></p>
   <p><code># write и left… поняли? :) left = number</code></p>
   <p><code>write = left/100 # Сколько сотен осталось вывести?</code></p>
   <p><code>left = left – write*100 # Вычтем эти сотни.</code></p>
   <p><code>if write &gt; 0</code></p>
   <p><code>return 'one hundred'</code></p>
   <p><code>end</code></p>
   <p><code>write = left/10</code></p>
   <p><code>#</code></p>
   <p><code>Сколько десятков осталось вывести?</code></p>
   <p><code>left = left – write*10</code></p>
   <p><code>#</code></p>
   <p><code>Вычтем эти десятки.</code></p>
   <p><code>if write &gt; 0</code></p>
   <p><code>if write == 1 # Охо-хо…</code></p>
   <p><code># Поскольку мы не можем вывести «tenty–two» вместо «twelve»,</code></p>
   <p><code># нам нужно сделать особые исключения для них. if left == 0</code></p>
   <p><code>numString = numString + 'ten' elsif left == 1</code></p>
   <p><code>numString = numString + 'eleven' elsif left == 2</code></p>
   <p><code>numString = numString + 'twelve' elsif left == 3</code></p>
   <p><code>numString = numString + 'thirteen' elsif left == 4</code></p>
   <p><code>numString = numString + 'fourteen' elsif left == 5</code></p>
   <p><code>numString = numString + 'fifteen' elsif left == 6</code></p>
   <p><code>numString = numString + 'sixteen' elsif left == 7</code></p>
   <p><code>numString = numString + 'seventeen' elsif left == 8</code></p>
   <p><code>numString = numString + 'eighteen' elsif left == 9</code></p>
   <p><code>numString = numString + 'nineteen' end</code></p>
   <p><code># Поскольку уже мы позаботились о цифре для единиц,</code></p>
   <p><code># нам не осталось ничего для вывода. left = 0</code></p>
   <p><code>elsif write == 2</code></p>
   <p><code>numString = numString + 'twenty' elsif write == 3</code></p>
   <p><code>numString</code></p>
   <p><code>= numString + 'thirty'</code></p>
   <p><code>elsif write</code></p>
   <p><code>= = 4</code></p>
   <p><code>numString</code></p>
   <p><code>= numString + 'forty'</code></p>
   <p><code>elsif write</code></p>
   <p><code>= = 5</code></p>
   <p><code>numString</code></p>
   <p><code>= numString + 'fifty'</code></p>
   <p><code>elsif write</code></p>
   <p><code>= = 6</code></p>
   <p><code>numString</code></p>
   <p><code>= numString + 'sixty'</code></p>
   <p><code>elsif write</code></p>
   <p><code>= = 7</code></p>
   <p><code>numString</code></p>
   <p><code>= numString + 'seventy'</code></p>
   <p><code>elsif write</code></p>
   <p><code>= = 8</code></p>
   <p><code>numString</code></p>
   <p><code>= numString + 'eighty'</code></p>
   <p><code>elsif write</code></p>
   <p><code>= = 9</code></p>
   <p><code>numString</code></p>
   <p><code>= numString + 'ninety'</code></p>
   <p><code>end</code></p>
   <empty-line/>
   <p><code>if left &gt; 0</code></p>
   <p><code>numString</code></p>
   <p><code>= numString + '–'</code></p>
   <p><code>end</code></p>
   <p><code>end</code></p>
   <empty-line/>
   <p><code>write = left</code></p>
   <p><code># Сколько единиц осталось вывести?</code></p>
   <p><code>left = 0</code></p>
   <p><code># Вычтем эти единицы.</code></p>
   <p><code>if write &gt; 0</code></p>
   <p><code>if write</code></p>
   <p><code>= = 1</code></p>
   <p><code>numString</code></p>
   <p><code>= numString + 'one'</code></p>
   <p><code>elsif write</code></p>
   <p><code>= = 2</code></p>
   <p><code>numString</code></p>
   <p><code>= numString + 'two'</code></p>
   <p><code>elsif write</code></p>
   <p><code>= = 3</code></p>
   <p><code>numString</code></p>
   <p><code>= numString + 'three'</code></p>
   <p><code>elsif write</code></p>
   <p><code>= = 4</code></p>
   <p><code>numString</code></p>
   <p><code>= numString + 'four'</code></p>
   <p><code>elsif write ==</code></p>
   <p><code>5</code></p>
   <p><code>numString = numString + 'five'</code></p>
   <p><code>elsif write ==</code></p>
   <p><code>6</code></p>
   <p><code>numString = numString + 'six'</code></p>
   <p><code>elsif write ==</code></p>
   <p><code>7</code></p>
   <p><code>numString = numString + 'seven'</code></p>
   <p><code>elsif write ==</code></p>
   <p><code>8</code></p>
   <p><code>numString = numString + 'eight'</code></p>
   <p><code>elsif write ==</code></p>
   <p><code>9</code></p>
   <p><code>numString = numString + 'nine'</code></p>
   <p><code>end</code></p>
   <p><code>end</code></p>
   <p><code>if</code></p>
   <p><code>numString == '</code></p>
   <p><code>'</code></p>
   <p><code># Только в одном случае «numString» может быть пустой -</code></p>
   <p><code># если «number</code></p>
   <p><code>” равно 0.</code></p>
   <p><code>return 'zero'</code></p>
   <p><code>end</code></p>
   <p><code>#</code></p>
   <p><code>Если мы дошли</code></p>
   <p><code>досюда, то у нас имеется число где-то</code></p>
   <p><code>#</code></p>
   <p><code>между 0 и 100,</code></p>
   <p><code>поэтому нам нужно вернуть «numString».</code></p>
   <p><code>numString</code></p>
   <p><code>end</code></p>
   <p><code>puts</code></p>
   <p><code>englishNumber(</code></p>
   <p><code>0)</code></p>
   <p><code>puts</code></p>
   <p><code>englishNumber(</code></p>
   <p><code>9)</code></p>
   <p><code>puts</code></p>
   <p><code>englishNumber(</code></p>
   <p><code>10)</code></p>
   <p><code>puts</code></p>
   <p><code>englishNumber(</code></p>
   <p><code>11)</code></p>
   <p><code>puts</code></p>
   <p><code>englishNumber(</code></p>
   <p><code>17)</code></p>
   <p><code>puts</code></p>
   <p><code>englishNumber(</code></p>
   <p><code>32)</code></p>
   <p><code>puts</code></p>
   <p><code>englishNumber(</code></p>
   <p><code>88)</code></p>
   <p><code>puts</code></p>
   <p><code>englishNumber(</code></p>
   <p><code>99)</code></p>
   <p><code>puts</code></p>
   <p><code>englishNumber(100)</code></p>
   <empty-line/>
   <p><code>zero</code></p>
   <p><code>nine</code></p>
   <p><code>ten</code></p>
   <p><code>eleven</code></p>
   <p><code>seventeen</code></p>
   <p><code>thirty-two</code></p>
   <p><code>eighty-eight</code></p>
   <p><code>ninety-nine</code></p>
   <p><code>one hundred</code></p>
   <p>И всё-таки, определённо имеется несколько моментов в этой программе, которые мне не нравятся. Во-первых, в ней слишком много повторений. Во-вторых, она не обрабатывает числа больше 100. В-третьих, в ней слишком много особых случаев, слишком много возвратов по return. Давайте используем несколько массивов и попробуем её немного подчистить:</p>
   <p><code>def englishNumber number</code></p>
   <p><code>if number &lt; 0 # Без отрицательных чисел.</code></p>
   <p><code>return 'Пожалуйста, введите неотрицательное число.'</code></p>
   <p><code>end</code></p>
   <p><code>if number == 0</code></p>
   <p><code>return 'zero'</code></p>
   <p><code>end</code></p>
   <empty-line/>
   <p><code># Больше нет особых случаев! Больше нет возвратов по return!</code></p>
   <empty-line/>
   <p><code>numString = '' # Эту строку мы будем возвращать.</code></p>
   <p><code># единицы</code></p>
   <p><code>onesPlace =['one', 'two', 'three', 'four', '</code></p>
   <p><code>five',</code></p>
   <p><code>'six', 'seven', 'eight', 'nine']</code></p>
   <p><code># десятки</code></p>
   <p><code>tensPlace =['ten', 'twenty', 'thirty', 'forty',</code></p>
   <p><code>'fifty',</code></p>
   <p><code>'sixty', 'seventy', 'eighty', 'ninety']</code></p>
   <p><code>teenagers =['eleven', 'twelve', 'thirteen', 'fourteen',</code></p>
   <p><code>'fifteen',</code></p>
   <p><code># «left» – сколько от числа нам ещё осталось вывести.</code></p>
   <p><code># «write» – часть числа, которую мы выводим сейчас.</code></p>
   <p><code># write и left… поняли? :) left = number</code></p>
   <p><code>write = left/ЮО # Сколько сотен осталось вывести?</code></p>
   <p><code>left = left – write*100 # Вычтем эти сотни.</code></p>
   <p><code>if write &gt; О</code></p>
   <p><code># Вот здесь действительно хитрый фокус: hundreds = englishNumber write</code></p>
   <p><code>numString = numString + hundreds + ' hundred'</code></p>
   <p><code># Это называется «рекурсия». Так что же я только что сделал?</code></p>
   <p><code># Я велел этому методу вызвать себя, но с параметром «write» вместо</code></p>
   <p><code># «number». Помните, что «write» это (в настоящий момент) число</code></p>
   <p><code># сотен, которые нужно вывести. Прибавив «hundreds» к «numString»,</code></p>
   <p><code># мы добавляем после неё строку ' hundred'. Так, например, если</code></p>
   <p><code># мы сначала вызвали englishNumber с 1999 (т.е. «number» = 1999),</code></p>
   <p><code># затем в этой точке «write» будет равен 19, а «left» равен 99.</code></p>
   <p><code># Наиболее лениво в этом месте было бы заставить englishNumber</code></p>
   <p><code># вывести нам 'nineteen', а затем мы выведем ' hundred',</code></p>
   <p><code># и потом оставшаяся часть englishNumber выведет 'ninety–nine'.</code></p>
   <p><code>if left &gt; О</code></p>
   <p><code># Так, мы не выводим 'two hundredfifty-one'… numString = numString + ' ' end end</code></p>
   <p><code>write = left/Ю # Сколько десятков осталось вывести?</code></p>
   <p><code>left = left – write*10 # Вычтем эти десятки.</code></p>
   <p><code>numString</code></p>
   <p><code>end</code></p>
   <p><code>puts</code></p>
   <p><code>englishNumber(</code></p>
   <p><code>0)</code></p>
   <p><code>puts</code></p>
   <p><code>englishNumber(</code></p>
   <p><code>9)</code></p>
   <p><code>puts</code></p>
   <p><code>englishNumber(</code></p>
   <p><code>10)</code></p>
   <p><code>puts</code></p>
   <p><code>englishNumber(</code></p>
   <p><code>11)</code></p>
   <p><code>puts</code></p>
   <p><code>englishNumber(</code></p>
   <p><code>17)</code></p>
   <p><code>puts</code></p>
   <p><code>englishNumber(</code></p>
   <p><code>32)</code></p>
   <p><code>puts</code></p>
   <p><code>englishNumber(</code></p>
   <p><code>88)</code></p>
   <p><code>puts</code></p>
   <p><code>englishNumber(</code></p>
   <p><code>99)</code></p>
   <p><code>puts</code></p>
   <p><code>englishNumber(100)</code></p>
   <p><code>puts</code></p>
   <p><code>englishNumber(101)</code></p>
   <p><code>puts</code></p>
   <p><code>englishNumber(234)</code></p>
   <p><code>puts</code></p>
   <p><code>englishNumber(3211)</code></p>
   <p><code>puts</code></p>
   <p><code>englishNumber(999999)</code></p>
   <p><code>puts</code></p>
   <p><code>englishNumber(1000000000000)</code></p>
   <empty-line/>
   <p><code>zero</code></p>
   <p><code>nine</code></p>
   <p><code>ten</code></p>
   <p><code>eleven</code></p>
   <p><code>seventeen</code></p>
   <p><code>thirty-two</code></p>
   <p><code>eighty-eight</code></p>
   <p><code>ninety-nine</code></p>
   <p><code>one hundred</code></p>
   <p><code>one hundred one</code></p>
   <p><code>two hundred thirty-four</code></p>
   <p><code>thirty-two hundred eleven</code></p>
   <p><code>ninety-nine hundred ninety-nine hundred ninety-nine one hundred hundred hundred hundred hundred hundred</code></p>
   <empty-line/>
   <p>Ааааа…. Это гораздо, гораздо лучше. Программа довольно компактная, вот почему я добавил в неё так много комментариев. Она даже работает с большими числами… хотя не совсем так хорошо, как можно было надеяться. Например, я полагаю, для последнего числа было бы гораздо лучше вернуть значение 'one trillion', или даже 'one million million' (хотя все три значения правильные). В сущности, вы можете сделать это прямо сейчас…</p>
   <empty-line/>
   <p><strong>Попробуйте ещё кое-что</strong></p>
   <p>• Доработайте englishNumber. Во-первых, добавьте тысячи. Так она должна возвращать ' one thousand ' вместо ' ten hundred ', а также ' ten thousand ' вместо 'one hundred hundred'.</p>
   <p>• Ещё доработайте englishNumber. Теперь добавьте миллионы, чтобы вам возвращалось ' one million ' вместо ' one thousand thousand '. Затем попробуйте добавить миллиарды и триллионы. Насколько далеко вы сможете зайти?</p>
   <p>• А как насчёт weddingNumber? Она должна работать почти также, как englishNumber, но только она должна вставлять повсюду слово «and», возвращая что-то наподобие ' nineteen hundred and seventy and two ', или как там это должно выглядеть в приглашениях на свадьбу? Я бы привёл вам больше примеров, но я сам не совсем это понимаю. Вам возможно, понадобится обратиться за помощью к устроителю свадеб.</p>
   <p>• «Девяносто девять бутылок пива…” Используя englishNumber и вашу старую программу, напечатайте стихи этой песни, на этот раз правильно. Накажите ваш компьютер: пусть она начнётся с 9999. (Однако не задавайте слишком большое число, так как выводить всё это на экран займёт у компьютера достаточно много времени. Сто тысяч бутылок пива занимает приличное время; а если вы зададите миллион, вы накажете и себя тоже!</p>
   <p>Мои поздравления! К этому моменту, вы стали настоящим программистом! Вы изучили всё, что нужно, чтобы составлять огромные программы с чистого листа. Если у вас есть идеи, какие бы программы вы сами хотели бы написать, попробуйте воплотить их!</p>
   <p>Конечно, составлять всё с чистого листа может оказаться довольно медленным процессом. Зачем же тратить время на написание кода, который кто-то уже написал? Вы бы хотели, чтоб ваша программа оправляла электронную почту? Вы бы хотели сохранять и загружать файлы на свой компьютер? А как насчёт генерирования web- страниц для учебника, где примеры кода в самом деле выполняются каждый раз, когда загружается страница? ;) В Ruby есть много различных видов объектов, которые мы можем использовать и которые помогут нам писать программы лучше и быстрее.</p>
  </section>
  <section>
   <title>
    <p>9. Классы</p>
   </title>
   <p>До сих пор мы видели несколько различных видов, или классов, объектов: строки, целые числа, дробные числа, массивы, а также несколько особых объектов (true, false и nil), о которых мы поговорим позже. В Ruby эти классы всегда записываются с заглавной буквы: String, Integer, Float, Array… и т. д. В общем случае, если мы хотим создать новый объект определённого класса, мы используем new:</p>
   <empty-line/>
   <p><code>a = Array.</code></p>
   <p><code>new +</code></p>
   <p><code>[12345]</code></p>
   <p><code>#</code></p>
   <p><code>Сложение</code></p>
   <p><code>массивов.</code></p>
   <p><code>b = String</code></p>
   <p><code>. new +</code></p>
   <p><code>'hello'</code></p>
   <p><code>#</code></p>
   <p><code>Сложение</code></p>
   <p><code>строк.</code></p>
   <empty-line/>
   <p><code>c = Time.new</code></p>
   <p><code>puts 'a =</code></p>
   <p><code>'+a.to</code></p>
   <p><code>s</code></p>
   <p><code>puts 'b =</code></p>
   <p><code>1 o t <sub>b</sub>. +</code></p>
   <p><code>s</code></p>
   <p><code>puts 'c =</code></p>
   <p><code>'+c.to</code></p>
   <p><code>s</code></p>
   <p><code>a = 12345 b = hello</code></p>
   <p><code>c = Wed Jun 28 02:11:24 GMT 2006</code></p>
   <p>Так как мы можем создавать массивы и строки с помощью[…] и '…' соответственно, мы редко создаём их с помощью new. (Хотя это и не совсем очевидно из предыдущего примера, String.new создаёт пустую строку, а Array.new создаёт пустой массив.) Кроме того, числа являются особыми исключениями: вы не можете создать целое число с помощью Integer.new. Вам придётся просто записать число.</p>
   <p><code>Класс TIME</code></p>
   <p>И что же особенного в этом классе Time? Объекты класса Time представляют моменты времени. Вы можете прибавлять числа к (или вычитать из) объектов времени, чтобы получить новые моменты времени: прибавление 1.5 к моменту времени создаст новый момент, который на полторы секунды позже первого:</p>
   <empty-line/>
   <p><code>time = Time.new</code></p>
   <p><code>#</code></p>
   <p><code>Момент, когда вы получили эту web–страницу.</code></p>
   <p><code>time2 = time + 60</code></p>
   <p><code>#</code></p>
   <p><code>Одной минутой позже.</code></p>
   <p><code>puts time</code></p>
   <p><code>puts time2</code></p>
   <empty-line/>
   <p><code>Wed</code></p>
   <p><code>Jun</code></p>
   <p><code>28</code></p>
   <p><code>02</code></p>
   <p><code>4 2 <sub>1</sub> <sub>1</sub></code></p>
   <p><code>GMT</code></p>
   <p><code>2006</code></p>
   <p><code>Wed</code></p>
   <p><code>Jun</code></p>
   <p><code>28</code></p>
   <p><code>02</code></p>
   <p><code>12:24</code></p>
   <p><code>GMT</code></p>
   <p><code>2006</code></p>
   <p>Вы также можете создавать объект времени, соответствующий определённому моменту, используя т^е.тк-^те:</p>
   <p><code>puts</code></p>
   <p><code>Time.mktime(2000,</code></p>
   <p><code>1,</code></p>
   <p><code>1)</code></p>
   <p><code># Двухтысячный год (Y2K).</code></p>
   <p><code>puts</code></p>
   <p><code>Time.mktime(1976,</code></p>
   <p><code>8,</code></p>
   <p><code>3, 10, 11)</code></p>
   <p><code># Когда я родился.</code></p>
   <p><code>Sat</code></p>
   <p><code>Jan</code></p>
   <p><code>01</code></p>
   <p><code>00:00:00</code></p>
   <p><code>GMT</code></p>
   <p><code>2000</code></p>
   <p><code>Tue</code></p>
   <p><code>u &lt;</code></p>
   <p><code>3 0</code></p>
   <p><code>10:11:00</code></p>
   <p><code>T M G</code></p>
   <p><code>6 7 9 <sub>1</sub></code></p>
   <p>Обратите внимание: момент моего рождения задан по Тихоокеанскому летнему времени (Pacific Daylight Savings Time, PDT). Хотя, когда наступил 2000-й год, было Тихоокеанское стандартное время (Pacific Standard Time, PST), по крайней мере для нас, жителей Западного берега. Скобки здесь нужны, чтобы сгруппировать параметры метода mktime. Чем больше параметров вы указываете, тем более точным становится ваше время.</p>
   <p>Вы можете сравнивать время с помощью методов сравнения (более раннее время меньше, чем более позднее время), а если вы вычтете одно время из другого, вы получите разницу между ними в секундах. Поиграйте с этим немного!</p>
   <p>Попробуйте ещё кое-что</p>
   <p>• Один миллиард секунд… Выясните точно, в какую секунду вы родились (если сможете). Вычислите, когда вы достигнете (или, возможно, уже достигли?) возраста в один миллиард секунд. А потом отметьте это в вашем календаре.</p>
   <p>• С днём рождения! Спросите, в каком году человек родился, затем в каком месяце, потом в какой день. Вычислите, сколько ему лет, и выдайте ему большой ХЛОП! на каждый его день рождения.</p>
   <p>Класс Hash</p>
   <p>Другой полезный класс – это класс Hash. Хэши во многом похожи на массивы: в них имеется набор слотов, которые могут указывать на различные объекты. Однако в массиве слоты выстроены в ряд, и каждый из них пронумерован (начиная с нуля). В хэше слоты не располагаются подряд (они просто как-то беспорядочно свалены вместе), и вы можете использовать для обращения к слоту любой объект, а не только число. Использовать хэши хорошо тогда, когда у вас есть набор каких-нибудь вещей, которые вы хотите обрабатывать, но они совсем не укладываются в нумерованный список. Например, цвета, которые я использую для различных частей кода, положенного в основу этого учебника:</p>
   <p><code>colorArray =</code></p>
   <p><code>[]</code></p>
   <p><code># то же, что Array.new</code></p>
   <p><code>colorHash =</code></p>
   <p><code>{ }</code></p>
   <p><code># то же, что Hash.new</code></p>
   <p><code>colorArray[0]</code></p>
   <p><code>= 'красный'</code></p>
   <p><code>colorArray[1]</code></p>
   <p><code>= 'зелёный'</code></p>
   <p><code>colorHash['строки']</code></p>
   <p><code>colorHash['числа']</code></p>
   <p><code>colorHash['^Ki4eBbie слова'] = 'синий' colorArray.each do |color| puts color end</code></p>
   <p><code>colorHash.each do |codeType, color| puts codeType + ': ' + color end</code></p>
   <empty-line/>
   <p>красный</p>
   <p>зелёный</p>
   <p>синий</p>
   <empty-line/>
   <p>строки: красный ключевые слова: синий числа: зелёный</p>
   <p>Если я использую массив, мне нужно помнить, что слот 0 предназначен для строк, слот 1 – для чисел и т. д. Но если я использую хэш, то всё просто! Слот 'строки', конечно, содержит цвет строк. Ничего не нужно запоминать. Вы, должно быть, заметили, что когда мы применяли each, объекты из хэша выдавались не в том порядке, в котором мы их в него помещали. (По крайней мере, так было, когда я это писал. Возможно, сейчас будет по-другому… С этими хэшами никогда ничего не знаешь наперёд.) Для содержания чего-то в определённом порядке предназначены массивы, а не хэши.</p>
   <p>Хотя для именования слотов в хэше обычно используются строки, вы могли бы использовать объект любого типа, даже массивы и другие хэши (хотя не могу представить себе, зачем бы вам захотелось это делать…):</p>
   <p><code>weirdHash = Hash.new weirdHash[12] = 'обезьян' weirdHash[[]] = 'пустота'</code></p>
   <p><code>weirdHash[Time.new] = 'текущее время и никакое другое'</code></p>
   <p>Хэши и массивы хороши для разных применений; вам решать, что из них лучше всего подходит для конкретной задачи.</p>
   <p>В конце предыдущей главы вы написали метод, выдающий английскую фразу для заданного целого числа. Однако, это не был метод целых чисел; это был просто метод «программы вообще». Но разве не было бы прекрасно, если вы могли бы написать что- то вроде 22. – Ьо_епд вместо englishNumber 22? Вот как вы бы это сделали:</p>
   <p><code>Ну вот, я его протестировал; кажется, он работает. ;)</code></p>
   <p>Вот так мы определили метод для целых чисел: «заскочили» в класс Integer, описали там метод и «выскочили» из него обратно. Теперь у всех целых чисел есть этот (хотя и немного недоделанный) метод. Фактически, если вам не нравится, как работает какой- нибудь встроенный метод, например to_s, вы могли бы просто переопределить его примерно таким же образом… но я не советую это делать! Лучше всего оставить старые методы в покое и создавать новые, когда вам хочется сделать что-нибудь новенькое.</p>
   <p>Ну что… всё ещё непонятно? Давайте, я ещё раз пройдусь по последней программе. До сих пор, когда мы выполняли какой-нибудь код или определяли какие-то методы, мы делали это в объекте по умолчанию под названием «программа». В нашей последней программе мы впервые покинули этот объект и проникли в класс Integer. Мы определили в нём метод (поэтому он стал методом для целых чисел), и все целые числа могут его использовать. Внутри этого метода мы использовали self, чтобы ссылаться на объект (целое число), использующий этот метод.</p>
   <p>Создание классов</p>
   <p>Мы уже видели достаточно много объектов различных классов. Однако, легко предоставить себе такие объекты, которых в Ruby нет. К счастью, создать новый класс так же просто, как расширить существующий. Скажем, мы бы хотели сделать на Ruby игральные кости. Вот как мы могли бы создать класс Die:</p>
   <empty-line/>
   <p><code>class Die # игральная кость def roll</code></p>
   <p><code>1 + rand(6) end</code></p>
   <p><code>end</code></p>
   <p><code># Давайте создадим пару игральных костей… dice =[Die.new, Die.new]</code></p>
   <p><code># …и бросим их. dice.each do |die|</code></p>
   <p><code>puts die.roll end</code></p>
   <p><code>5</code></p>
   <p><code>6</code></p>
   <empty-line/>
   <p>(Если вы пропустили раздел о случайных числах: rand(6) просто возвращает случайное число между 0 и 5.)</p>
   <p>Вот так! Наши собственноручно созданные объекты. Бросьте кости несколько раз (нажимая на кнопку «Обновить») и понаблюдайте, что при этом появится.</p>
   <p>Мы можем определить для наших объектов самые разные методы… но здесь чего-то явно не хватает. Работа с этими объектами сильно напоминает программирование до того, как мы узнали о переменных. Взгляните на наши кости, например. Мы можем бросать их, и каждый раз при этом они выдают нам другое число. Но если мы хотели бы задержаться на этом числе, нам бы пришлось создать переменную, указывающую на это число. Кажется, любая порядочная игральная кость должна иметь возможность хранить число, а бросание кости должно изменять это число. Если мы уже отслеживаем состояние самой кости, то нам уже не нужно отслеживать где-то ещё число, которое она показывает.</p>
   <p>Однако, если мы попытаемся сохранить полученное число в (локальной) переменной метода roll, оно исчезнет, как только закончится roll. Нам нужно хранить число в переменной другого типа –</p>
   <subtitle>Переменные экземпляра</subtitle>
   <p>Обычно, когда мы хотим что-то сказать о строке, мы просто называем её строкой. Однако, мы могли также назвать её строковым объектом. Некоторые программисты могли бы назвать её экземпляром класса String, но это просто причудливый и длинный (так что можно запыхаться) способ сказать: «строка». Экземпляр класса – это просто объект этого класса.</p>
   <p>Так что переменные экземпляра – это просто переменные объекта. Локальные переменные метода действуют до завершения метода. С другой стороны, переменные экземпляра каждого объекта будут действительны, пока существует объект. Чтобы отличить переменные экземпляра от локальных переменных, перед их именами ставится символ @:</p>
   <p><code>class Die # игральная кость def roll</code></p>
   <p>@numberShowing = 1 + rand(6) end</p>
   <p><code>def showing</code></p>
   <p>@numberShowing</p>
   <p><code>end</code></p>
   <p><code>end</code></p>
   <p><code>die = Die.new die.roll</code></p>
   <p><code>puts die.showing puts die.showing die.roll</code></p>
   <p><code>puts die.showing puts die.showing</code></p>
   <p><code>6</code></p>
   <p><code>6</code></p>
   <p><code>3</code></p>
   <p>Очень хорошо! Так, метод roll бросает кость, а showing сообщает нам, какое число выпало. Однако, что же будет, если мы попытаемся посмотреть, что выпало прежде, чем мы бросили кость (прежде, чем мы задали значение @numberShowing)?</p>
   <p><code>class Die # игральная кость def roll</code></p>
   <p>@numberShowing = 1 + rand(6) end</p>
   <p><code>def showing</code></p>
   <p><code>@numberShowing</code></p>
   <p><code>end</code></p>
   <p><code>end</code></p>
   <p><code># Поскольку я не собираюсь снова использовать эту кость,</code></p>
   <p><code># мне не нужно сохранять её в переменной.</code></p>
   <p><code>puts Die.new.showing</code></p>
   <p><code>nil</code></p>
   <p>Хммм… ладно, по крайней мере, она не выдала нам ошибку. Однако, в самом деле нет никакого смысла в том, что кость «не была брошена», или что бы там ни означало значение nil в этом случае. Было бы хорошо, если бы мы могли задать значение для нашего нового объекта «кость» сразу после того, как он был создан. Вот зачем нужен метод initialize:</p>
   <empty-line/>
   <p><code>class</code></p>
   <p><code>Die # игральная кость</code></p>
   <p><code>def</code></p>
   <p><code>initialize</code></p>
   <p><code>#</code></p>
   <p><code>я просто</code></p>
   <p><code>брошу эту кость, хотя мы</code></p>
   <p><code>#</code></p>
   <p><code>могли бы</code></p>
   <p><code>сделать что-нибудь ещё, если бы хотели,</code></p>
   <p><code>#</code></p>
   <p><code>например,</code></p>
   <p><code>задать, что выпало число 6.</code></p>
   <p><code>roll</code></p>
   <p><code>end</code></p>
   <p><code>def roll</code></p>
   <p>@numberShowing = 1 + rand(6) end</p>
   <p><code>def showing</code></p>
   <p>@numberShowing</p>
   <p><code>end</code></p>
   <p><code>end</code></p>
   <p><code>puts Die.new.showing</code></p>
   <p><code>2</code></p>
   <empty-line/>
   <p>Когда объект создаётся, всегда вызывается его метод initialize (если он у него определён).</p>
   <p>Наши игральные кости теперь почти безупречны. Может быть, единственное, чего не хватает, так это способа задать, какой стороной выпала кость… Почему бы вам не написать метод cheat, который как раз это и делает! Вернётесь к чтению, когда закончите его (и, конечно, когда проверите, что он работает). Убедитесь, что невозможно задать, чтобы на кости выпало 7!</p>
   <p>Итак, мы только что прошли весьма крутой материал. Однако же, он довольно сложный, поэтому позвольте мне дать вам другой, более интересный пример. Ну, скажем, мы хотим сделать простое виртуальное домашнее животное – дракончика. Как большинство детей, он должен быть способен есть, спать и «гулять», что означает, что нам нужно будет иметь возможность кормить его, укладывать спать и выгуливать. Внутри себя нашему дракону понадобится отслеживать, когда он голоден, устал или ему нужно на прогулку; но у нас не будет возможности узнать это, когда мы будем общаться с нашим драконом: точно так же вы не можете спросить человеческого младенца: «Ты хочешь есть?». Мы также предусмотрим несколько других забавных способов для общения с нашим дракончиком, а когда он родится, мы дадим ему имя. (Что бы вы ни передали в метод new, для вашего удобства будет передано в метод initialize.) Ладно, давайте попробуем:</p>
   <p><code>class Dragon</code></p>
   <p><code>def initialize name</code></p>
   <p><code>@name = name</code></p>
   <p><code>@asleep = false</code></p>
   <p><code>@stuffInBelly = 10</code></p>
   <p><code># Он сыт.</code></p>
   <p><code>@stuffInIntestine = 0</code></p>
   <p><code># Ему не надо гулять.</code></p>
   <p><code>puts @name + ' родился.'</code></p>
   <p><code>end</code></p>
   <p><code>def passageOfTime # проходит некоторое время if @stuffInBelly &gt; 0</code></p>
   <p><code># Переместить пищу из желудка в кишечник.</code></p>
   <p>@stuffInBelly = @stuffInBelly – 1</p>
   <p>@stuffInIntestine = @stuffInIntestine + 1 else # Наш дракон страдает от голода! if @asleep</p>
   <p>@asleep = false</p>
   <p><code>puts 'Он внезапно просыпается!' end</code></p>
   <p><code>puts @name + ' проголодался! Доведённый до крайности, он съедает</code></p>
   <p>ВАС ! '</p>
   <p><code>exit # Этим методом выходим из программы. end</code></p>
   <p><code>if @stuffInIntestine &gt;= 10 @stuffInIntestine = 0</code></p>
   <p><code>puts 'Опаньки! ' + @name + ' сделал нехорошо…' end</code></p>
   <p><code>if hungry? if @asleep</code></p>
   <p>@asleep = false</p>
   <p><code>puts 'Он внезапно просыпается!' end</code></p>
   <p><code>puts 'В желудке у ' + @name + '(а) урчит…' end</code></p>
   <p><code>if poopy? if @asleep</code></p>
   <p>@asleep = false</p>
   <p><code>puts 'Он внезапно просыпается!'</code></p>
   <p><code>ешЗ</code></p>
   <p><code>puts @пате</code></p>
   <p><code>+ ' подпрыгивает, потому что хочет на горшок…'</code></p>
   <p><code>етЗ</code></p>
   <p><code>етЗ</code></p>
   <empty-line/>
   <p><code>end</code></p>
   <p><code>pet = Dragon.new</code></p>
   <p><code>'Норберт'</code></p>
   <p><code>pet.feed</code></p>
   <p><code>pet. toss</code></p>
   <p><code>pet.walk</code></p>
   <p><code>pet.putToBed</code></p>
   <p><code>pet.rock</code></p>
   <p><code>pet.putToBed</code></p>
   <p><code>pet.putToBed</code></p>
   <p><code>pet.putToBed</code></p>
   <p><code>pet.putToBed</code></p>
   <p>Норберт родился.</p>
   <p>Вы кормите Норберт(а).</p>
   <p>Вы подбрасываете Норберт(а) в воздух.</p>
   <p>Он хихикает, обжигая при этом вам брови.</p>
   <p>Вы выгуливаете Норберт(а).</p>
   <p>Вы укладываете Норберт(а) спать.</p>
   <p>Норберт храпит, наполняя комнату дымом.</p>
   <p>Норберт храпит, наполняя комнату дымом.</p>
   <p>Норберт храпит, наполняя комнату дымом.</p>
   <p>Норберт медленно просыпается.</p>
   <p>Вы нежно укачиваете Норберт(а).</p>
   <p>Он быстро задрёмывает…</p>
   <p>…но просыпается, как только вы перестали качать. Вы укладываете Норберт(а) спать.</p>
   <p>Он внезапно просыпается!</p>
   <p>В желудке у Норберт(а) урчит…</p>
   <p>Вы укладываете Норберт(а) спать.</p>
   <p>Он внезапно просыпается!</p>
   <p>В желудке у Норберт(а) урчит…</p>
   <p>Вы укладываете Норберт(а) спать.</p>
   <p>Он внезапно просыпается!</p>
   <p>В желудке у Норберт(а) урчит…</p>
   <p>Норберт подпрыгивает, потому что хочет на горшок…</p>
   <p>Вы укладываете Норберт(а) спать.</p>
   <p>Он внезапно просыпается!</p>
   <p>Норберт проголодался! Доведённый до крайности, он съедает ВАС!</p>
   <p>Вот тебе и раз! Конечно, было бы лучше, если бы это была интерактивная программа, но эти изменения вы можете сделать попозже. Я просто попытался показать те части программы, которые непосредственно относятся к созданию нового класса Dragon.</p>
   <p>В этом примере мы увидели несколько новых конструкций. Первая достаточно проста: exit заканчивает программу «здесь и сейчас». Вторая – это ключевое слово private, которое мы вставили прямо в середину описания нашего класса. Я мог бы обойтись без него, но я хотел подчеркнуть мысль о том, что одни методы – это то, что вы можете делать с драконом, а другие – то, что просто происходит внутри дракона. Вы можете считать, что эти методы скрыты «под капотом»: если вы не работаете автомехаником, всё, что на самом деле вам нужно знать, это педаль газа, педаль тормоза и рулевое колесо. Программист назвал бы их открытым интерфейсом вашей машины. Однако то, каким образом ваша аварийная подушка знает, когда наполниться воздухом, является внутренним поведением машины; обычному пользователю (водителю) не нужно знать об этом.</p>
   <p>А сейчас в качестве более конкретного примера, иллюстрирующего эти строки, давайте поговорим о том, как вы могли бы представить автомобиль в видео-игре (чем я как раз, по случайному совпадению, и занимаюсь). Во-первых, вы захотели бы решить, каким должен выглядеть ваш внешний интерфейс; другими словами, какие методы смогут вызывать пользователи у ваших объектов-автомобилей? Ну, им понадобится нажимать на педаль газа и педаль тормоза, но им также понадобится указывать, с какой силой они нажимают на педаль. (Есть большая разница между «вдавить в пол» и «дотронуться».) Им также понадобится управлять, и снова потребуется возможность сказать, насколько сильно они поворачивают руль. Я полагаю, вы могли бы продолжить и добавить сцепление, сигналы поворота, реактивную установку, форсаж, конденсатор временного потока [главная деталь машины времени – <emphasis>Прим. перев.</emphasis>] и так далее… Это зависит от того, какую разновидность игры вы делаете.</p>
   <p>Однако, нужно, чтобы внутри объекта-автомобиля происходило много чего другого; автомобилю нужны будут такие вещи, как скорость, направление и положение (и это только самые основные). Эти атрибуты могут изменяться нажатием на педали газа и тормоза и, конечно, поворачиванием руля, но пользователь не должен иметь возможности непосредственно устанавливать положение (что было бы подобно сверхсветовому перемещению). Вы, должно быть, также пожелаете отслеживать боковые заносы и повреждения, отрыв всех колёс от земли и так далее. Всё это будет внутренностями вашего автомобильного объекта.</p>
   <p><strong>Попробуйте ещё кое-что</strong></p>
   <p>• Сделайте класс для апельсинового дерева – OrangeTree. У него должен быть метод height, возвращающий его высоту, и метод oneYearPasses, который при вызове увеличивает возраст дерева на один год. Каждый год дерево становится выше (как по-вашему, на какую высоту в год должно вырастать апельсиновое дерево?), а после определённого числа лет (опять же, как вы считаете) дерево должно умереть. Первые несколько лет оно не должно плодоносить, но через некоторое время должно, и мне кажется, что более старые деревья приносят каждый год больше плодов, чем молодые… настолько, насколько вы считаете это разумным. И, конечно, вам нужно иметь возможность сосчитать апельсины методом countTheOranges (который возвращает число апельсинов на дереве) и собирать их методом pickAnOrange (который уменьшает @orangeCount на единицу и возвращает строку с описанием, насколько вкусен был апельсин, или же он просто сообщает вам, что больше нет апельсинов для сбора в этом году). Удостоверьтесь, что те апельсины, что вы не собрали в этом году, опадут до следующего года.</p>
   <p>• Напишите программу, в которой вы смогли бы взаимодействовать с вашим дракончиком. У вас должна быть возможность вводить такие команды, как feed и walk, и чтобы при этом вызывались нужные методы вашего дракона. Конечно, поскольку то, что вы вводите, это просто строки, вам понадобится некое подобие диспетчера методов, где ваша программа проверяет, какая строка была введена и затем вызывает соответствующий метод.</p>
   <p>Вот почти что и всё, что можно сказать об этом! Нет, подождите секундочку… Я же не рассказал вам обо всех этих классах, которые выполняют самые разнообразные вещи: отправляют электронную почту, сохраняют и загружают файлы на ваш компьютер, или же создают окна и кнопки (и даже 3-хмерные миры) и всё прочее! Что ж, попросту имеется настолько много классов, которые вы можете использовать, что мне никак невозможно показать вам их все; я даже не знаю, что большинство из них из себя представляют! А что я могу сказать вам о них, так это то, где можно разузнать о них поподробнее, чтобы вы смогли изучить те из них, которые вы захотите применить в ваших программах. Однако, прежде, чем вы отправитесь на самостоятельное изучение, вам ещё следует узнать о других важных особенностях Ruby, которых нет в большинстве других языков, но без которых я просто не смог бы жить: о блоках и процедурных объектах.</p>
  </section>
  <section>
   <title>
    <p>10. Блоки и процедурные объекты</p>
   </title>
   <p>Это определённо одна из самых крутых возможностей Ruby. В некоторых других языках тоже есть такие возможности, хотя они могут называться как-нибудь по- другому (например, замыкания), но в большинстве даже более популярных языков, к их стыду, они отсутствуют.</p>
   <p>Так что же это за новая крутая возможность? Это способность принимать блок кода (то есть код между do и end), обёртывать его в объект (называемый процедурным объектом или proc по-английски), сохранять его в переменной или передавать его в метод, а затем исполнять код этого блока, когда бы вы ни пожелали (более одного раза, если хотите). Таким образом, блок напоминает настоящий метод за исключением того, что он не привязан ни к какому объекту (он сам является объектом), и вы можете сохранять его или передавать его как параметр подобно тому, как вы это делаете с любым другим объектом. Думаю, настало время привести пример:</p>
   <empty-line/>
   <p><code>toast = Proc</code></p>
   <p><code>.new do</code></p>
   <p><code>puts 'Ваше</code></p>
   <p><code>здоровье! '</code></p>
   <p><code>end</code></p>
   <p><code>toast.call</code></p>
   <p><code>toast.call</code></p>
   <p><code>toast.call</code></p>
   <p><code>Ваше здоровье!</code></p>
   <p>Ваше здоровье!</p>
   <p>Ваше здоровье!</p>
   <p>Итак, я создал объект proc (это название, полагаю, означает сокращение от «procedure», т. е. «процедура», но гораздо более важно, что оно рифмуется с «block»), который содержит блок кода, затем я с помощью call вызвал proc–объект три раза. Как видите, это очень напоминает метод.</p>
   <p>На самом деле, это даже более походит на метод, чем в показанном мной примере, так как блоки могут принимать параметры:</p>
   <p><code>doYouLike = Proc.new do |aGoodThing|</code></p>
   <p><code>puts 'Я *действительно* люблю '+aGoodThing+'!' end</code></p>
   <p><code>doYouLike.call 'шоколад' doYouLike.call 'рубин'</code></p>
   <p>Я *действительно* люблю шоколад!</p>
   <p>Я *действительно* люблю рубин!</p>
   <p>Хорошо, вот мы узнали, что из себя представляют блоки и ргос-и читается: «проки»</p>
   <p>[<emphasis>Прим. перев.</emphasis>], и как их можно использовать, но в чём же здесь дело? Почему бы просто не использовать методы? Ну потому, что некоторые вещи вы просто не сможете сделать с помощью методов. В частности, вы не можете передавать методы в другие методы (но вы можете передавать в методы процедурные объекты), и методы не могут возвращать другие методы (но они могут возвращать ргос-объекты). Это возможно просто потому, что ргос-и являются объектами, а методы – нет.</p>
   <p>(Между прочим, вам это не кажется знакомым? Вот-вот, вы уже видели блоки раньше… когда вы изучали итераторы. Но давайте поговорим об этом ещё чуточку попозже.)</p>
   <p>Методы, принимающие процедурные объекты</p>
   <p>Когда мы передаём процедурный объект в метод, мы можем управлять тем, как, в каком случае или сколько раз мы вызываем ргос-объект. Например, имеется, скажем, нечто, что мы хотим сделать перед и после выполнения некоторого кода:</p>
   <p><code>def doSelflmportantly someProc</code></p>
   <p><code>puts 'Всем немедленно ЗАМЕРЕТЬ!</code></p>
   <p><code>Мне нужно кое-что сделать…'</code></p>
   <p><code>someProc.call</code></p>
   <p><code>puts 'Внимание всем, я закончил.</code></p>
   <p><code>Продолжайте выполнять свои дела.'</code></p>
   <p><code>end</code></p>
   <p><code>sayHello = Proc.new do</code></p>
   <p><code>puts 'привет'</code></p>
   <p><code>end</code></p>
   <p><code>sayGoodbye = Proc.new do</code></p>
   <p><code>puts 'пока'</code></p>
   <p><code>end</code></p>
   <p><code>doSelflmportantly sayHello</code></p>
   <p><code>doSelflmportantly sayGoodbye</code></p>
   <p><code>Всем немедленно ЗАМЕРЕТЬ! Мне нужно кое-что сделать… привет Внимание всем, я закончил. Продолжайте выполнять свои дела. Всем немедленно ЗАМЕРЕТЬ! Мне нужно кое-что сделать… пока</code></p>
   <p>Внимание всем, я закончил. Продолжайте выполнять свои дела.</p>
   <p>Возможно, это не выглядит так уж особенно потрясающим… но это так и есть. :-) В программировании слишком часто имеются строгие требования к тому, что должно быть сделано и когда. Если вы хотите, например, сохранить файл, вам нужно открыть файл, записать туда информацию, которую вы хотите в нём хранить, а затем закрыть файл. Если вы позабудете закрыть файл, могут случиться «Плохие Вещи™. Но каждый раз, когда вы хотите сохранить или загрузить файл, вам требуется делать одно и то же: открывать файл, выполнять то, что вы действительно желаете сделать, затем закрывать файл. Это утомительно и легко забывается. В Ruby сохранение (или загрузка) файлов работает подобно приведённому выше коду, поэтому вам не нужно беспокоиться ни о чём, кроме того, что вы действительно хотите сохранить (или загрузить). (В следующей главе я покажу вам, где разузнать, как делать такие вещи, как сохранение и загрузка файлов.)</p>
   <p>Вы также можете написать методы, которые будут определять, сколько раз (или даже при каком условии) вызывать процедурный объект. Вот метод, который будет вызывать переданный ему proc–объект примерно в половине случаев, и ещё один метод, который будет вызывать его дважды:</p>
   <p><code>def maybeDo someProc</code></p>
   <p><code># Условный вызов</code></p>
   <p><code>if rand(2) == 0</code></p>
   <p><code>someProc.call</code></p>
   <p><code>end</code></p>
   <p><code>end</code></p>
   <p><code>def twiceDo someProc</code></p>
   <p><code># Двойной вызов</code></p>
   <p><code>someProc.call</code></p>
   <p><code>someProc.call</code></p>
   <p><code>end</code></p>
   <p><code>wink = Proc.new do</code></p>
   <p><code>puts '&lt;nOflMMrHyTb&gt;'</code></p>
   <p><code>end</code></p>
   <p><code>glance = Proc.new do</code></p>
   <p><code>puts ' &lt;B3mHHyTb&gt; '</code></p>
   <p><code>end</code></p>
   <p><code>maybeDo wink</code></p>
   <p><code>maybeDo glance</code></p>
   <p><code>twiceDo wink</code></p>
   <p><code>twiceDo glance</code></p>
   <p><code>&lt;подмигнуть&gt;</code></p>
   <p><code>&lt;подмигнуть&gt;</code></p>
   <p><code>&lt;взглянуть&gt;</code></p>
   <p><code>&lt;взглянуть&gt;</code></p>
   <p>(Если вы перезагрузите эту страницу несколько раз [имеется ввиду страница оригинального учебника – <emphasis>Прим. перев.</emphasis>], то вы увидите другие результаты.) Это самые распространённые применения процедурных объектов, которые дают нам возможность делать такие вещи, которые мы просто не могли бы сделать, используя только методы. Конечно, вы могли бы написать метод, чтобы подмигнуть два раза, но вы не смогли бы написать метод, чтобы просто делать дважды что-нибудь!</p>
   <p>Прежде, чем мы продолжим, давайте посмотрим на последний пример. До сих пор все передаваемые процедурные объекты были довольно похожи друг на друга. В этот раз они будут совсем другими, и вы увидите, насколько сильно подобный метод зависит от тех процедурных объектов, что были ему переданы. Наш метод примет обычный объект и процедурный объект, и вызовет процедурный объект с обычным объектом в качестве параметра. Если процедурный объект вернёт false, мы закончим выполнение, иначе мы вызовем процедурный объект с возвращённым объектом. Мы будем продолжать так делать, пока процедурный объект не вернёт false (что ему лучше сделать в конце концов, иначе программа «загнётся»). Этот метод вернёт последнее значение, возвращённое процедурным объектом, не равное false.</p>
   <p><code>def doUntilFalse firstlnput, someProc input = firstlnput output = firstlnput</code></p>
   <p><code>while output</code></p>
   <p><code>input = output output = someProc.call input end</code></p>
   <p><code>input</code></p>
   <p><code>end</code></p>
   <p><code>buildArrayOfSquares = Proc.new do |array| # Создание массива квадратов чисел</code></p>
   <p><code>lastNumber = array.last if lastNumber &lt;= 0 false else</code></p>
   <p><code>array.pop # Уберём последнее число…</code></p>
   <p><code>array.push lastNumber*lastNumber # …и заменим его на его квадрат…</code></p>
   <p><code>array.push lastNumber–1 # …за которым идет предыдущее</code></p>
   <p>число.</p>
   <p><code>end</code></p>
   <p><code>end</code></p>
   <p><code>alwaysFalse = Proc.new do |justIgnoreMe| false end</code></p>
   <p><code>puts doUntilFalse([5], buildArrayOfSquares).inspect</code></p>
   <p><code>puts doUntilFalse ('Я пишу это в 3 часа утра; кто–то меня вырубил!', alwaysFalse)</code></p>
   <p>[25, 16, 9, 4, 1, 0]</p>
   <p>Я пишу это в 3 часа утра; кто-то меня вырубил!</p>
   <p>Хорошо, признаю, что это был довольно странный пример. Но он показывает, насколько по-разному ведёт себя наш метод, когда ему передают совсем разные процедурные объекты.</p>
   <p>Метод inspect во многом похож на to_s за исключением того, что возвращаемая им строка – это попытка показать код на Ruby для создания объекта, который вы ему передали. Здесь он показывает нам весь массив, возвращённый при нашем первом вызове метода doUntilFalse. Вы, должно быть, также заметили, что мы сами никогда не возводили в квадрат этот 0 в конце массива, но поскольку 0 в квадрате всегда равен 0, нам это и не нужно было делать. А так как alwaysFalse, как вы знаете, возвращает всегда false, метод doUntilFalse ничего не делал, когда мы вызвали его во второй раз; он просто вернул то, что ему было передано.</p>
   <p>Методы, возвращающие процедурные объекты</p>
   <p>Ещё одна из крутых возможностей, которые можно делать с процедурными объектами, это то, что их можно создавать в методах, а затем возвращать их. Это делает возможным разнообразные сумасшедшие, но мощные программистские штучки (с впечатляющими названиями наподобие ленивое вычисление, бесконечные структуры данных и карринг). Но дело в том, что я почти никогда не использовал это на практике, а также не припомню, чтобы видел, как кто-либо применял это в своём коде. Думаю, это не такого рода вещи, которые обычно нужно делать на Ruby, а, может быть, Ruby просто подталкивает вас находить другие решения – не знаю. В любом случае, я только кратко коснусь этого.</p>
   <p>В этом примере метод compose принимает два процедурных объекта и возвращает новый процедурный объект, который, будучи вызван, вызывает первый процедурный объект и передаёт его результат во второй.</p>
   <p><code>def compose proc1, proc2</code></p>
   <p><code>Proc.new do |x|</code></p>
   <p><code>proc2.call(proc1.call(x))</code></p>
   <p><code>end</code></p>
   <p><code>end</code></p>
   <p><code>squareIt = Proc.new do |x|</code></p>
   <p><code>x * x</code></p>
   <p><code>end</code></p>
   <p><code>doublelt = Proc.new do |x|</code></p>
   <p><code>x + x</code></p>
   <p><code>end</code></p>
   <p><code>doubleThenSquare = compose doublelt,</code></p>
   <p><code>squareIt</code></p>
   <p><code>squareThenDouble = compose squareIt,</code></p>
   <p><code>doublelt</code></p>
   <p><code>puts doubleThenSquare.call(5)</code></p>
   <p><code>puts squareThenDouble.call(5)</code></p>
   <p>&gt; </p>
   <p><code>100</code></p>
   <p><code>50</code></p>
   <p>Обратите внимание, что вызов proel должен быть внутри скобок при вызове proc2, чтобы он был выполнен первым.</p>
   <p>Передача блоков (не proc–объектов) в методы</p>
   <p>Ну, хорошо, этот подход представляет чисто академический интерес, к тому же применять его несколько затруднительно. В основном трудность состоит в том, что здесь вам приходится выполнить три шага (определить метод, создать процедурный объект и вызвать метод с процедурным объектом); тогда как есть ощущение, что должно быть только два (определить метод и передать блок непосредственно в этот метод, совсем не используя процедурный объект), поскольку в большинстве случаев вы не хотите использовать процедурный объект / блок после того, как вы передали его в метод. Что ж, да будет вам известно, что в Ruby всё это уже сделано за нас! Фактически, вы уже делали это каждый раз, когда использовали итераторы.</p>
   <p>Сначала я быстро покажу вам пример, а затем мы обсудим его.</p>
   <p><code>class Array</code></p>
   <p><code>def eachEven(&amp;wasABlock_nowAProc)</code></p>
   <p><code>isEven = true # Мы начинаем с «true», т.к. массив начинается с 0, а он чётный.</code></p>
   <p><code>self.each do |object| if isEven</code></p>
   <p><code>wasABlock_nowAProc.call object end</code></p>
   <p><code>isEven = (not isEven) # Переключиться с чётного на нечётное или наоборот.</code></p>
   <p><code>end</code></p>
   <p><code>end</code></p>
   <p><code>end</code></p>
   <p><code>['яблоками', 'гнилыми яблоками', 'вишней', 'дурианом'].eachEven do |fruit| puts</code></p>
   <p><code>'Мммм! Я так люблю пирожки с '+fruit+', а вы?' end</code></p>
   <p><code># Помните, что мы берём элементы массива с чётными номерами,</code></p>
   <p><code># все из которых оказываются нечётными числами; это</code></p>
   <p><code># просто потому, что мне захотелось создать подобные трудности.</code></p>
   <p><code>[1, 2, 3, 4, 5].eachEven do |oddBall|</code></p>
   <p><code>puts oddBall.to_s+' – НЕ чётное число!' end</code></p>
   <empty-line/>
   <p><code>Мммм!</code></p>
   <p><code>Я так люблю пирожи</code></p>
   <p><code>с яблоками,</code></p>
   <p><code>а вы?</code></p>
   <empty-line/>
   <p><code>Мммм!</code></p>
   <p><code>Я так люблю пирожи</code></p>
   <p><code>с вишней, а</code></p>
   <p><code>вы?</code></p>
   <empty-line/>
   <p><code><sup>–</sup> <sup>Н</sup> И</code></p>
   <p><code>чётное число!</code></p>
   <empty-line/>
   <p><code>ЕН – 3</code></p>
   <p><code>чётное число!</code></p>
   <empty-line/>
   <p><code>5 – НЕ</code></p>
   <p><code>чётное число!</code></p>
   <empty-line/>
   <p>Итак, всё, что мы должны сделать, чтобы передать блок в метод eachEven, это «прилепить» блок после метода. Подобным же образом вы можете передать блок в любой метод, хотя многие методы просто проигнорируют блок. Чтобы заставить ваш метод не игнорировать блок, а взять его и превратить его в процедурный объект, нужно поместить имя процедурного объекта в конце списка параметров вашего метода и поставить перед ним амперсанд (&amp;). Конечно, это немного мудрёно, но не слишком, и вам придётся сделать это только один раз (когда вы описываете метод). А затем вы можете использовать этот метод снова и снова точно так же, как и встроенные методы, принимающие блоки такие, как each и times. (Помните, 5.times do…?)</p>
   <p>Если для вас это слишком запутанно, просто помните, что должен сделать eachEven: вызвать переданный ему блок для каждого чётного элемента в массиве. После того, как однажды вы написали метод и убедились, что он работает, вам уже не нужно думать о том, что в действительности делается «под капотом» («какой блок и когда вызывается??»). На самом деле, именно поэтому мы пишем подобные методы: чтобы нам никогда не приходилось снова думать о том, как они работают. Мы просто используем их.</p>
   <p>Помню, один раз я захотел сделать, чтобы можно было измерять, сколько времени выполняются различные секции программы. (Это также известно как профилирование программного кода.) И я написал метод, который засекает время перед исполнением кода, затем выполняет его, в конце снова засекает время и вычисляет разницу. Сейчас я не могу найти этот метод, но мне он и не нужен; он, возможно, выглядел примерно так:</p>
   <empty-line/>
   <p><code>def profile descriptionOfBlock, &amp;block # Описание блока и сам блок startTime = Time.now</code></p>
   <p><code>block.call</code></p>
   <p><code>duration = Time.now – startTime</code></p>
   <p><code>puts descriptionOfBlock+': '+duration.to_s+' сек.' end</code></p>
   <p><code>profile '25000 удваиваний' do number = 1</code></p>
   <p><code>25000.times do</code></p>
   <p><code>number = number + number end</code></p>
   <p><code>puts number.to_s.length.to_s+' цифр' # Да, это число цифр в таком ГИГАНТСКОМ числе.</code></p>
   <p><code>end</code></p>
   <p><code>profile 'сосчитать до миллиона' do number = 0</code></p>
   <p><code>1000000.times do</code></p>
   <p><code>number = number + 1</code></p>
   <p><code>end</code></p>
   <p><code>end</code></p>
   <p><code>7526 цифр</code></p>
   <p><code>25000 удваиваний: 0.304966 сек. сосчитать до миллиона: 0.615216 сек.</code></p>
   <empty-line/>
   <p>Как просто! Как элегантно! Теперь с помощью этого крошечного метода я легко могу измерить время работы любой секции в любой программе, в какой только захочу: я просто закину код в блок и отправлю его методу profile. Что может быть проще? В большинстве языков мне понадобилось бы явно добавлять код для измерения времени (тот, что написан в profile) до и после каждой секции, которую я хотел бы захронометрировать. В то время как в Ruby я всё держу в одном-единственном месте и (что более важно) отдельно от всего остального!</p>
   <p>Попробуйте ещё кое-что</p>
   <p>• Дедушкины часы. Напишите метод, который принимает блок и вызывает его один раз для каждого часа, который прошёл сегодня. Таким образом, если я бы передал ему блок do puts 'БОМ! ' end, он бы отбивал время (почти) как дедушкины часы. Проверьте ваш метод с несколькими различными блоками (включая тот, что я вам дал). Подсказка: Вы можете использовать Time.now.hour, чтобы получить текущий час. Однако, он возвращает число между 0 и 23, поэтому вам придётся изменить эти числа, чтобы получить обычные числа, как на циферблате (от 1 до 12).</p>
   <p>• Протоколирование программ. Напишите метод под названием log, который принимает строку описания блока и, конечно, сам блок. Подобно методу doSelfimportantly, он должен выводить с помощью puts строку, сообщающую, что он начал выполнение блока, и ещё одну строку в конце, сообщающую, что он закончил выполнение блока, а также сообщающую вам, что вернул блок. Проверьте ваш метод, отправив ему блок кода. Внутри этого блока поместите другой вызов метода log, передав ему другой блок. (Это называется вложенностью.) Другими словами, ваш вывод должен выглядеть примерно так:</p>
   <empty-line/>
   <p><code>Начинаю «внешний блок»…</code></p>
   <p><code>Начинаю «другой небольшой блок»…</code></p>
   <p><code>…«другой небольшой блок» закончен,</code></p>
   <p><code>вернул: 5</code></p>
   <p><code>Начинаю «ещё один блок»…</code></p>
   <p><code>…«ещё один блок» закончен, вернул:</code></p>
   <p><code>Мне нравится тайская еда!</code></p>
   <p><code>…«внешний блок» закончен, вернул:</code></p>
   <p><code>false</code></p>
   <empty-line/>
   <p><code>• Улучшенное протоколирование. Вывод из предыдущего метода log было трудновато читать, и было бы тем хуже, чем больше была бы вложенность. Было бы гораздо легче читать, если бы он делал отступы в строках для внутренних блоков. Чтобы это сделать, вам понадобится проверять, насколько глубоко вложен вызов</code></p>
   <p>метода перед тем, как log хочет что-нибудь напечатать. Чтобы сделать это, примените глобальную переменную, т. е. переменную, которую вы можете видеть из любого места вашего кода. Чтобы сделать переменную глобальной, просто поставьте перед именем вашей переменной символ $, вот так: $global, $nestingDepth и $bigTopPeeWee. В конце концов, ваша программа протоколирования должна выводить примерно вот что:</p>
   <empty-line/>
   <p><code>Начинаю «внешний блок»…</code></p>
   <p><code>Начинаю «другой небольшой блок»…</code></p>
   <p><code>Начинаю «маленький-премаленький блок»…</code></p>
   <p><code>…«маленький-премаленький блок» закончен,</code></p>
   <p><code>вернул:</code></p>
   <p><code>море любви</code></p>
   <p><code>…«другой небольшой блок» закончен, вернул:</code></p>
   <p><code>42</code></p>
   <p><code>Начинаю «ещё один блок»…</code></p>
   <p><code>…«ещё один блок» закончен, вернул: Я люблю</code></p>
   <p><code>индийскую еду!</code></p>
   <p><code>…«внешний блок» закончен, вернул: true</code></p>
   <empty-line/>
   <p>Ну вот почти и всё, что вы намеревались узнать из этого учебника. Мои поздравления! Вы изучили очень много! Возможно, вам не кажется, что вы помните всё, или же вы пропустили некоторые части… Ну и ладно, это нормально. Программирование – это не то, что вы знаете; это то, что вы можете вычислить. Покуда вы знаете, где найти то, что вы позабыли, у вас будет всё в порядке. Надеюсь, вы не думаете, что я написал всё это, не заглядывая куда-нибудь время от времени? Я именно так и делал. Мне также много помогали с кодом, выполняющим все примеры в этом учебнике. Но куда же я заглядывал и кого я просил о помощи? Давайте, я покажу вам…</p>
  </section>
  <section>
   <title>
    <p>11. Что не вошло в учебник</p>
   </title>
   <p>Итак, куда мы сейчас отправимся? Кого можно спросить, если у вас возник вопрос? А если вы хотите, чтобы ваша программа открывала web–страничку, отправляла электронную почту или масштабировала цифровое изображение? Что ж, есть полным- полно мест, где найдется помощь по Ruby. Но, к сожалению, такой ответ вам не слишком поможет, не так ли? :-)</p>
   <p>Что касается меня, то на самом деле есть только три места, где я ищу помощи по Ruby. Если это небольшой вопрос, и я полагаю, что я могу сам поэкспериментировать, чтобы найти на него ответ, то я использую irb. Если это вопрос посерьёзнее, я обращаюсь к своей киркомотыге. А если я никак не могу разобраться с ним сам, то я прошу помощи в ruby–talk.</p>
   <subtitle>IRB: Интерактивный интерпретатор Ruby</subtitle>
   <p>Если вы установили Ruby, то вы также установили irb. Чтобы его запустить, нужно просто перейти в командное окно и напечатать irb. Когда вы находитесь в сеансе irb, вы можете вводить любые выражения языка Ruby, какие пожелаете, а он будет выдавать вам их значения. Введите 1 + 2, и он выдаст вам 3. (Обратите внимание, что вам не нужно использовать puts.) Это похоже на гигантский калькулятор на Ruby. Когда вы закончите, просто введите команду exit.</p>
   <p>В irb имеется гораздо больше этого, но обо всём этом вы можете узнать в «киркомотыге».</p>
   <subtitle>Киркомотыга: „Программирование на Ruby”</subtitle>
   <p>Абсолютно именно та книга по Ruby, которая нужна всем – это «Программирование на Ruby: Руководство прагматичного программиста», написанная Дэвидом Томасом и Эндрю Хантом &lt;a href="http://www.pragmaticprogrammer.com/"&gt; (Программисты-прагматики). Хотя я очень рекомендую достать&lt;a href="http://www.pragmaticprogrammer.com/titles/ruby/"&gt; 2-е &lt;a href="http://www.pragmaticprogrammer.com/titles/ruby/"&gt; издание этой замечательной книги, где освещены все последние возможности Ruby, вы также можете взять немного более старую (но до сих пор в основном подходящую) версию, бесплатно доступную&lt;a href="http://www.rubycentral.com/book/"&gt; в Сети. (На самом деле, если вы установили версию Ruby для Windows, то она у вас уже имеется.)</p>
   <p>В этой книге вы можете найти о руби Ruby почти всё, от основ до самых передовых возможностей. Она легко читается; она исчерпывающая; она почти безупречна. Хотелось бы, чтобы для всякого языка имелась бы книга подобного качества. В конце книги вы найдёте огромный раздел, где подробно описан каждый метод каждого класса, приведены объяснения и примеры. Я просто полюбил эту книгу!</p>
   <p>Её можно найти в нескольких местах (включая собственный сайт &lt;a href="http://www.pragmaticprogrammer.com/"&gt; Программистов- &lt;a href="http://www.pragmaticprogrammer.com/"&gt;прагматиков), но мне больше всего нравится сайт&lt;a href="http://www.ruby-doc.org/docs/ProgrammingRuby/"&gt; ruby–doc.org. В этой версии слева имеется симпатичное оглавление, а также предметный указатель. (На &lt;a href="http://www.ruby-doc.org/"&gt; ruby–doc.org</p>
   <p>есть также много другой документации, например, о базовом API и стандартной библиотеке… В основном, там есть готовые к использованию документы обо всём, что касается Ruby.&lt;a href="http://www.ruby-doc.org/"&gt; Проверьте сами.)</p>
   <p>А почему же она называется «киркомотыга» («the pickaxe»)? Ну, там на обложке книги есть картинка киркомотыги. Мне кажется, это глупое название, но оно уже «прилипло».</p>
   <subtitle>Ruby–Talk: список рассылки о Ruby</subtitle>
   <p>Даже имея irb и киркомотыгу, вы иногда всё-таки не можете разобраться с чем- нибудь. Или, возможно, вы хотите знать, не делал ли уже кто-нибудь то, над чем вы сейчас работаете, чтобы выяснить, можно ли вам этим воспользоваться. В этих случаях вам нужно обратиться именно в&lt;a href="mailto:ruby-talk@ruby-lang.org"&gt; ruby–talk, список рассылки о Ruby. В нём полно дружелюбных, умных, отзывчивых людей. Чтобы побольше узнать о нём или подписаться на него, взгляните&lt;a href="http://www.ruby-lang.org/en/20020104.html"&gt; сюда.</p>
   <p>ПРЕДУПРЕЖДЕНИЕ: В этой рассылке каждый день приходит много почты. У меня она автоматически пересылается в другой почтовый ящик, поэтому она мне не мешает. Если же вы не желаете иметь дело со всей этой почтой, то это вам и не нужно! Список рассылки ruby–talk зеркалируется в новостную группу comp.lang.ruby, и наоборот, так что там вы можете увидеть те же самые сообщения. Любым из этих способов вы увидите одни и те же сообщения, просто немного в разных форматах. [Web–интерфейс к архиву этого списка рассылки находится по адресу:&lt;a href="http://www.ruby-forum.com/forum/4"&gt; www.ruby– &lt;a href="http://www.ruby-forum.com/forum/4"&gt;forum.com/forum/4. – <emphasis>Прим. перев.</emphasis>]</p>
   <subtitle>Tim Toady</subtitle>
   <p>То, от чего я старался уберечь вас, но с чем вы непременно скоро столкнётесь, это принцип TMTOWTDI (произносится «Тим Тоуди») или «There's More Than One Way To Do It», что значит «Есть не один способ сделать что-либо».</p>
   <p>В то время как одни будут говорить вам, какая замечательная вещь этот TMTOWTDI, другие относятся к нему совсем по-другому. На самом деле, у меня в основном не возникает по этому поводу никаких сильных эмоций, но я считаю, что это ужасный метод обучить кого-то, как нужно программировать. (Как будто научить делать что-то одним способом это само по себе не достаточно трудоёмкое и сложное дело!)</p>
   <p>Однако теперь, когда вы выходите за рамки того учебника, вы будете читать гораздо более разнообразные программы. Например, мне приходят на ум по крайней мере пять различных способов создания строки (помимо заключения некоторого текста в одинарные кавычки), и каждый из них работает немного по-другому. Я показал вам только самый простой из этих шести.</p>
   <p>А когда мы говорили о ветвлении, я показал вам if, но не показал unless. Предоставляю вам выяснить что это такое в irb.</p>
   <p>Ещё одно приятное сокращение, которое вы можете использовать для if, unless и while, это симпатичная однострочная версия:</p>
   <p><code># Эти слова взяты из программы, которую я написал для генерирования</code></p>
   <p><code># англоподобной болтовни. Круто, да?</code></p>
   <p><code>puts 'grobably combergearl kitatently thememberate' if 5 == 2**2 + 1**1</code></p>
   <p><code>puts 'enlestrationshifter supposine follutify blace' unless 'Chris'.length</code></p>
   <p>= = 5</p>
   <p><code>grobably combergearl kitatently thememberate</code></p>
   <empty-line/>
   <p>И наконец, есть ещё один способ писать методы, которые принимают блоки (а не процедурные объекты). Мы видели это, когда мы захватывали блок и превращали его в процедурный объект, используя трюк с &amp;block в списке параметров при определении функции. Тогда, чтобы вызвать блок, вы просто используете block.call. Ладно, есть способ покороче (хотя лично я нахожу его более запутанным). Вместо этого:</p>
   <p><code>def doItTwice(&amp;block) block.call block.call end</code></p>
   <p><code>doltTwice do</code></p>
   <p><code>puts 'murditivent flavitemphan siresent litics' end</code></p>
   <p><code>murditivent</code></p>
   <p><code>n a h p m e t i v a l f</code></p>
   <p><code>siresent</code></p>
   <p><code>litics</code></p>
   <p><code>murditivent</code></p>
   <p><code>flavitemphan</code></p>
   <p><code>siresent</code></p>
   <p><code>litics</code></p>
   <empty-line/>
   <p>…вы делаете так:</p>
   <p><code>def doltTwice yield yield end</code></p>
   <p><code>doltTwice do</code></p>
   <p><code>puts 'buritiate mustripe lablic acticise' end</code></p>
   <p><code>buritiate</code></p>
   <p><code>mustripe</code></p>
   <p><code>lablic</code></p>
   <p><code>acticise</code></p>
   <p><code>buritiate</code></p>
   <p><code>mustripe</code></p>
   <p><code>lablic</code></p>
   <p><code>acticise</code></p>
   <empty-line/>
   <p>Ну, не знаю… а что вы об этом думаете? Возможно, так только я так считаю, но… yield?! Если бы это было что-нибудь наподобие call_the_hidden_block или что-то в этом роде, что бы имело немного больше смысла для меня. Многие люди говорят, что yield для них имеет смысл. Но я думаю, что принцип TMTOWTDI предполагает вот что: они делают что-то по-своему, а я делаю это по-моему.</p>
   <p><strong>КОНЕЦ</strong></p>
   <p>Используйте всё это во благо, а не во зло. :-) И если вы находите этот учебник полезным (или запутанным, либо если вы нашли ошибку),&lt;a href="mailto:chris@pine.fm"&gt; дайте мне знать!</p>
   <empty-line/>
   <image l:href="#img_04.png"/>
   <empty-line/>
  </section>
 </body>
 <binary id="cover.png" content-type="image/png">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</binary>
 <binary id="img_01.png" content-type="image/png">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
F+2Y+8rquQAAAABJRU5ErkJggg==</binary>
 <binary id="img_02.png" content-type="image/png">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
RK5CYII=</binary>
 <binary id="img_03.png" content-type="image/png">iVBORw0KGgoAAAANSUhEUgAAAB0AAAA2BAMAAADJ1o/JAAAAMFBMVEX8/vx1aUr29OqTiW2J
fmLa1savqJDu7OV/dFaakXilnITn5NfAuqXSzL3JxLG3sZ0HoS4GAAAAAXRSTlMAQObYZgAA
Aa5JREFUeF590TFIG1EcBvDHg3DDNcKfBjm3I5A4mAwHthzFRo7AQYKaoCJocYgmakmGmwoN
UjgEMcElEASFCDe0SzIEsYOLiAiJW5BQyCaikg4FbZtSgkPfXXPv3S2+7cf33vven4eeW6N+
Am75nfifX//0iL2rtSOL3HddJc7vbFWtDZ9kSBAH98sRDQVEtHTwdEcc+HH/poUX6tyvnrUN
+8cuzrlm0tOvD2rwYoZ/vAnlRLs3mPOkGvmsTRT+EjAyJyvU/PvTUq1zRs2lvymv+9fUOH2p
x9Za1Oh3GXx7Dv+VQVCTDusA28w4BQBFZt4gHmH3ewwQwMccLoEPhAfqkAQFHdh7PyigKlC1
5/N/1CEhwWfbeA5gSoEK9TxARIIJ29wtwFsJVG1gvgvwSoI4ddNy0ZWXoKDR81ZeqNtuu3Pc
dp/Hx2bO+tCJbuYJjc1j5oei7U3JzKvUHsP0OvufDWLhJzW6JfO8bDEvEA8nmcNKRNrVmHl5
RpkWmbmLKbnKiHBHjTYcRvl4bNbpYHRbc/rF+KSTaKhccdlrZFzmU1mXuW7DZbR05XZgUPcP
qXh52pfeZSwAAAAASUVORK5CYII=</binary>
 <binary id="img_04.png" content-type="image/png">iVBORw0KGgoAAAANSUhEUgAAAVIAAABWCAMAAACq7e5/AAADAFBMVEURBAaMiYtYS02ECBeu
JDWVDCYuKStaBQ5taGq1FS3ISVXKyMmQExlbEhfQNklnCByZFSmrqKrq5+nFZG3kmpxoV1mh
Vl88Nznc2du6t7l9eXrGJzccFhial5n8/fzbV2IAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABV
ApDIAAAbtElEQVR42sVdi4KiurJVYngcQyfal0FpmPn/vzypV1IBbJnZ+8zF6R5FsHWx6l0V
T844F38M/W+MNQZ/W9riPYd78HfTNMYE5xvavDeNbD3/xN8+hG692S6+WIg3eV38G+qGfxn+
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</binary>
</FictionBook>
