Rubyn: различия между версиями

107 байт убрано ,  10 лет назад
м
робот косметические изменения
м (→‎Начало работы: изменение названия шаблона)
м (робот косметические изменения)
 
 
<div style="margin:0 3% 0 5%;float:left;">[[ИзображениеФайл:Ruby_logo.png|100px|]]</div>
{{Эпиграф|Человек создан для творчества, и я всегда знал, что люблю творить. Увы, я обделён талантом художника или музыканта. Зато умею писать программы.}}
{{Эпиграф|Я хочу, чтобы компьютер был моим слугой, а не господином, поэтому я должен уметь быстро и эффективно объяснить ему, что делать.
Учебник пока неполон. Читайте [[#Иноязычная литература|иноязычную литературу по Ruby]] и с новыми знаниями присоединяйтесь к написанию. Да-да, каждый может участвовать: [[Справка|научитесь работать]] в [[w:вики|вики]]-среде, с остающимися вопросами выступайте на [[Обсуждение:Ruby|странице обсуждения учебника]].
 
== Отличия РубиНа от Ruby ==
 
Самое первое и главное отличие - при написании переменных, классов, методов Вы теперь не ограничены 128 первыми символами ANSI. Вам доступны все 256 8-битных символа. В данной реализации используется наиболее общеупотребительная кодировка Windows-1251.
В дальнейшем, если вы читаете что-либо о языке Ruby, то все это в полной мере относится и к языку РубиН. В случае отличий это всегда будет оговорено и будет использовано название РубиН.
 
== Основные свойства Ruby ==
 
Интерпретируемый язык:
==== fxri: полигон и справочник ====
 
[[ИзображениеФайл:Интерфейс программы fxri.png|300px|right|Внешний вид программы fxri]]
 
В последних версиях дистрибутива «Установка за один щелчок» для Windows появилась утилита <big>''<tt>fxri</tt>''</big>. Это оконная кроссплатформенная программа, вобравшая в себя функционал ri и irb. Буковки <tt>fx</tt> в начале означают использование библиотеки [http://www.fxruby.org/ FXRuby]. Последние две буквы <tt>ri</tt> означают Ruby Informer (Информатор о классах и методах в языке Руби).
Данные любого [[w:Тип данных|типа]] в Ruby суть объекты тех или иных классов. Самые используемые встроенные типы данных: Fixnum ([[w:Целое число|целые числа]], меньшие <math>2^{31}</math>), Bignum (целые числа, большие <math>2^{31}</math>), Float ([[w:Вещественное число|числа с плавающей точкой]]), Array ([[w:Индексный массив|массивы]]), String ([[w:Строковый тип|строки]]), Hash ([[w:Ассоциативный массив|ассоциативные массивы]]). Естественно, что это только базовые типы, но их вполне хватает для широкого спектра задач.
 
[[ИзображениеФайл:RubyDataClasses.png|frame|center|Все абстрактные типы данных]]
 
=== Числа ===
=== Логический тип ===
<div style="float:right;margin:0.8em;padding:0.2em;background#fffcff;">
==== Логические операции ====
{| class="standard"
! название операции || символ операции || литерное обозначение
Чаще всего логический тип возникает как результат сравнения.
 
==== Методы сравнения ====
{| class="standard"
! название метода || символ
Диапазон-мотоцикл (<big><code>..</code></big>) проезжает от первого указанного объекта к его <code>.succ</code> (''succedent'' — «последующему»), и до последнего включительно. Три точки — то же, но мотоцикл остановился прямо перед последним элементом. Ещё раз:
 
<big><code>1..99</code>&equiv;<code>1...100</code></big>
 
{{info|Объекты, имеющие <code>.succ</code> называют [[w:Последовательность|последовательными]]: этим методом можно по текущему элементу достоверно определить следующий.}}
 
=== Семейный портрет чисел ===
[[ИзображениеФайл:RubyNumericClasses.png|thumb|right|Числовые типы данных]]
 
В отличие от большинства элементарных типов данных, числа обладают своей иерархией. Все числа в Руби наследованы от класса Numeric (Числовой). Поэтому, если хотите добавить новый метод ко всем числам, то нужно расширять именно этот класс. Далее идет деление чисел: Integer ([[w:Целое число|целое]]), Float ([[w:Десятичная дробь|дробное]]) и Complex ([[w:Комплексное число|комлексное]]). При желании можно добавить и Rational ([[w:Рациональное число|рациональное]]), но на данном семейном портрете оно отсутствует.
[Частичное решение [http://rubyclub.com.ua/messages/show/164]]
 
===== Двумерные целочисленные =====
 
# Найти максимальный элемент для каждого столбца, а затем получить произведение этих элементов.
# Найти сумму положительных элементов, больших К.
# Вычислить сумму и среднее арифметическое элементов главной диагонали.
# Найти номера строк, все элементы которых &mdash; нули.
 
== Подробнее об ассоциативных массивах ==
 
но с небольшими особенностями:
* результат поиска &mdash; массив из двух элементов вида <code>[ключ, значение]</code>
* сначала поиск происходит по ключу, а в случае совпадения ключей &mdash; по значению
 
Несколько больше возможностей приобрели методы .max_by и min_by
noJIHbIu_xew == {} #-> false</source>
 
Можно спросить по другому &mdash; "Размер у тебя не нулевой?"
<source lang=ruby>nycTou_xew = {}
noJIHbIu_xew = { "гаечный" => 20, "замочный" => "английский", "разводной" => 34 }
 
У ассоциативных массивов есть следующие итераторы:
* <code>.find_all</code> &mdash; поиск всех элементов, которые удовлетворяют логическому условию
* <code>.map</code> &mdash; изменение всех элементов по некоторому алгоритму
* <code>.inject</code> &mdash; сложение, перемножение и агрегация элементов массива
 
Набор итераторов точно такой же, как и у индексных массивов &mdash; сказывается их родство. Вот только ведут себя они несколько иначе:
* результатом является двумерный массив (как после метода <code>.to_a</code>)
* в качестве счетчика (переменной в фотографии) передается массив вида <code>[ключ, значение]</code>
== Подробнее о строках ==
 
{{info|Строка &mdash; это упорядоченная последовательность символов, которая располагается между ограничительными символами}}
 
Строковый тип является самым популярным в любом языке программирования. Ведь без него невозможно написать любую программу (особенно учитывая, что любая программа &mdash; это строка). При выводе на экран или записи в файл, любой тип данных преобразовывается к строке (явно или неявно). Это значит, что в конечном итоге все сводится к строковому типу. Кстати, и ввод данных тоже осуществляется в виде строки (и только потом преобразовывается в другие типы).
 
{{Начало цитаты}}Студенты 4-го курса МЭТТ ГАИ поступили на подготовительные курсы в МГИУ. Там им начали преподавать основы программирования на Ruby. И одна из заданных им задач была: "Дано число, необходимо поменять порядок цифр на обратный". Задача сложная, но наши студенты об этом не знали и решили ее преобразованием к строке: <code>ucxogHoe.to_s.reverse</code>. Преподаватели были поражены и впредь запретили им использовать преобразования к строке в своих программах. И все потому, что это сильно упрощало решение и давало студентам огромное преимущество перед остальными слушателями курсов.{{Конец цитаты}}
Давайте будем называть строки в минутах «ленивыми», а строки в лапках — «работящими».
 
{{info|«Вставка» &mdash; это хитрая конструкция, которая вставляется между ограничительными символами (внутрь строки). Она состоит из комбинации решетки и двух ушек ( <code><u>#{</u> 'здесь был Вася' <u>}</u></code> ). Внутри нее можно писать не только <code>'Здесь был Вася'</code>, но и любой программный код. Результат программного кода будет преобразован к строке и вставлен вместо «вставки»}}
 
{{Начало цитаты}}
{{info|Для преобразования целочисленного кода обратно в символ, используется метод <code>.chr</code>}}
 
==== Строка-перевертыш ====
 
Иногда хочется перевернуть строку задом наперед. Причины могут быть разные. Например, вы ищите палиндром (число, которое можно перевернуть без ущерба для его значения). Занимается этим благородным делом метод <code>.reverse</code>. Давайте сформируем сообщение для Иных по другую сторону Сумрака:
{{Внимание|Не стоит путать метод <code>.reverse</code> для массивов с методом <code>.reverse</code> для строк. В массивах меняется порядок элементов, а в строках — символов}}
 
==== Меняю шило на мыло! ====
 
Для того, чтобы заменить <code>"шило"</code> на <code>"мыло"</code> используется не газета "Из рук в руки", а методы <code>.sub</code> и <code>.gsub</code>:
* Название метода <code>.gsub</code> корнями уходит в язык Perl. В нем, для осуществления всевозможных замен, использовалась конструкция <code>s///<u>g</u></code>, где модификатор <code>/g</code> означал все возможные замены (от английского <u>g</u>lobal — всеобщий, глобальный)}}
 
==== Сканируем текст на оШЫбки ====
 
Давайте, найдем и посчитаем о<b>ШЫ</b>бки. Искать мы будем методом <code>.scan</code>
{{Конец цитаты}}
 
==== Правила работы со строками ====
 
Правила — это образцы к которым можно примерять строки. Правила обладают своим собственным языком, который позволяет описывать одну, две, сотню и вообще любое количество строк. Это своеобразная упаковка для множества строк в одну компактную запись.
{{info|Правила в рамках учебника будут описаны очень сжато. Многие тонкости освещены не будут, поэтому для освоения "фигур высшего пилотажа" необходимо прочитать специализированную литературу. Например, [http://www.books.ru/shop/books/82357 книгу "Регулярные выражения"]}}
 
===== Символьный класс =====
 
Символьный класс — просто конечный набор символов. Он ограничивается квадратными скобками и содержит перечисление символов, которые можно вместо него подставить. Заменяется он всего на один символ, входящий в этот класс. Примеры символьных классов:
{{info|Взгляните на примеры правил! Правда, они стали понятней? По крайней мере второе...}}
 
===== Квантификатор =====
 
Квантификатор показывает сколько раз может повторяться предыдущий символ (группа, альтернатива или еще какая нечисть). Квантификатор ограничивается парой ушек (фигурными скобками). Примеры квантификаторов:
{{info|Снова посмотрите на примеры правил. Теперь вам они понятны? Если нет, то перечитайте две предыдущие главы — в них основа правил}}
 
===== Альтернатива =====
 
Альтернатива нужна, когда необходимо объединить несколько правил в одно. При этом совпадение засчитывается, когда есть совпадение хотя бы с одним правилом. Желательно альтернативу заключать внутрь группировки (круглые скобки). Правила, входящие в альтернативу, разделяются | (палкой, которая и является альтернативой). Примеры альтернатив:
{{Внимание|В данном примере продемонстрирована альтернатива с группировкой. В принципе альтернатива может существовать и без нее, но так возникает меньше ошибок у начинающих}}
 
===== Группировка =====
 
Группировка используется, когда необходимо обрабатывать результат частями. Например, при обработке ссылок в [[w:HTML|HTML]]-документе удобно отдельно обрабатывать текст ссылки и [[w:URL|URL]]. Группировка также как и альтернатива, заключается в круглые скобки. Более того, альтернатива обрабатывается как группировка. Доступ к результату совпадения каждой группировки осуществляется посредством специальных переменных <code>$1, $2, ..., $9</code>. Подробнее группировки будут рассмотрены в подразделе "Правильная замена". Пример использования группировки:
{{info|Существует много видов группировок. Например, <code>(?:…)</code> — группировка без сохранения результата в «долларовую переменную» или <code>(?!…)</code> — негативная группировка. В любом случае они ограничиваются парой круглых скобок}}
 
===== Фиксирующая директива =====
 
Фиксирующие директивы — это символы, которые привязывают правило к некоторому признаку. Например, к концу или началу строки.
{{Внимание|Фиксирующих директив гораздо больше двух. Об остальных читайте в специализированной литературе}}
 
===== Модификатор =====
 
Модификатор предназначен для изменения поведения правила. Он размещается сразу же после правила (после последней наклонной черты). Пример использования модификатора:
Бывают следующие модификаторы:
* <b>m</b>ultiline &mdash; перенос строки считается простым символом
* <b>i</b>gnorcase &mdash; поиск без учета регистра
* e<b>x</b>tended &mdash; игнорировать пробельные символы
 
{{Внимание|Игнорирование регистра работает только для латиницы}}
{{Внимание|Рекомендуется использовать метод <code>[]</code> вместо метода <code><nowiki>=~</nowiki></code> (заимствованного из Perl), так как <code>[]</code> более функционален}}
 
==== Жадность ====
 
Речь пойдет о жадности среди квантификаторов. Возьмем некоторый квантификатор <code>{n,m}</code> и посмотрим как он работает.
 
=== Хитрости ===
==== Перенос по словам ====
Несколько лет назад (еще при жизни http://ruby-forum.ru) решали мы интересную задачу: как реализовать автоматический перенос на новую строку (wrap). Для тех, кто не застал те времена, уточню задание: дан текст, необходимо, вставить переносы таким образом, чтобы каждая из полученных строк была меньше n (для определенности <code>n=80</code>). Недавно я осознал, что не могу решить эту задачу тем способом, который был нами тогда найден. Я его просто не помнил... Решение нашлось быстро, достаточно было вспомнить, что на англ. языке эта задача именуется коротким и емким словом wrap.
 
Метод реализован только для массивов, но возможно его добавление к хешам или строкам.
 
==== Случайное число из диапазона ====
 
Студенты часто возмущаются, почему чтобы получить случайное число от 3 до 6 нужно писать нечто невнятное вида:
Итак, в чем соль? Дело в том, что для сложения векторов необходимо сложить их соответствующие координаты. В случае же с массивами происходит конкатенация (сцепление) массивов. Вот именно в этой роли вектора не имеют себе равных. В остальных случаях, замечательно работает массив.
 
=== Хитрости ===
 
=== Задачи ===
Как организована работа с файлами? В самом общем случае работа с файлами состоит из следующих этапов:
# Открытие файла. Сущность этого этапа состоит в создании объекта класса <code>File</code>.
# Запись или чтение. Вызываются привычные нам методы вывода на экран и не совсем привычные &mdash; ввода.
# Закрытие файла. Во время закрытия файла происходят действия с файловой системой. С объектом, который создается при открытии файла ничего не происходит, но после этого он указывает на закрытый файл и производить операции чтения/записи при помощи него уже нельзя.
 
config.class #-> <u>String</u></code>
 
{{Внимание|Имя файла &mdash; это строка. Не стоит усложнять себе жизнь и думать, что имя файла имеет некий "божественный" тип данных. Будьте проще и люди к вам потянутся}}
 
В примере можно увидеть, как считывается файл <code>config.yaml</code> в переменную <code>config</code>. Вторая строчка примера показывает, что, при использовании метода <code>.read</code>, файл считывается в виде строки (класс <code>String</code>). Теперь к переменной <code>config</code> можно применять любые методы из богатого строкового арсенала.
 
== Сети ==
=== Как написать [[w:Троянская программа|троян]]? ===
Однажды, один из студентов (<tt>Geka</tt>) попросил меня рассказать о том, как создать простейшее клиент-серверное приложение на Ruby. Перед тем, как подойти ко мне он уже облазил несколько форумов, но у него все равно осталось много вопросов. Отчаявшись он наконец подошел ко мне...
 
{{Конец цитаты}}
 
==== Построение серверной части ====
На руках у него уже была серверная часть программы, которая позволяла манипулировать удаленной файловой системой (как потом оказалось, ему ее презентовал <tt>Invalid</tt>). Давайте на нее посмотрим...
 
Класс <tt>GServer</tt> (и его наследники) прослушивает порт в фоновом режиме. Но если программа завершается, то завершатся и все нити (Thread's). Поэтому надо чем-то занять программу на время работы сервера. Вот и было решено ожидать завершения прослушивающей нити сервера. Эта команда останавливает выполнение программы (за исключением нитей в фоне) до окончания прослушивания экземпляром созданного класса.
 
==== Построение клиентской части ====
Как мы уже видели выше, серверная часть полностью определяет функциональность всего клиент-серверного приложения. Клиентская часть же лишь принимает от пользователя запросы, пересылает их серверу и получает ответ, который передает пользователю.
 
}}
 
=== Как создать сетевой блокнот? ===
Идея написать подобную программу появилась после прочтения статьи [http://doci.nnm.ru/php_forall_/22.11.2006/sozdaem_svoj_onlajn_bloknot/ Создаем свой online-блокнот]. Продемонстрированная там программа предельно проста, но на ее примере очень удобно показать работу с [[w:ERB|ERB]]. А учитывая тот факт, что ERB используется в составе инструментария [[w:Ruby on Rails|Руби на Рельсах]], то ценность этой статьи становится очевидной.
==== Первое приближение ====
В первом приближении мы попытаемся реализовать ту же самую функциональность, что и описана в статье. Вот только [[w:PHP|PHP]] подразумевает наличие веб-сервера, который будет заниматься интерпретацией его команд. В нашем же примере мы самостоятельно поднимем веб-сервер (написанный на Ruby), чтобы не заморачиваться с настройкой стороннего.
 
Получилось немного громоздкое описание, но это только поначалу. Дальше мы будем рассматривать только изменения, а их будет существенно меньше.
 
==== Добавляем ERB ====
Теперь приступим к ERB. Это шаблонная библиотека, которая позволяет осуществлять вставку в произвольный текст любого Ruby-кода. Для этого имеются два основных тега:
* <code><nowiki><% ... %></nowiki></code>
 
{{Начало цитаты}}"Кесарю - кесарево!" (с) [[w:Иисус Христос|Иешуа Ганоций]]{{Конец цитаты}}
==== Выносим ERB-шаблон во внешний файл ====
ERB-шаблон существенно портит красоту нашего Ruby-кода. Поэтому, решение вынести шаблон во внешний файл вполне оправдано. Тем более, что это позволит нам править ERB-шаблон отдельно от программы. Более того, внесенные в шаблон изменения будут вступать в силу без перезагрузки сервера.
 
Вот, уже другое дело! Можно было бы этим и ограничиться, если бы в библиотеке <tt>WEBrick</tt> отсутствовал бы ERB-сервлет... Но он есть!
 
==== ERB-шаблон превращается в ERB-сервлет ====
Если ERB-шаблон подключать, как ERB-сервлет, то программа существенно упрощается за счет того, что логику, которая отвечает за формирование данных можно вынести в шаблон. Чтобы это ощутить, достаточно взглянуть на новую версию нашей программы:
 
 
=== Гнезда, которые свили не птицы ===
[[ИзображениеФайл:Гнезда.png|frame|center|Примерное содержание главы]]
 
=== Как пропинговать компьютер в сети? ===
=== Приемо-передача файлов ===
 
=== Как скачать HTML-страницу ===
Для скачивания [[w:HTML|HTML]]-страниц обычно используется [[w:HTTP|протокол HTTP]]. Адрес страницы задается в виде [[w:URL|URL]]. В Руби существует несколько способов скачать страницу по протоколу HTTP. Начнем с самого древнего – класса Net::HTTP (древнее только Socket'ы, но про них мы умолчим). Для определенности мы будем скачивать этот учебник и сохранять его в виде файла RubyBook.html.
 
{{Внимание|Обратите внимание, что необходимо указывать полный URL с указанием протокола (в данном случае <nowiki>http://</nowiki>)}}
 
==== Запрос заголовка ====
Во время скачивания передается не только сама страница (<b>тело сообщения</b> или на англ. body), но и техническая информация (<b>заголовок</b> или на англ. head). Мы еще не раз будем свидетелями такого поведения в протоколах сети Интернет. В заголовке содержится информация об успешности запроса (код возврата), типе передаваемых данных, кодировке, HTTP-сервере и так далее. Для примера, мы будем производить HTTP-запрос и получать ответ только в виде заголовка. Запись заголовка в файл производить не будем, так как в реальной практике этот прием практически не используется. Сначала «потренируемся на кошках», то есть на классе Net::HTTP:
 
Мы использовали свойство метода <code>.open</code> прикреплять к себе блок.
 
==== Работа через прокси ====
Прокси-сервер – это сервер, перенаправляющий запросы другим серверам. Обычно таковой используется для скрытия истинного [[w:IP-адрес|IP-адрес]]а или для контроля за [[w:трафик|трафик]]ом.
 
 
Вот как выглядит страница <tt>index.html</tt> после обработки браузером (<tt>Firefox</tt>):
[[ИзображениеФайл:RubyBooks_Index_html.png|center|Вид страницы public_html/index.html в Firefox]]
Теперь рассмотрим серверную часть программы (сервлет <tt>/input</tt>), которая будет обрабатывать запросы (сформированные файлом <tt>public/index.html</tt>). Сервлет является частью сервера. Поэтому листинг сервера будет одновременно и листингом сервлета.
 
:* При помощи <code>resp.body = ...</code> мы формируем выходные данные (строка с HTML-кодом).
:* HTML-код: <code><nowiki><html><body><div align=center><form action='/' method='post'><textarea rows='5' cols='60'></nowiki><u>#{..}</u><nowiki></textarea><br /><input type='submit' value='Повторим?'></form></div></body></html></nowiki></code>; просто создает окружения для наших выходных данных. В частности видно, что наши выходные данные будут помещаться в тег <tt>TEXTAREA</tt>. Это сделано для того, чтобы удобней было копировать данные. Вот примерно так это будет выглядеть в браузере:
[[ИзображениеФайл:RubyBooks_Input.png|center|Пример работы сервлета /input]]
:* Код обработки данных: <code>req.query.map{ |key,value| bosses[ key ] }.compact.join("\n")</code>; получает список передаваемых параметров в виде ассоциативного массива (метод <code>.query</code>) и заменяет имена переменных на значения из ассоциативного массива <code>bosses</code>. Далее идет преобразование в строку при помощи метода <code>.join("\n")</code>.
* <code>server.start</code>
Вот почти такую программу я и презентовал секретарше Анюте. «Почти» потому, что фамилии должны идти строго в определенном порядке (чего нельзя добиться в ассоциативном массиве), но для того, чтобы посмотреть реализацию веб-сервера — продемонстрированной версии программы должно быть достаточно. Смело меняйте код и создавайте свои веб-сервера!
 
==== Сервлетки в рубиновом соусе ====
Мы уже неоднократно упоминали понятие [[w:Сервлет|сервлет]], но особенно на нем не останавливались. Давайте сейчас рассмотрим типовые сервлеты, которые имеются в стандартной поставке <tt>WEBrick</tt>
* '''Файловый сервлет'''
Ну вот вроде и все, что можно сказать по сервлетам.
 
== Приложения ==
;[[/Задачник]]:Сборник задач
;[[/Справочник]]:Справочник по базовым классам
;[[/Идеология]]:программирования вообще и на Руби в частности
 
== Дальнейшее чтение ==
=== Русскоязычные ресурсы ===
* [http://ror.ru Все о Ruby on Rails] Рускоязычный ресурс по Ruby.
=== Русскоязычная литература ===
* [http://www.shokhirev.com/mikhail/ruby/ltp/title.html Learn To Program]. Перевод Михаила В. Шохирева.
* [http://www.linuxshare.ru/docs/devel/languages/ruby/ruby.html Ruby &mdash; руководство пользователя]. Перевод Александра Мячкова.
* [http://www.ruby.linux.by/man-ruby_lections.html Конспект лекций по высокоуровневому программированию]. Шипиев Р.Н.
* [http://sabanin.ru/wp-content/articles/Rolling_with_Ruby_on_Rails_rus_translation.pdf Rolling with Ruby on Rails]. Перевод Андрея Горбатова (pdf).
* [http://www3.msiu.ru/~roganova/First_A_2005-2006/index.html Лекции по программированию]. Роганова Н.А.
 
=== Иноязычная литература ===
* [http://poignantguide.net/ruby/ ''Why’s (Poignant) Guide to Ruby'']{{ref-en}} — эта книга достойна чтения, ''даже если Вам не нужно знание Руби''. Просто шедевр. Распространяется бесплатно. <small>Там ещё богатая подсветка текста; эх, нам бы такую.</small>. [[Why's Poignant Guide To Ruby RUS|Частичный перевод здесь]].
* ''Programming Ruby'' Дэйва Томаса{{ref-en}}. Многие пытались, но не перевели на русский. Первая редакция книги содержится в пакете [http://rubyinstaller.rubyforge.org/wiki/wiki.pl «Установка за один щелчок»] для Windows. Владельцы других [[w:Операционная система|ОС]] смогут найти её в Сети (например, в виде [http://www.rubycentral.com/book/ набора вебстраниц]). Вторую редакцию книги можно купить на [http://www.amazon.com/gp/product/0974514055/sr=8-1/qid=1148659457/ref=pd_bbs_1/102-3466370-6596946?%5Fencoding=UTF8 Amazon.com] в бумажном или электронном виде.
* [http://www.meshplex.org/wiki/Ruby/Ruby_on_Rails_programming_tutorials Full Ruby on Rails Tutorial]
 
Где-то на странице (обычно слева, снизу от меню) должен быть список ссылок на параллельные версии этого викиучебника на других языках. [[de:Ruby-Programmierung]] [[en:Programming:Ruby]] [[eo:Lernolibro_pri_Rubeno]] [[pl:Ruby]]
 
[[Категория:Языки программирования]]
[[Категория:Ruby]]
[[Категория:Объектно-ориентированное программирование]]
 
[[de:Ruby-Programmierung]]
[[en:Programming:Ruby]]
[[eo:Lernolibro pri Rubeno]]
[[pl:Ruby]]
234

правки