WWW.DISS.SELUK.RU

БЕСПЛАТНАЯ ЭЛЕКТРОННАЯ БИБЛИОТЕКА
(Авторефераты, диссертации, методички, учебные программы, монографии)

 

ФЕДЕРАЛЬНОЕ АГЕНТСТВО ПО ОБРАЗОВАНИЮ

МОСКОВСКИЙ ГОСУДАРСТВЕННЫЙ ИНДУСТРИАЛЬНЫЙ УНИВЕРСИТЕТ

Е. А. Роганов, Н. А. Роганова

Программирование

на языке Ruby

Учебное пособие

МГИУ

Москва 2008

ББК 32.97

УДК 681.3

Р59

Рецензент:

И. В. Абрамов, кандидат физико-математических наук, доцент Московского государственного индустриального университета Роганов Е. А., Роганова Н. А.

Программирование на языке Ruby: Учебное пособие. — М.:

Р59 МГИУ, 2008. — 56 c.

ISBN 978-5-2760-1495-1 Настоящее пособие содержит описание языка программирования Ruby и предназначено прежде всего для студентов первого курса на правления «Прикладная математика и информатика» и специально сти «Математическое обеспечение и администрирование информаци онных систем». Оно может быть также полезно студентам инженер ных и экономических специальностей, изучающих программирование, а также учащимся старших классов.

ББК 32. УДК 681. Редактор К. В. Шмат Подписано в печать 05.02. Формат бумаги 60x84/16 Бум. офсетная Усл.печ.л. 3,5 Уч.-изд.л. 3,75 Изд. № 1-08/ Тираж 100 Заказ № РИЦ МГИУ, 115280, Москва, Автозаводская, www.izdat.msiu.ru [email protected] тел. 677-23- © Е. А. Роганов, ISBN 978-5-2760-1495- © Н. А. Роганова, © МГИУ, Оглавление Предисловие............................... 1. Основы языка Ruby......................... 1.1. Установка Ruby......................... 1.2. Первые программы....................... 1.3. Использование базовых типов.....................

2. Модификация и создание пользовательских классов 3. Тестирование и обработка исклительных ситуаций..... 3.1. Unit-тесты............................ 3.2. Обработка исключительных ситуаций............. 3.3. Тестирование последовательностей.............. 4. Стековый калькулятор и языки................. 4.1. Рекурсивная реализация компилятора правильных формул 4.2. Реализация компилятора с помощью стека.........

Приложения A. Язык программирования Ruby.................. A.1. Базовые типы.......................... A.2. Термы и выражения.......................

Литература и гиперссылки Предметный указатель......................... Предисловие Ruby, названный так в честь драгоценного камня рубина, — один из самых молодых языков современного промышленного программирования.

В МГИУ с 2003 года именно Ruby является первым из языков, которые изучают студенты-программисты. Его используют для написания простей ших программ на занятиях по информатике старшеклассники подшефных школ нашего университета. Ruby применяется сотрудниками информаци онно-вычислительного центра университета для генерации индивидуаль ных заданий по математике и информатике для студентов и слушателей факультета довузовского образования. Он же позволяет с минимальны ми затратами сил и времени решать многие другие задачи организации эффективного учебного процесса. Наконец, именно на Ruby реализована основная часть информационной системы, позволившей автоматизировать работу университета в целом.

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

Первая версия интерпретатора была обнародована создателем языка, япон ским программистом Юкихиро Мацумото (Yukihiro Matsumoto) в году. Официальный сайт, посвящённый языку Ruby, размещён по адресу http://www.ruby-lang.org, а много дополнительной полезной и интерес ной информации можно найти в Википедии — свободной Интернет-энцик лопедии (http://en.wikipedia.org/wiki/Ruby_programming_language).

Ruby — это чрезвычайно мощный, динамический, чисто объектно-ори ентированный язык, при разработке которого основное внимание было уде лено удобству программирования на нём. Многие удачные идеи, использо ванные ранее в таких языках, как Perl, Python, Smalltalk, LISP и неко торых других, в Ruby удалось гармонично объединить. Благодаря этому язык легко изучать, на нём очень легко и приятно писать программы, а в уже написанные программы легко вносить необходимые изменения.

В МГИУ с 2003 года Ruby является первым из языков, которые изу чают студенты-программисты. Его используют для написания простейших программ на занятиях по информатике старшеклассники подшефных школ нашего университета. Ruby применяется сотрудниками информационно вычислительного центра университета для генерации индивидуальных зада ний по математике и информатике для студентов и слушателей факультета довузовского образования. Он же позволяет с минимальными затратами сил и времени решать многие другие задачи организации эффективного учебного процесса. Наконец, именно на Ruby реализована основная часть информационной системы, позволившей автоматизировать работу универ ситета в целом (см. [6]).

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



1.1 Установка Ruby. Если Ваша операционная система — Linux или Mac OS X, то, скорее всего, интерпретатор языка Ruby вместе со все ми необходимыми библиотеками уже установлен. Команда ruby -v в этом случае выведет информацию о версии интерпретатора, подобную следую щей: ruby 1.8.4 (2005-12-24) [i686-linux].

Для Microsoft Windows существует так называемый One-Click Installer, который можно взять с сайта http://rubyinstaller.rubyforge.org.

Подходящий RPM-пакет для операционной системы Linux легко найти на сайте http://www.rpmfind.net, набрав в поле поиска слово ruby.

Так как Ruby — свободный программный продукт, то его исходные тек сты доступны и могут быть получены с сайта http://www.ruby-lang.org.

Установка из исходных текстов требует определённых знаний, но, как пра вило, сводится к выполнению лишь нескольких команд, подобных следую щим: tar xvfz ruby-1.8.4.tar.gz; cd ruby-1.8.4;./cogure; make install.

1.2 Первые программы. Программа на языке Ruby представля ет собой последовательность выражений и инструкций (expressions and statements), которые размещаются обычно по одному (одной) на строке.

Точка с запятой используется для отделения друг от друга инструкций на одной и той же строке, обратный слэш \ в конце строки позволяет продол жить запись выражения на следующей строчке, а комментарии начинаются с символа # и продолжаются до конца текущей строки.

Пример 1. Напишите программу, печатающую строку-приветствие.

Эта программа содержит единственную инструкцию — вызов метода puts ", !" стить в файле hello.rb, то команда ruby hello.rb запустит программу и мы увидим приветствие на экране, который является стандартным выво дом по умолчанию. Перенаправить вывод в файл с именем res.txt можно командой ruby hello.rb > res.txt.

Ruby является объектно-ориентированным языком, но допускает напи сание программ в директивном стиле. Можно считать, что наша программа содержит команду (директиву) «напечатать строку», хотя на самом деле всё устроено немного сложнее. Те сущности (называемые объектами), с которыми имеет дело программа на языке Ruby, в процессе выполнения программы взаимодействуют между собой, посылая друг другу сообщения (называемые также вызовами методов), содержащие иногда дополнитель ную информацию (объекты-параметры). Вызов метода m объекта obj с параметром arg записывают в виде obj.m(arg) или просто obj.m arg1, а единственная инструкция нашей программы является сокращением от STDOUT.puts ", !". Теперь уже ясно, что сообщение «на печатать строку» посылается объекту STDOUT — стандартному выводу.

1 Подробнее о вызовах методов рассказано на стр. 45.

Пример 2. Напишите программу, печатающую сумму первых n членов начинающейся с единицы геометрической прогрессии со знаменателем q.

Рассмотрим сначала решение, основанное на использовании известной формулы для суммы геометрической прогрессии S = (q n 1) / (q 1). Запуск этой программы даёт результат 7, а заменив 3 на 64 и запустив програм му ещё раз, мы получим знаменитое «шахматное»

число 18446744073709551615.

В Ruby (в отличие от многих других языков) легко работать с большими числами.

Программа содержит три инструкции, первые две из которых при сваивают переменным q и n значения 2 и 3 соответственно. Отметим, что сами переменные объектами не являются, а лишь указывают (ссы лаются) на различные объекты (в данном случае на числа — объекты класса Fixnum). Далее вычисляется выражение (q**n-1)/(q-1), кото рое неявно преобразуется в строку и печатается методом puts на стан дартный вывод. Вот развёрнутая форма второй инструкции программы:

STDOUT.puts ((q**n-1)/(q-1)).to_s, где метод to_s, применяемый к числу, возвращает представление этого числа в виде строки.

Кроме чисел и уже встречавшихся нам строк в языке Ruby существует ещё ряд базовых типов (см. стр. 42), для работы с которыми можно исполь зовать много различных операторов (см. стр. 48), включая стандартные арифметические операторы и оператор присваивания. Имена локальных (другие нам встретятся чуть позже) переменных должны начинаться с ма ленькой латинской буквы и могут содержать также большие буквы, цифры и символ подчёркивания. Имена констант (например, STDOUT) должны на чинаться с большой буквы. Более полная информация об использовании имён приведена на стр. 45.

Другое решение этой задачи, использующее цикл while, требует чуть больших комментариев. Переменные s и i используются в этой программе как аккумулятор для накопления сум q = 2; n = мы прогрессии и счётчик цикла соответственно. Вначале i=s= они обнуляются, а на каждой итерации цикла, выполнение while i < n которого продолжается, пока величина i остаётся мень s += q**i ше n, значение s увеличивается на очередной член про i += грессии, а значение i — на единицу. После завершения цикла остаётся только напечатать результат. Заметим, что выражение i += a эквивалентно i = i + a.

2 Согласно легенде, изобретатель шахмат Сета потребовал от индусского царя Шерама, решившего наградить его, выдать за первую клетку доски одно пшеничное зерно, за вторую — два, за третью — четыре и так далее, вплоть до последней, шестьдесят четвёртой.

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

Даже хорошее знание лучших языков программирования не заменяет знания математики.

1.3 Использование базовых типов. Часто программы получа ют данные из файлов, запрашивают их с клавиатуры или берут непосред ственно из командной строки. Проиллюстрируем последнюю из этих воз можностей на примере решения следующей несложной задачи.

Пример 3. Напишите программу, печатающую сумму цифр десятичного представления натурального числа, задаваемого в командной строке.

После запуска программы test.rb командой ruby test.rb 123 Маша в массиве ARGV окажутся все аргументы командной строки, указанные при её запуске, то есть строки 123 и. Выражение ARGV[0] даёт первый элемент массива (строку 123). Для решения задачи этого достаточно, а более подробно с массивами (Arrays) можно познакомиться, заглянув на стр. 43. Таблица A.10 на стр. 47 содержит перечень наиболее часто ис пользуемых предопределённых объектов Ruby-программы (ARGV — один из них).

Так как последняя цифра числа n равна остатку от деления на 10 (n%10), n = ARGV[0].to_i s= while n > end puts s образование числа в строку. Запустить эту програм Для опытного человека написание подобной программы не является проблемой, но новичок может сделать в ней несколько самых разных оши бок, поэтому будущих программистов знакомят с математическими метода ми проектирования циклов. Подобные знания зачастую абсолютно необхо димы, но рассматриваемую задачу даже новичок сможет решить безоши бочно, если воспользуется так называемым подходом Ruby (Ruby way).

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

Новая версия программы содержит последовательный вызов всего трёх методов и состоит из одной строки.

puts ARGV[0].scan(/./).inject(0){|s,x| s+x.to_i} Метод scan3 с па раметром /./ пре образует строковое представление числа ARGV[0]в массив цифр, который обрабатывается методом inject — одним из так называемых итерато ров, последовательно выполняющим действия, указанные в блоке (код в фигурных скобках), над каждым из элементов массива. При этом перемен ная s сначала инициализируется нулём, а на каждой итерации увеличива ется на величину x.to_i, равную числовому значению очередной цифры x.

Полученный результат затем печатается методом puts.

Отметим, что inject является методом модуля Enumerable, который включается (mix in) в различные классы, расширяя их возможности. Кроме массивов таким классом являются диапазоны (Ranges), чаще всего исполь зуемые в качестве последовательностей элементов: натуральные числа от 3 до 9 (3..9 или 3...10), латинские буквы от D до H ('D'..'H') и т. п. При решении следующей задачи использование итератора each для диапазона чисел является вполне естественной идей.

Пример 4. Является ли простым число 15 485 863?

Напомним, что натуральное число является простым, если оно имеет ровно два различных делителя. Интерес к простым числам связан прежде всего с их использованием в криптографии. Подробнее об этом можно узнать на сайте http://www.utm.edu/research/primes и на страницах Википедии (http://en.wikipedia.org/wiki/Prime_numbers).

Наивный алгоритм проверки простоты числа n очевиден: будем после довательно находить остатки от деления n на числа 2, 3, 4 и так далее, вплоть до n-1. Если хотя бы один из остатков окажется нулевым, то число простым не являет n = 15_485_ ся. Итератор each для каждого элемента диапа (2... n).each do |i| зона выполняет блок (начинающийся do и закан if n%i == чивающийся end4), проверяющий это условие и puts false; exit прекращающий выполнение программы (метод exit) в случае его выполнения. В Ruby oперато ры if, while и некоторые другие являются про 3 Список всех методов класса String приведён в разделе Library Reference книги [3].

Команда ri String печатает его целиком, а команда ri String#scan — описание метода scan.

4 Блок принято ограничивать do-end вместо {}, если его тело занимает несколько строк.

сто модификаторами выражений, что не так во многих других языках (обязательно ознакомьтесь с примерами на стр. 49).

Программа станет намного изящнее и понятнее, если воспользоваться n=15_485_863; puts !(2...n).any?{|i| n%i==0} Enumerable. Этот метод проверяет для элементов i диапазона (2...n) заданное в блоке условие n%i==0 и возвращает «истину» (true), как толь ко встретит элемент, ему удовлетворяющий. Если же таких элементов не найдётся, то метод возвратит «ложь» (false). Отрицание (!) полученного результата является ответом на вопрос о простоте числа n.

Аналогичный методу any? метод all? модуля Enumerable позволяет проверить истинность заданного в блоке условия для всех элементов кол лекции. Этот модуль определяет ещё целый ряд методов, полный перечень можно получить с помощью команды ri Enumerable.

Пример 5. Найдите минимальное четырёхзначное число, уменьшающее ся на 27 после перестановки его последней цифры на первую позицию.

Последняя цифра числа x — это x%10, а число, получающееся после её puts (1000...10000).find{|x|x/10+1000*(x%10) == x-27} ражения x/10+1000*(x%10). Таким образом, нам нужно найти (nd) пер вое число из диапазона 1000...10000, для которого выполняется условие x/10+1000*(x%10) == x-27. Это делает метод find (или detect).

Заметим, что методы find_all и select, будучи применёнными к кол лекции, возвращают массив всех тех её элементов, которые удовлетворяют заданному в блоке условию, а метод reject возвращает элементы, для ко торых условие оказывается ложным.

Пример 6. Напечатайте квадраты всех натуральных чисел, не больших тысячи, десятичная запись которых заканчивается на 396.

Для решения задачи достаточно применить метод map (или collect), p (1..1000).map{|t|t*t}.select{|x|x%1000==396} 5 Подробнее об именах методов рассказано на стр. 45.

элементам коллекции, а затем выбрать из него нужные числа. Метод p печатает массив (как и иные объекты) в более удобном виде, чем puts.

Пример 7. Выясните, является ли заданная в командной строке после довательность символов палиндромом. Напомним, что палиндром — это последовательность, которая не изменяется после её инвертирования (пе реворачивания). Ограничимся в этой задаче только малыми русскими бук вами и пробелами, которые должны игнорироваться. Вот примеры палин дромов: «поп», «шалаш», «аргентина манит негра», «а роза упала на ла пу азора». Если программа, решающая эту задачу, содержится в файле palindrome.rb, то команда ruby palindrome.rb аргентина манит негра должна напечатать true.

Как мы уже знаем, объект ARGV содержит массив аргументов командной строки. Метод join класса Array «склеивает» в одну строку все его эле менты, а метод reverse класса String инвертирует строку.

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

Пока мы использовали только методы, определённые для классов и мо дулей стандартной библиотеки, но часто при написании программ полезно создавать свои методы. Напри мер, при решении задачи о про def prime?(n) стоте числа естественно опреде not (2... n).any?{|i| n%i == 0} лить метод prime? с одним па end раметром (числом), возвращаю щий true или false. Затем его puts x if prime?(x) можно использовать для того, чтобы найти и напечатать все простые числа из диапазона 15_485_800..15_485_863. Подробнее про определение методов рассказано на стр. ??.

Пример 8. Реализованный выше метод prime? работает достаточно мед ленно. Говорят, что его сложность линейна6, ибо для простых чисел выпол няется почти n итераций. Реализуйте метод prime?, работающий быстрее.

Заметим, что если n = pq, то одно из чисел p и q заведомо не пре восходит n. До этой величины и достаточно выполнять проверку7. Для вычисления квадратного корня используем метод sqrt модуля Math.

6 Более точно это формулируют так: асимптотическая сложность метода есть (n).

7 Поэтому сложность получающейся программы будет равна ( n) def prime?(n) not (2.. Math.sqrt(n)).any?{|i| n%i == 0} end (15_485_800.. 15_485_863).each{ |x| puts x if prime?(x) } Без знания математики хорошей программы не напишешь.

Пример 9. Многочлен можно задать массивом его коэффициентов. На пример, многочлену x 3 +2x 3 соответствует массив [1,0,2,-3], а массив [1,2] задаёт многочлен x + 2. Реализуйте метод, позволяющий перемно жать два многочлена, заданные их коэффициентами.

мы эта формула совершенно не нужна. Достаточно заметить, что степень def mul(p,q) r = Array.new(p.size+q.size-1,0) p.each_with_index do |u, i| q.each_with_index do |v, j| p mul([1,0,2,-3],[1,2]) идею проще всего с помощью Enumerable, который последовательно выполняет заданный блок для всех элементов коллекции, передавая в него сам элемент и его индекс. Метод size класса Array используется для определения количества элементов в нём, а метод new с двумя параметрами этого же класса создаёт новый массив указанного размера, заполненный нулями. Массивы в Ruby при меняют очень часто, так как их можно использовать в качестве стеков, очередей, деков, списков и других структур данных. Некоторые из методов класса Array описаны на стр. ??.

Пример 10. Реализованный в примере 8 метод prime? является слишком медленным для получения списка всех простых чисел от 2 до миллиона.

Напишите программу, решающую эту задачу за «разумное время».

Более двух тысяч лет назад греческий математик Эратосфен придумал алгоритм, называемый сейчас «решетом Эратосфена» 8. В простейшем ва рианте он выглядит так. Выпишем сначала все числа от 2 до n. Затем от метим первое простое число 2 и вычеркнем все числа, кратные ему. Далее отметим первое из ещё не отмеченных и не вычеркнутых чисел (это будет число 3), и вычеркнем все числа, кратные ему (включая и те, которые уже вычеркнуты). Будем продолжать данный процесс, пока это возмож n = Integer(ARGV[0]) но. В итоге останутся только про sieve = [] стые числа. Слегка модифициро for i in 2.. n ванный алгоритм приводит к про грамме, которая через несколько секунд после её запуска командой ruby sieve.rb 1000000 печатает список всех простых чисел, мень ших миллиона. Первая инструк ция программы содержит вызов метода Integer модуля Kernel, который делает почти то же самое9, что используемый нами ранее метод to_i класса String, — преобразует строку в число. В созданный далее пустой массив sieve заносятся числа от 2 до n с помощью цикла for.

Массив при этом растёт: после первого присваивания он содержит три элемента ([nil,nil,2]), после второго — уже четыре и т. д. Цикл for является лишь удобным сокращением для известного нам итератора each:

запись for i in 2.. m неявно преобразуется в (2.. m).each do |i|.

В следующем цикле число не обрабатывается, если оно равно nil, то есть уже вычеркнуто (см. таблицу A.12 на стр. 49). Вычёркивание всех ему кратных осуществляет итератор min.step(limit,step){|i| block} класса Numeric, который выполняет block, начиная со значения i=min, увеличивая его после каждой итерации на step до тех пор, пока оно не станет больше, чем limit. Воспользуйтесь командой ri compact для вы яснения того, что делает метод compact.

Учитесь находить нужную Вам информацию в книгах, справочных системах и сети Интернет.

Пример 11. Числами Фибоначчи называют последовательность, задава емую следующими формулами: f0 = 0, f1 = 1, fn = fn1 + fn2 для n > 1.

Напишите рекурсивный метод вычисления величины fn.

например, http://en.wikipedia.org/wiki/Sieve_of_Eratosthenes.

8 Смотри, 9 Integer учитывает также индикаторы системы счисления — префиксы 0, 0b и 0x.

Числа Фибоначчи встречаются и в науке, и в природе чрезвычайно часто10, а последовательность этих чисел занимает весьма почётное место в Интернет-энциклопедии целочисленных последовательностей11, которая является очень интересной сама по себе.

Рекурсивным называют метод, который вызывает сам себя, и написать n < 2 ? n : fib(n-2) + fib(n-1) деление последовательности чисел if a then b; else c end (см. таблицу A.12 на стр. 49).

Пример 12. С помощью написанного рекурсивного метода практически невозможно находить числа Фибоначчи fn для больших значений n, так как даже на вычисление сорокового числа на компьютере с тактовой ча стотой процессора 2.4 Ghz требуется почти 6 минут. Реализуйте метод, позволяющий найти миллионное число Фибоначчи за «разумное время».

Требуемое решение можно получить, рассматривая преобразование F, def fib(n) return n if n < for i in 2.. n (обратите внимание на множественное (параллель a, b = b, a+b ное) присваивание, см. стр. 49) имеет линейную p fib(1_000_000) заданными в постановке задачи характеристиками ведь в его десятичной записи содержится 86784 цифры!

require 'matrix' (Matrix[ [1,1], [1,0] ]**n)[0,1] можно получить ещё более быст на сайт http://www.mcs.surrey.ac.uk/Personal/R.Knott/Fibonacci.

10 Загляните 11 http://www.research.att.com/~njas/sequences.

. Первая строка этих матриц содержит числа Фибоначчи, а так как возведение в степень (в том числе и матриц) выполняется быстро, то вычисление чисел Фибоначчи таким способом оказывается весьма эффек тивным.

Для работы с матрицами, которые не входят в число базовых типов языка Ruby, необходимо с помощью директивы require подключить биб лиотеку, в которой определён класс Matrix и методы для манипулирования с объектами этого класса. Миллионное число Фибоначчи последняя про грамма находит почти в два с половиной раза быстрее, чем предыдущая, и разница в скорости их работы увеличивается с ростом номера n числа fn.

1.4 Упражнения Задача 1. Оператор ** в Ruby реализован весьма эффективно по сравнению с наивным способом умножения основания на себя нужное число раз. Напишите программу с применением цикла while, которая будет возводить число a в нату ральную степень n за время, сопоставимое со временем работы оператора a**n даже для больших значений показателя.

Задача 2. Измените написанную при рассмотрении примера 7 программу так, что бы она работала и в ситуации, когда исследуемая строка заключается в апострофы или кавычки. Например, команда ruby palindrome.rb ’аргентина манит негра’ должна печатать true.

Задача 3. Какие изменения следует внести в программу умножения многочленов (пример 9), если коэффициенты многочленов задавать в обратном порядке — от младших степеней к старшим?

Задача 4. Напишите программу, находящую для всех чисел от 1 до задаваемого в командной строке натурального n, массив списков (массивов) всех делителей этих чисел. Для n = 6, например, программа должна напечатать следующую строку:

[[1], [1, 2], [1, 3], [1, 2, 4], [1, 5], [1, 2, 3, 6]].

Задача 5. Назовём билет с натуральным номером, десятичная запись которого состоит из чётного количества (2n) цифр, счастливым, если сумма первых его n цифр равна сумме n последних. Напишите программу, вычисляющую количество счастливых билетов для заданного натурального n.

Задача 6. Напишите программу, способную вычислить количество счастливых билетов (см. задачу 5) для n = 1000 за «разумное время» (например, около секунд на компьютере с тактовой частотой процессора 2.4 Ghz).

Задача 7. Напишите такую программу, решающую задачу 4, чтобы время её ра боты для n = 106 удовлетворяло требованиям, сформулированным в задаче 6 (это ограничение касается собственно нахождения массива; вывод такого огромного количества данных требует заметного дополнительного времени).

Задача 8. Программа умножения многочленов, приведённая на стр. 12, имеет квадратичную сложность (количество операций при перемножении двух многочле нов степени n пропорционально n2). Так называемое быстрое преобразование Фу рье (см. книгу [5]) позволяет сделать это быстрее. Реализуйте алгоритм быстрого умножения многочленов таким образом.

2. Модификация и создание пользовательских классов Ruby является объектно-ориентированным языком программирования.

Давайте рассмотрим особенности представления классов.

Объекты и классы В реальной жизни все объекты обладают индивидуальными свойства ми. Но, введя некоторые обобщения, можно поделить объекты реальной жизни на группы. Каждая из таких групп будет обладать одинаковым набо ром свойств и, как следствие, к ней будут применимы одинаковые наборы действий.

В языке программирования Ruby для описания набора свойств групп объектов и применимых к этим объектам действий используется такое понятие, как Класс — это формальное описание основных end свойств объекта (его атрибутов) и методов, приме def msiu нимых к нему. Задав описание класса, в дальнейшем можно создавать столько его экземпляров, сколько потребуется.

Классы в Ruby — открыты; если нам не хватает функциональности класса, то мы можем дополнить класс новым методом или переопределить старый.

Иерархия классов и полиморфизм Зачастую из класса можно выделить группу объектов, обладающую каким-либо специальным свойством. Такую группу называют подклассом, или дочерним классом. Дочерний класс наследует все свойства родитель ского класса, но обладает отдельной функциональностью. С помощью сим вола < указывается родительский класс.

Пример 1.

Птицы всех видов несут яйца, но не все птицы умеют летать. Хотя в классе Penguin и не описан метод lay_egg, при необходимости он ищется (и находится!) в родительском классе (принцип наследования, иерархиче ская организация классов). Метод fly переопределен для пингвинов, и реакция на вызов этого метода определяется принадлежностью к тому или 18 Модификация и создание пользовательских классов иному классу (полиморфизм, различные реалиции на одинаковую коман ду).

class Bird def lay_egg puts " #{self.class}. !" class Penguin < Bird puts " #{self.class}..."

b = Bird.new; b.lay_egg; b.fly p = Penguin.new; p.lay_egg; p.fly Создание класса Дальнейшее описание проиллюстрируем обыкновенными дробями. В процессе вычислений нередко возникает необходимость работы с дробны ми числами. Учитывая ограничения по точности представления чисел с плавающей точкой в компьютере, иногда бывает необходимо производить вычисления в терминах обыкновенных дробей, представляющих собой от ношение целого числителя и целого знаменателя. В Ruby имеется класс Rational, описывающий такие дроби. Представим на время, что его нет и создадим нечто подобное.

class Frac def initialize(a, b) raise 'Division by zero' if b.to_i == @numerator, @denominator = a.to_i, b.to_i когда мы создаем эк тельную ситуацию (об этом будет рассказано позже) и выдает соот ветствующее сообщение об ошибке.

Переменные экземпляра Переменные @numerator, @denominator — это переменные атрибу ты экземпляра класса. В именах переменных экземпляра необходимо ис пользовать префикс @. Каждый объект, принадлежащий данному классу, имеет свои собственные значения этих атрибутов (свойства), но пока их можно использовать только внутри методов самого класса. При попытке обратиться к таким переменным извне класса будет выдано сообщение об ошибке. Что же делать, если хочется иметь доступ к переменным экзем пляра вне класса?

Один способ состоит в создании методов, возвра щающих значение соответствующего атрибута. Но в случае большого числа атрибутов такой подход не удобен. Язык Ruby предлагает более удобную воз можность.

Для контроля доступа к переменным экземпляра можно использовать макросы attr_reader (для чте ния), attr_writer (для изменения значения) и attr_accessor (для выдачи разрешения на оба действия).

Метод to_s, присут ствующий в классе, опре деляет, как объект должен отображаться при печати.

Переопределение x.denominator = операторов Оперирование дробя ми предполагает возможность производить математические действия, на пример, сложение. Символ + является оператором языка Ruby. Но неко торые операторы для удобства пользователя могут быть переопределены.

Но не все! Например, + может быть переопределен, = нет.

Реализуем операцию сложения дробей самостоятельно. Чтобы дроби не получались избыточными, нам надо будет уметь их сокращать. Это поз воляет сделать алгоритм Евклида.

20 Модификация и создание пользовательских классов class Frac def initialize(a, b) raise 'Division by zero' if b.to_i == @numerator,@denominator = a.to_i, b.to_i simplify() raise "Undefined method + for class Frac and #{b.class}!" return Frac.new(self.numerator * b.denominator + private def simplify() x, y = @numerator.abs, @denominator.abs @numerator, @denominator = @numerator / m, @denominator / m В операторе сложения мы проверяем, что второй аргумент операции + тоже является объектом типа Frac.

if b.kind_of?(Frac) ект относится к тому или иному классу, при помощи метода kind_of?.

Ключевое слово self указывает на объект, вызвавший метод. Запись self.numerator эквивалентна @numerator.

Метод simplify реализует алгоритм Евклида, упрощающий дроби.

Чтобы у нас всегда были упрощенные дроби, он вызывается в конструкторе класса. Ключевое слово private определяет право доступа к следующим за ним методам только внутри класса. Таким образом, метод simplify не может быть использован вне класса Frac.

Аналогично + мы можем также переопределять и логические опера торы. Например, оператор ==, позволяющий сравнивать два объекта на равество.

class Frac def ==(b) if !b.kind_of?(Frac) raise "Undefined method == for class Frac and #{b.class}!" return (self.numerator == b.numerator and self.denominator == b.denominator) Если нам хочется, чтобы объекты нашего класса можно было бы срав нивать между собой (и, как следствие, сортирововать массив таких объ ектов методом sort), то необходимо переопределить метод. Метод должен возвращать 0 если объекты равны между собой; отрицательное число, если первый аргумент меньше второго; и положительное число в остальных случаях.

class Frac if !b.kind_of?(Frac) raise "Undefined method for class Frac and #{b.class}!" return self.numerator * b.denominator b.numerator * self.denominator Переменные класса В случае необходимости иметь какую-то одинаковую для всех объектов класса характеристику используют переменные класса, которые синтак сически выделяются указанием префикса @@ в их имени.

Предположим, что нам потребовалось знать общее количество дробей, созданных при работе с классом Frac. Добавив в конструктор класса команду инкре мента такой переменной, мы сможем узнать количество созданных дробей.

22 Модификация и создание пользовательских классов Методы класса С понятием применения метода связано понятие ответственности за его выполнение. Иногда за то или иное действие отвечает не объект, а сам класс. В этом случае применяется метод класса. При его задании перед именем метода указывается имя класса.

def dist(a) sqrt((a.x-@x)**2 + (a.y-@y)**2) def R2Point.dist(a, b) sqrt((a.x-b.x)**2 + (a.y-b.y)**2) p2 = R2Point.new(-1,-2) бя ответственность за выполне puts R2Point.dist(p1, p2) обе участвуют в данной опера подход состоит в команде, отдаваемой самому классу: «класс, определи расстояние между двумя объектами».

3. Тестирование и обработка исклительных ситуаций 3.1 Unit-тесты. Проанализировав, на что уходит время у большин ства программистов, — можно обнаружить, что на написание кода в дей ствительности тратится совсем небольшая часть. Какая-то часть уходит на понимание задачи, еще кусок на проектирование, а большую часть вре мени занимает отладка. Отладка — это процесс проверки программы на соответствие поставленной задаче, хотя чаще под этим определением пони мают работу по нахождению ошибок в программе. Отладка — это «страш ная вещь», и любой программист может рассказать о том, как на поиски какой-то ошибки ушел день или даже больше. Исправить ошибку мож но довольно быстро, но самое сложное — найти её. А при исправлении ошибки всегда существует возможность добавить новую, которая проявит ся гораздо позднее.

Из опыта предыдущих курсов было замечено, что студент написав про грамму, как правило, поверхностно проверяет её на работоспособность, а некоторые даже не запускают программу, почему-то считая, что раз уж они её написали, то она просто обязана работать правильно. Доходит до того, что студенты пытаются сдать программы, не обрабатываемые интер претатором или компилятором.

Поэтому одной из основных целей этого курса можно считать задачу обучения студента проверке (тестированию) программ. У новичков процесс тестирования выглядел обычно следующим образом. Написав программу, студент запускал ее один раз (или несколько, в зависимости от количе ства частных случаев, рассмотренных в программе) и, получив похожий на правду ответ, считал, что задача решена. Если же программа выдава ла неверный ответ, то он пытался найти ошибку и затем заново запускал программу.

Очевидно такая схема написания неудобна. Например, пусть отлажи ваемая программа ищет пересечение двух прямоугольников. В процессе проверки нам придется неоднократно (для проверки различных частных случаев) вводить координаты различных прямоугольников (по восемь чи сел на тест). Понятно, что необходимо как-то автоматизировать этот про цесс. Один из способов — поместить тестовые данные в файл и считывать их оттуда при старте программы. Такой способ позволяет нам экономить на вводе тестовых данных, но этапа сравнения полученных решений с тре буемыми при этом способе не избежать. Для решения этой задачи про граммисты на Ruby обычно используют специальную библиотеку TestUnit 24 Тестирование и обработка исклительных ситуаций (подобного рода библиотеки есть в большинстве современных языков про граммирования, в языке Java, например, для этих целей используется пакет JUnit).

Приведем простой пример, в котором протестируем довольно простую программу о разложении чётного числа на сумму простых.

def number_decomposition(number) num1, num2 = number/2, number/ while num1 > 1 and num2 < number if prime?(num1) and prime?(num2) return nil if FILE == $ p number_decomposition(142) Метод number_decomposition использует рассмотренный (стр. 10) нами ранее метод prime? (проверка числа на простоту).

Исходная программа была подготовлена к процессу тестирования. Ме тод number_decomposition возвращает полученный результат (вместо пе чати, который мы будем сравнивать с набором подготовленных шаблонов).

Тело условного оператора в конце программы будет выполнено только в случае, если интерпретатору на выполнение будет передан данный файл с программой, при подключении этого файла командой require условие FILE == $0 будет ложно.

Для тестирования создадим подкласс базовой библиотеки тестирова ния. Обратите внимание на стили наименований: имя такого класса должно начинаться с префикса Test, а имена тестирующих методов — с лексемы test. Каждый тест содержит набор сравнений — специальных функций, имя которых начинается со слова assert.

Метод assert получает два аргумента (второй — необязательный): ло гическое выражение и текстовое сообщение. Если логическое выражение окажется ложно, то программа добавит 1 к числу неуспешных проверок и выведет сообщение о неудаче. Кроме этого, будет напечатано тексто вое сообщение, переданное методу в качестве второго аргумента. Метод assert_equal получает три аргумента (третий — необязательный): ожидае мое значение, сравниваемое значение (как правило результат работы тести руемой функции) и сообщение, которое будет выведено при несовпадении первого и второго аргументов. Метод assert_nil проверяет, является ли аргумент объектом nil.

require "test/unit" require "number_decomposition4test.rb" class TestNumberDecomposition < Test::Unit::TestCase def setup def test_prime?

assert(false == prime?(1)) assert false == prime?(10) assert_equal(true, prime?(2), " 2") assert_equal true, prime?(7), " 7" assert_equal(true, prime?(103)) def test_number_decomposition assert_nil(number_decomposition(2)) assert_equal([5, 5], number_decomposition(10)) assert_equal [7, 11], number_decomposition(18) assert_equal [97, 103], number_decomposition(200) Вы можете добавлять в класс вспомогательные методы и использовать их в тестовых случаях, но только методы, начинающиеся с test, будут за пущены во время выполнения теста! Тесты вызываются в том порядке, в котором они представлены в программе. Если в тестирующем классе при сутствуют методы с именами setup и (или) teardown, то они будут выпол нены соответственно перед запуском всех тестов и после их завершения.

Очень полезно писать тесты до начала программирования.

Посмотрим на результат работы данной программы. Его можно ин терпретировать таким образом. Выполнено 2 теста (tests) и 9 сравнений (assertions). Обнаружено 0 сбоев (failures) и 0 ошибок (errors). Это озна чает, что программа теоретически работает и, наверное, все в порядке.

26 Тестирование и обработка исклительных ситуаций $ ruby test_number_decomposition.rb Loaded suite test_number_decomposition Started Finished in 0.003189 seconds.

2 tests, 9 assertions, 0 failures, 0 errors Ради эксперимента искусственно внесем ошибку в метод prime?, сделав так, чтобы он считал единицу простым числом.

Запуск теста моментально обнаруживает ошибку, показав место, где произошел сбой — седьмую строку с выражением assert false == prime?(1) (отметим, что количество сбоев стало равным одному). Изучив тестовый случай, можно понять, где произошла ошибка и в чем причина. Теперь выполнять тесты стало очень легко.

$ ruby test_number_decomposition.rb Loaded suite test_number_decomposition Started Finished in 0.061807 seconds.

1) Failure:

test_prime?(TestNumDecomposition) [test_number_decomposition.rb:7]:

is not true.

2 tests, 5 assertions, 1 failures, 0 errors Когда требуется ввести в программу новую функцию, начните с созда ния теста. Это не так странно, как может показаться. Когда вы пишите тест, то спрашиваете себя, что нужно сделать для добавления этой функ ции и как она должна работать.

3.2 Обработка исключительных ситуаций. В большинстве современных языков программирования предусмотрена возможность ра боты с исключительными (особыми) ситуациями. В языке Ruby програм мисты могут работать как со встроенными ситуациями, так и с ситуа циями, создаваемыми по указанию программиста при наличии того или иного события. Типичные встроенные ситуации — это «деление на ноль»

(ZeroDivisionError) или «достижение конца файла» (EOFError).

Перейдем к простому примеру, в котором мы бу дем обрабатывать исключительную ситуацию «деле ние на ноль». При запуске данной программы возни кает исключительная ситуация (ZeroDivisionError).

Для реализации механизма исключений в языке Ruby присутствуют следующие ключевые слова: rescue, raise, ensure.

rescue — поймать и обработать исключение, находящееся в блоке.

raise — генерировать исключительную ситуацию.

ensure — всегда выполнить код, заключенный в этот блок.

Обработаем ситуацию, описанную выше, внеся опасный участок кода в блок обработки исключения rescue.

Если кроме блока rescue присутствует блок ensure, то он будет выполнен в лю бом случае. Поэтому зача стую блок ensure использу ют для освобождения заре зервированных ресурсов. В puts " ensure !" следующей программе блок end ensure следит за освобож дением дескриптора файла.

f = File.open("testfile") begin #..

f.close unless f.nil?

Будьте внимательны при использовании исключений. Использование конструкции rescue без ука зания конкретного исключения приводит к обработке всех ошибок.

Любая библиотека Ruby возбуждает исключения при возникновении любой ошибки, и вы также можете явно возбуждать ошибки в своем коде.

Создать исключение программист может с помощью метода raise модуля Kernel (или его синонима fail). Рассмотрим его применение на следую щих примерах:

28 Тестирование и обработка исклительных ситуаций raise raise "Missing name" if name.nil?

if i >= names.size raise IndexError, "#{i} >= size (#{names.size})" Первая форма просто перехватывает текущее исключение и позволяет тем или иным способом затем обработать его. Старайтесь не использовать форму возбуждения исключения без аргумента, так как она не информатив на. Второй пример демонстрирует передачу сообщения при возбуждении исключения. Вид возбужденного исключения в этом случае можно узнать, определив тип переменной $!

sum = begin a.each { |x| sum += 1 } rescue end В некоторых ситуациях программист не может сказать, когда закончит ся процесс ввода данных. Например, на вход поступает некая последова тельность чисел. При завершении ввода требуется выдать какую-нибудь характеристику последовательности. В такой систуации уместно исполь зовать обработку исключений (конкретно, ситуацию EOFError). Начнем с ряда простых примеров.

begin rescue EOFError puts " #{sum}" end прибавляем его значение к переменной sum. При завершении ввода печа тается значение переменной sum. (При вводе даннных с консоли нажатие Ctrl-D (CTRL-Z в Windows) завершает ввод.) Обратим внимание на распро страненную ошибку. При работе с последовательностью не следует использовать контейнеры (объекты arr = @str.length cur = @str[@index].chr def compileT compileM return if @index >= @str.length cur = @str[@index].chr def compileM if @str[@index].chr == '(' def compileV print "#{@str[@index].chr} " Аналогичным способом в соответствии с грамматикой реализуются ме тоды «обработать терм», «обработать множитель». А метод «обработать переменную» заключается лишь в выводе на экран переменной и пропуске очередного элемента.

Однако, если попытаться откомпилировать нашим компилятором фор мулу a b c, то мы увидим, что последовательность символов для стеко вого калькулятора соответствует формуле a (b c), т.е. в этой ситуации компилятор работает неверно (традиционная операция вычитания ассоци ативна слева, а у нас скобки «накапливаются» справа) 1.

Обработка ввода формул (RunRecursComp.rb) require "RecursCompf" c = RecursComp.new while true c.compile(readline.chomp) 4.2 Реализация компилятора с помощью стека. Граммати ку, описанную в предыдущем разделе, легко преобразовать к виду, соответ ствующему правильному порядку выполнения арифметических действий:

формулатерм|формула + терм|формулатерм терммножитель|терммножитель|терм/множитель множитель(формула)|переменная переменнаяa|b|c|...|z Однако рекурсивно реализовать соответствующий этой грамматике ком пилятор так, как это было сделано раньше, нельзя. Невозможно, напри мер, при обработке формулы по очередному элементу определить, надо ли обрабатывать терм или формулу. Но даже если бы это оказалось возмож ным, мы бы не имели права в программе обработки формулы рекурсивно обратиться к себе, так как в этот момент непрочитанная часть еще не из менилась и, следовательно, в этом месте программа бы обращалась к себе до бесконечности.

Приведенную выше реализацию компилятора правильных формул мож но подправить так, чтобы операции выполнялись в нужном порядке. Заме 1 На самом деле ошибка возникла не из-за работы компилятора, а из-за некорректно написанной грамматики, в чем легко убедиться, рассмотрев дерево вывода формул для данной грамматики.

тим, однако, что при этом основное достоинство рекурсивной реализации — простая связь грамматики и программы — будет утеряно. Поэтому мы сначала изменим форму описания языка и лишь потом переделаем компи лятор.

Введем новые понятия: аддитивная операция = +, ; мультипликатив ная операция =·, /; и зададим понятия терма и формулы в новой форме:

формулатерм{ терм } терммножитель{ множитель}, где фигурные скобки означают повторение содержимого нуль или более раз. Остальные понятия грамматики, описанной в предыдущем разделе, оставим без изменения. При реализации компилятора в соответствии с но вым описанием языка паре фигурных скобок будет соответствовать цикл.

Метод «обработать формулу», например, будет заключаться в следую щем: сначала обрабатывается терм, затем начинается цикл, внутри кото рого происходит выбор: непрочитанных элементов нет выход из цикла;

очередной элемент + пропустить очередной элемент, обработать терм, напечатать “+”; очередной элемент пропустить очередной элемент, обработать терм, напечатать “”; иначе выход из цикла.

Аналогичным образом модифицируется метод «обработать терм». При компиляции по новой программе формула a b c будет обработана пра вильно.

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

Прежде всего заметим, что любую правильную формулу можно ском пилировать так, что: 1) переменные в последовательности для стекового калькулятора будут идти в том же порядке, что и переменные в форму ле; 2) все операции в последовательности будут расположены позже соот ветствующих знаков операций в формуле. (Этот факт легко доказывается индукцией по числу знаков операций в формуле.) Таким образом, формулу можно компилировать так: встретив имя пере менной, немедленно его напечатать, а встретив знак операции или скобку, печатать те из предыдущих, но еще невыполненных операций (будем их называть отложенными), которые выполнимы в данный момент, после чего «откладывать» и новый знак. Поскольку среди оставшихся отложен ных операций нет таких, которые выполнимы до пришедшего знака, то для хранения можно воспользоваться стеком (назовем его стеком операций).

Этот стек и есть та информация, которая необходима для индуктивной компиляции формулы.

Рассмотрим реализацию стека. Для этого мы создадим класс Stack.

Вообще стек реализовать достаточно просто, так как фактически для его правильной работы необходимы всего лишь четыре метода: конструктор;

метод, помещающий элемент в стек; метод, берущий элемент из стека, и метод, показывающий вершину стека.

class Stack def initialize @array = Array.new def push(c) @array.push(c) @array.pop @array.last Класс Compf Давайте теперь разберем класс Compf — компилятор формул, исполь зующий стек операций. Класс Compf является подклассом класса Stack и имеет методы всех трёх типов доступа: public, protected и private. Компи лятор допускает только однобуквенные имена переменных.

require 'Stack' class Compf < Stack def compile(str) "(#{str})".each_byte { |c| processSymbol(c.chr) } def symType(c) when '+', '-', '*', '/' def processSymbol(c) case symType(c) processSuspendedSymbol(c) processSuspendedSymbol(c) def processSuspendedSymbol(c) while precedes(top, c) Работа начинается с вызова метода compile, в котором все символы строки str последовательно передаются методу processSymbol.

def priority(c) def precedes(a, b) return false if symType(a) == SYM_LEFT return true if symType(b) == SYM_RIGHT priority(a) >= priority(b) protected def symOther(c) def nextOper(c) def nextOther(c) nextOper(c) Квалификатор доступа protected и метод nextOther нужны для созда ния на базе класса Compf нового класса Calc, реализующего калькулятор формул2.

Класс Calc (калькулятор числовых формул) выведен из класса Compf, переопределяет некоторые методы последнего, и имеет дополнительный стек для размещения в нём чисел. Калькулятор работает только с цифрами (числами от 0 до 9).

Несколько комментариев к методу nextOper(c) класса Calc. Множе ственное присваивание в первой строке метода корректно, т.к. в языке Ruby при выполнении множественного (параллельного) присваивания сна 2 Хотя в языке Ruby в данном случае можно убрать "protected тем самым размещая все нижеописываемые константы и методы в зоне действия квалификатора private, в языках Java и C++ здесь нужен именно квалификатор protected.

чала последовательно вычисляются все выражения в правой части опе ратора присваивания.

require 'Compf' class Calc < Compf def initialize def compile(str) protected def symOther(c) def nextOper(c) second, first = @s.pop, @s.pop @s.push(first.method(c).call(second)) def nextOther(c) @s.push(c.to_i) Конструкция first.method(c).call(second) во второй строке метода мо жет быть объяснена таким примером: выражение 3.metod(’-’).call(2), экви валентно выражению 3.-(2) или просто 3-2.

Задача 1. Добавьте операции sin, cos и унарный минус.

Задача 2. Добавьте правоассоциативную операцию ^ возведения в степень.

Задача 3. Добавьте квадратные и фигурные скобки.

Задача 4. Измените программу так, чтобы допускались в качестве имен переменных произвольные идентификаторы языка Ruby.

Задача 5. Добавьте левоассоциативную операцию % с приоритетом, рав ным приоритету операции /.

Задача 6. Добавьте возможность записи формулы с пробелами и коммен тариями двух типов (/* */ и //).

Задача 7. Измените программу так, чтобы ввод, содержащий в качестве аргументов только восьмеричные числа (начинающиеся с нуля, например 056), компилировался в программу, содержащую десятичные числа.

Задача 8. Измените программу так, чтобы ввод, содержащий в качестве ар гументов только шестнадцатеричные числа (начинающиеся с 0x, например 0x56), компилировался в программу, содержащую восьмеричные числа.

Задача 9. Измените программу так, чтобы ввод, содержащий в качестве ар гументов только римские числа, не превосходящие 5000, компилировался в программу, содержащую десятичные числа.

Задача 10. Измените программу так, чтобы для коммутативной операции аргументы выдавались в алфавитном порядке.

Задача 11. Добавьте фигурные скобки, означающие возведение в квадрат.

Используйте операцию DUP стекового калькулятора.

Задача 12. Считая, что a = 0, оптимизируйте формулу (уберите лишние сложения).

Задача 13. Считая, что b = 1, оптимизируйте формулу (уберите лишние умножения).

Задача 14. Добавьте возможность ввода формулы на нескольких строках.

A. Язык программирования Ruby A.1 Базовые типы. Базовыми типами языка Ruby являются чис ла, строки (объекты класса String), массивы (класс Array), диапазоны (Range), хэши или ассоциативные массивы (Hash), символы (Symbol) и ре гулярные выражения (объекты класса Regexp). Любое целое число x Z может быть представлено объектом класса Fixnum (если величина |x| не слишком велика) или Bignum (иначе), но лишь конечное подмножество из несчётного множества действительных чисел R представимо в виде объек тов класса Float, часто называемых числами с плавающей точкой.

-1234567890 -1234567890345 целое число — объект класса Bignum 1_234_567_890 1234567890345 подчёркивания в записи чисел игнорируются -123.45 -123.45 «действительное» число (класс Float) 1.2345e+2 123.45 экспоненциальная формы записи Для задания строк можно использовать кавычки (") или апострофы (').

В первом случае распознаются и интерпретируются так называемые эс кейп-последовательности (например, \n, \", \t, \r) и выполняется подста новка результатов вычисления выражения expr вместо подстроки #{expr}.

В обоих случаях последовательности \\ и \' преобразуются в символы \ и ' соответственно. Существуют и другие способы задания строк, некото рые из которых показаны в таблице A.2.

"2 + 3 = #{2+3}" "2 + 3 = 5" подстановка вычисленного выражения '2 + 3 = #{2+3}' "2 + 3 = #{2+3}" подстановка не выполняется %q( Ruby) " Ruby" аналог строки в апострофах %Q(#{2**32}) "4294967296" аналог строки в кавычках "a\nb" всего три символа: буквы a и b разделены символом \n Массив (Array) в Ruby — это набор (коллекция, множество) произ вольных объектов (см. таблицу A.3).

[1, 2.3, "Ruby"] [1, 2.3, "Ruby"] массив из трёх элементов [[1,2],[3]] [[1, 2], [3]] массив из двух массивов %w( ?) ["", "?"] способ создания массива строк %w(\ ?) [" ", "?"] экранирование пробела %W(2 3 #{2*3}) ["2", "3", "6"] подстановка значения выражения Диапазон (Range) — последовательность объектов, которая включает (для e1..e2) или не включает (для e1...e2) в себя элемент e2. Исполь зуемый в качестве итератора диапазон передаёт в блок все свои элементы (как при вызове метода to_a, преобразующего диапазон в массив).

'd'..'n' ["d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n"] Хэш (Hash) — это набор пар ключ–значение. Хэш схож с массивом, за исключением одной особенности — индексация производится с помощью объектов любых типов, кроме integer. Причем порядок обхода элементов не зависит от порядка вставки.

Примеры хэшей приведены ниже:

Hash["a",1,"b",2,"c",3 ] {"a"=>1, "b"=>2,"c"=>3} хэш из трех элементов Hash["a" => 1, "b" => 2] {"a" => 1, "b" => 2} хэш из двух элементов Как видно из примера, для создания хэша часто используются лите ралы key => value. Ключ и значения находятся в паре, поэтому число аргументов должно быть четным.

Хэши имеют значение по умолчанию. Это значение возвращается ка ким-либо итератором при попытке обращения к ключу, не существующему в хэше. И этим значением является nil.

Регулярные выражения (объекты класса Regexp) используются для подбора шаблона строки. Для создания регулярных выражений нужно ис пользовать литералы /.../ или %r..., а также конструктор Regexp.new. От метим, что разные версии Руби используют разные средства для работы с регулярными выражениями.

При создании регулярных выражений могут идти следующие парамет ры:

С помощью регулярных выражений можно:

Проверять, соответствует ли вся строка целиком заданному шаблону.

Находить в строке подстроки, удовлетворяющие заданному шаблону.

Извлекать из строки подстроки, соответствующие заданному шабло Изменять в строке подстроки, соответствующие шаблону.

Примеры использования регулярных выражений приведены в таблице А7.

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

A.2 Термы и выражения. Термами в языке Ruby являются лите ралы (объекты базовых типов), результаты выполнения команд операци онной системы, генерации символов и вызова методов, а также значения констант и переменных.

Вызов метода m объекта obj1 со списком параметров arg и блоком blk (иначе называемый посылкой сообщения m получателю obj) записывают в виде obj.m(arg){blk} или obj.m(arg) do blk end. Для вызовов, выпол няемых вне классов («на верхнем уровне»), получателем является main — экземпляр класса Object, создаваемый при старте Ruby-программы. При меры вызовов методов приведены в таблице A.8.

В языке Ruby имена используются для ссылок на константы, перемен ные, методы, классы и модули. В таблице A.9 перечислены зарезервиро ванные слова, которые не могут быть использованы в качестве имён.

Имена констант должны начинаться с большой латинской буквы (от A до Z), за которыми может следовать любая последовательность больших и малых латинских букв, цифр и символов подчёркивания (_).

Переменные в языке Ruby бывают четырёх различных видов: локаль ные, экземпляра, класса и глобальные. Имена локальных переменных должны начинаться с малой латинской буквы (от a до z) или символа подчёркивания, за которыми может следовать любая последовательность больших и малых латинских букв, цифр и символов подчёркивания. В име нах локальных переменных, состоящих из нескольких слов, рекомендуется использовать подчёркивание, например, day_week.

К именам переменных экземпляра вначале добавляется символ @ (на пример, @x), переменных класса — два таких символа (например, @@name), а глобальных переменных — символ $ (например, $_). Некоторые пред определённые объекты имеют имена, отступающие от этого правила.

Методы, не являющиеся переопределяемыми операторами (см. табли цу A.11), должны иметь имя, образованное по тем же правилам, что и име на локальных переменных. К имени метода может быть добавлен восклица тельный (!) или вопросительный знак (?), либо символ =. Рекомендуется использовать такие имена для методов, изменяющих объект-получатель (self), возвращающих логическое значение и допускающих использова ние в левой части оператора присваивания соответственно.

Имена классов и модулей являются константами и следуют описанным выше правилам. Рекомендуется для констант, определяемых в классах, ис 1 В случае отсутствия явного получателя им является объект self некоторого класса, в контексте которого происходит данный вызов.

puts ", !" Получатель — предопределённый объект main клас 2.+(3) Получатель — число 2 (объект класса Fixnum).

[1,2,3][0]=4 Получатель — массив [1,2,3] (см. таблицу A.11).

"123".to_i Получатель — строка "123". Метод to_i класса "123".to_i(8) Параметр 8 указывает, что строку надо рассматри 3.times do |i| p i end Получатель — число 3. Параметров нет, но имеется a=[1,2,3,4,5] Получатель — экземпляр a класса Array, включаю a.inject(0){|s,x|s+x} щего в себя модуль Enumerable. Метод inject при [1,2].to_i Получатель — массив [1,2]. Так как класс Array, пользовать только большие буквы и символ подчёркивания, а при построе нии имён классов и модулей применять так называемый MixedCase, когда каждое из слов, образующих сложное имя, пишется с большой буквы.

Выражение представляет терм или несколько термов, объединённых с помощью перечисленных в таблице A.11 операторов. Приоритеты операто Таблица A.9. Зарезервированные слова языка Ruby ров, разделённых горизонтальными линиями, различны и убывают сверху вниз. Многие из операторов являются методами и могут быть переопреде лены. Примеры использования операторов приведены в таблице A.12.

Таблица A.10. Некоторые предопределённые стандартные объекты ARGF или $< Object Объект, предоставляющий доступ к конкатенации всех ARGV или $* Array Массив строк, содержащий аргументы командной стро ENV Object Подобный хэшу объект, содержащий значения перемен DATA IO Если программа содержит директиву END, то DATA RUBY_PLATFORM String Идентификатор платформы (операционной системы с дополнительными характеристиками), на которой вы RUBY_VERSION String Версия интерпретатора Ruby STDOUT IO Стандартный вывод, начальное значение $stdout FILE String Имя файла, содержащего выполняемую программу LINE String Номер текущей строки в программе = %= ~= /= -= += Присваивание и присваивания с операцией Нет



Похожие работы:

«ФЕДЕРАЛЬНОЕ АГЕНТСТВО ПО РЫБОЛОВСТВУ ФЕДЕРАЛЬНОЕ ГОСУДАРСТВЕННОЕ ОБРАЗОВАТЕЛЬНОЕ УЧРЕЖДЕНИЕ ВЫСШЕГО ПРОФЕССИОНАЛЬНОГО ОБРАЗОВАНИЯ МУРМАНСКИЙ ГОСУДАРСТВЕННЫЙ ТЕХНИЧЕСКИЙ УНИВЕРСИТЕТ И. А. Дудина ЛОГИКА Допущено Ученым советом университета в качестве учебно-методического пособия для студентов всех форм обучения по гуманитарным и социально-экономическим направлениям и специальностям Мурманск 2009 УДК 16 (075.8) ББК 87.4 я 73 Д 81 Дудина, И. А. Логика : учеб.-метод. пособие для студентов всех форм...»

«Федеральное агенство по образованию Государственное образовательное учреждение Высшего профессионального образования ГОРНО-АЛТАЙСКИЙ ГОСУДАРСТВЕННЫЙ УНИВЕРСИТЕТ Кафедра агрохимии и защиты растений Основы научных исследований в агрономии Учебно- методический комплекс Для студентов, обучающихся по специальности 110201 Агрономия Горно-Алтайск РИО Горно-Алтайского госуниверситета 2008 Печатается по решению методического совета Горно-Алтайского госуниверситета УДК ББК Авторский знак Основы научных...»

«Государственное санитарно-эпидемиологическое нормирование Российской Федерации 3.1.2. ИНФЕКЦИИ ДЫХАТЕЛЬНЫХ ПУТЕЙ КРИТЕРИИ РАСЧЕТА ЗАПАСА ПРОФИЛАКТИЧЕСКИХ И ЛЕЧЕБНЫХ ПРЕПАРАТОВ, ОБОРУДОВАНИЯ, ИМУЩЕСТВА, ИНДИВИДУАЛЬНЫХ СРЕДСТВ ЗАЩИТЫ И ДЕЗИНФЕКЦИОННЫХ СРЕДСТВ ДЛЯ СУБЪЕКТОВ РОССИЙСКОЙ ФЕДЕРАЦИИ НА ПЕРИОД ПАНДЕМИИ ГРИППА Методические рекомендации МР 3.1.2.0004-10 Издание официальное Москва 2010 Критерии расчета запаса профилактических и лечебных препаратов, оборудования, имущества, индивидуальных...»

«Учреждение образования БЕЛОРУССКИЙ ГОСУДАРСТВЕННЫЙ ТЕХНОЛОГИЧЕСКИЙ УНИВЕРСИТЕТ ЭКОНОМИЧЕСКОЕ ОБОСНОВАНИЕ ДИПЛОМНЫХ ПРОЕКТОВ Методические указания для студентов специальностей 1-48 01 02 Химическая технология производства и переработки органических веществ, 1-48 01 05 Химическая технология переработки древесины, 1-48 02 01 Биотехнология заочной формы обучения Минск 2008 УДК 336.45(075.8) ББК 65.9(2)304.17я73 Э 40 Рассмотрены и рекомендованы к изданию редакционноиздательским советом университета...»

«ИНСТИТУТ •ОТКРЫТОЕ ОБЩЕСТВО • Учебная литература по гуманитарным и социальным дисциплинам для высшей школы готовится и издается при содействии Института Открытое общество (Фонд Сороса) в рамках программы Высшее образование Редакционный совет: В.И. Бахмин, Я.М. Бергер, Е.Ю. Гениева, Г.Г. Дилигенский, В.Д. Шадриков ИНСТИТУТ ОТКРЫТОЕ общество ЦЫГАНКОВ П.А. МЕЖДУНАРОДНЫЕ отношения Рекомендовано Государственным комитетом Российс кой Федерации по высшему образованию в качестве учебного пособия для...»

«МИНИСТЕРСТВО ОБРАЗОВАНИЯ И НАУКИ РОССИЙСКОЙ ФЕДЕРЕЦИИ Федеральное государственное автономное образовательное учреждение высшего профессионального образования ЮЖНЫЙ Южный федеральный университет ФЕДЕРАЛЬНЫЙ ТЕХНОЛОГИЧЕСКИЙ ИНСТИТУТ УНИВЕРСИТЕТ в г. Таганроге Г.Г. Галустов В.С. Плаксиенко Н.Е. Плаксиенко УСТРОЙСТВА ПРИЕМА И ОБРАБОТКИ СИГНАЛОВ УЧЕБНОЕ ПОСОБИЕ Часть Таганрог УДК 621.391.262(075.8)+621.391.24(075.8) Галустов Г.Г., Плаксиенко В.С., Плаксиенко Н.Е. Под ред. В.С. Плаксиенко Устройства...»

«Методические рекомендации по разработке программ профессиональной ориентации и профессиональной подготовке подростков с девиантным поведением по востребованным на рынке труда профессиям 1. Общие положения 1.1. Нормативную правовую основу разработки примерной образовательной программы профессиональной подготовки (далее – программа) составляют: Федеральный закон Об образовании. Федеральный закон от 21.07.2007 № 194-ФЗ О внесении изменений в отдельные законодательные акты Российской Федерации в...»

«Идущим дорогой через ринг: учебное пособие, 2000, Рашид Камалетдинов, 5858403050, 9785858403050, Инсан, 2000 Опубликовано: 27th April 2008 Идущим дорогой через ринг: учебное пособие СКАЧАТЬ http://bit.ly/1otHQ3d,,,,. Жеода сбрасывает друмлин в то же время устанавливается достаточно приподнятый над уровнем моря коренной цоколь. Хвостохранилище деформирует основной шельф на границе с Zapadno-Karelskim поднятием своеобразную систему грабенов. Роговая обманка аккумулирует kalievo-natrievyiy...»

«Государственное образовательное учреждение высшего профессионального образования Челябинский государственный педагогический университет Профессионально – педагогический институт Кафедра педагогики и психологии профессионального образования С. Г. Литке ОБЩАЯ ПСИХОЛОГИЯ Методические рекомендации Серия: УЧЕБНО-МЕТОДИЧЕСКОЕ ПОСОБИЕ по выполнению самостоятельной работы по специальности 050501 - Профессиональное обучение (очная и заочная формы обучения) Челябинск Государственное образовательное...»

«АННОТАЦИЯ В методических рекомендациях рассмотрены организационные мероприятия и вопросы разработки и реализации проектов реконструкции жилых домов с надстройкой и обстройкой здания без отселения жителей с привлечением средств собственников и других источников внебюджетного финансирования в условиях города Москвы (далее – Проект). Приведены перечни необходимых работ, основополагающих законодательных и нормативных актов, участников проекта реконструкции, а также регламент их взаимодействия....»

«Учреждение образования Белорусский государственный технологический университет УТВЕРЖДЕНА Ректором БГТУ Профессором И.М. Жарским 24.06.2010 г. Регистрационный № УД-410/баз. ТЕХНОЛОГИЧЕСКИЕ ПРОЦЕССЫ В ПРОИЗВОДСТВЕ ТЕХНИЧЕСКОГО СТЕКЛА Учебная программа для специальности 1-48 01 01 Химическая технология неорганических веществ, материалов и изделий специализаций 1-48 01 01 06 Технология стекла и ситаллов и 1-48 01 01 10 Технология эмалей и защитных покрытий 2010 г. УДК 666.117(073) ББК 35.41я Т...»

«2 3. Ротач В.Я. Теория автоматического управления: учебник для вузов. – 2-е изд., перераб. и доп.– М.: Издательство МЭИ, 2004. Метрология, стандартизация и сертификация. 1.Общие вопросы стандартизации и сертификации. Основные понятия и определения в области стандартизации: цели и задачи стандартизации; нормативные документы, используемые в области стандартизации. 2. Стандартизация и сертификация. Термины и определения, относящиеся к качеству продукции: основные понятия в области сертификации;...»

«Министерство образования Республики Беларусь Учреждение образования Брестский государственный технический университет Кафедра экономики и организации строительства МЕТОДИЧЕСКИЕ УКАЗАНИЯ по расчёту и проектированию временного строительного хозяйства при разработке строительных генеральных планов в составе курсовых и дипломных проектов для студентов строительных специальностей дневной и заочной форм обучения Брест 2002 УДК У 725 (07) Методические указания предназначены для расчёта и...»

«Международный консорциум Электронный университет Московский государственный университет экономики, статистики и информатики Евразийский открытый институт В.С. Белов Информационноаналитические системы Основы проектирования и применения Учебно-практическое пособие Издание 2-ое, переработанное и дополненное Москва 2005 1 УДК 004.415 ББК 32.973.202 Б 435 Белов В.С. ИНФОРМАЦИОННО-АНАЛИТИЧЕСКИЕ СИСТЕМЫ. Основы проектирования и применения: учебное пособие, руководство, практикум / Московский...»

«Пояснительная записка Рабочая программа составлена на основе Федерального Государственного стандарта, Программы для общеобразовательных учреждений. Химия //Программы для общеобразовательных учреждений. Химия. 8-11 классы. - М.: Просвещение, 2009. – 55 с.//. Н.Н.Гара. Изучение химии в 9 классе направлено на достижение следующих целей: освоение важнейших знаний о химической символике, об основных химических понятиях, фактах, теориях и законах химии; овладение умениями наблюдать химические...»

«ПОЯСНИТЕЛЬНАЯ ЗАПИСКА Рабочая программа по православной культуре для 8 класса разработана на основе авторской программы учебного предмета Православная культура для средних общеобразовательных школ, гимназий и лицеев. В. Д. Скоробогатов, Т. В. Рыжова, О. Н. Кобец. — Ульяновск: ИНФОФОНД, 2006, 62 с. Цели и задачи рабочей программы: формирование мотивации к изучению духовно-мировоззренческих основ отечественной культуры, православной литературы; основ православной нравственности, морали, этики и...»

«МИНИСТЕРСТВО КУЛЬТУРЫ российском ф едера ци и Ф ЕДЕРАЛЬН О Е ГОСУДАРСТВЕННО Е БЮ ДЖ ЕТНОЕ О Б Р А ЗО В А Т Е Л Ь Н О Е У Ч Р Е Ж Д Е Н И Е В Ы С Ш Е Г О О Б Р А ЗО В А Н И Я С А Н К Т -П Е Т Е РБ У Р Г С К И Й Г О С У Д А РС Т В Е Н Н Ы Й У Н И В Е РС И Т Е Т КИ Н О И Т Е Л Е В И Д Е Н И Я Рабочая программа учебной дисциплины История искусств Направление подготовки/специальность: 54.03.01. Дизайн (072500.62 Дизайн) Профиль подготовки / специализация - Дизайн в медиаиндустрии Квалификация...»

«МИНИСТЕРСТВО ОБРАЗОВАНИЯ И НАУКИ РОССИЙСКОЙ ФЕДЕРАЦИИ ФЕДЕРАЛЬНОЕ ГОСУДАРСТВЕННОЕ БЮДЖЕТНОЕ ОБРАЗОВАТЕЛЬНОЕ УЧРЕЖДЕНИЕ ВЫСШЕГО ПРОФЕССИОНАЛЬНОГО ОБРАЗОВАНИЯ САМАРСКИЙ ГОСУДАРСТВЕННЫЙ ТЕХНИЧЕСКИЙ УНИВЕРСИТЕТ ТЕОРЕТИЧЕСКИЕ ОСНОВЫ ЭЛЕКТРОТЕХНИКИ Методические указания и задания к контрольным работам для студентов дистанционной и заочной форм обучения Самара 2013 УДК 621.3 (075.8) М-991 Теоретические основы электротехники: метод. указ. / В.М. Мякишев, М.С.Жеваев. – Самара: Самар. гос. техн. ун-т,...»

«МИНИСТЕРСТВО ЗДРАВООХРАНЕНИЯ РЕСПУБЛИКИ БЕЛАРУСЬ ГОСУДАРСТВЕННОЕ УЧРЕЖДЕНИЕ ОБРАЗОВАНИЯ БЕЛОРУССКАЯ МЕДИЦИНСКАЯ АКАДЕМИИ ПОСЛЕДИПЛОМНОГО ОБРАЗОВАНИЯ КАФЕДРА ФИЗИОТЕРАПИИ И КУРОРТОЛОГИИ КАФЕДРА ХИРУРГИИ А.Н. Мумин, А.В. Волотовская, В.Н. Подгайский ФИЗИЧЕСКИЕ ФАКТОРЫ В ЛЕЧЕНИИ И РЕАБИЛИТАЦИИ БОЛЬНЫХ ПОСЛЕ ОПЕРАЦИИ РЕПЛАНТАЦИИ СЕГМЕНТОВ КОНЕЧНОСТЕЙ Учебно-методическое пособие для врачей Минск, БелМАПО 2010 УДК 616-089.168.1(075.9) ББК 53.54я М Рекомендовано в качестве учебно-методического пособия...»

«DISCUSSION PAPER Institute of Agricultural Development in Central and Eastern Europe АГРАРНЫЙ СЕКТОР РОССИИ НА ПОДЪЕМЕ?! АНАЛИЗ ТЕХНИЧЕСКОЙ ЭФФЕКТИВНОСТИ АГРАРНЫХ ПРЕДПРИЯТИЙ ГЕНРИЕТТE ШТАНГЕ, АЛЕКСЕЙ ЛИССИТСА DISCUSSION PAPER NO. 69 2004 Theodor-Lieser-Strae 2, 06120 Halle (Saale), Deutschland Telefon: +49-345-2928 110 Fax: +49-345-2928 199 E-mail: [email protected] Internet: http://www.iamo.de Генриетте Штанге в 2003 году успешно завершила учебу в университете им. Гумбольдта в Берлине на...»






 
2014 www.av.disus.ru - «Бесплатная электронная библиотека - Авторефераты, Диссертации, Монографии, Программы»

Материалы этого сайта размещены для ознакомления, все права принадлежат их авторам.
Если Вы не согласны с тем, что Ваш материал размещён на этом сайте, пожалуйста, напишите нам, мы в течении 1-2 рабочих дней удалим его.