Журнал LinuxFormat - перейти на главную

LXF89:Нестандартное программирование

Материал из Linuxformat
Перейти к: навигация, поиск

Содержание

Ruby без Rails

Вы слыхали о Ruby on Rails — а сейчас Майк Сондерс расскажет вам о его основе, Ruby, ярком примере современного языка высокого уровня…

Вот и еще одна статья из цикла об «экзотических» языках программирования. Язык Tcl, с которым мы познакомились месяц назад, очень подходит для разработки оконных приложений с графическим интерфейсом, а сейчас мы займемся Ruby, предназначенным для создания серверных и сетевых приложений. Заскучали? Напрасно. Сейчас объясним, почему.

Мы постараемся не погрязнуть в техноязе: на то есть подробнейшая документация. Вместо этого мы начнем с основ языка, затем напишем простенькое приложение, а в завершение — полноценный web-проект. Вы уже знакомы с азами программирования? Отлично! Читайте дальше, и вы поймете, что Ruby достоин вашего внимания. Многие из нас слышали о Ruby в контексте Ruby on Rails, современного программного каркаса [framework]. На его основе сейчас разрабатываются крупные сайты (например, Basecamp, Jobster или 43 Things), и он поставляется с новой версией OS X, Leopard. На ринг Ruby вышел совсем недавно, и тем удивительнее тот факт, что его разработка ведется с 1993 года!

Детище Юкихиро Мацумото [Yukihiro Matsumoto] увидело свет в 1995 году. Ключевой особенностью языка стал принцип освобождения программиста от черной работы. Зачем продираться через заковыристый синтаксис, если требуется сделать что-то простое?

Проработав более двух лет на C++ и найдя, что он все еще сталкивается с неприятными сюрпризами, Мацумото решил создать язык, максимально оправдывающий ожидания — чтобы в нем программы делали именно то, что интуитивно предполагалось, и отсутствовали тупиковые случаи. «Прежде всего надо думать о людях», провозгласил Юкихиро, «о том, как они мыслят о программе и как представляют себе действия машин. Люди — хозяева. А машины — работники».

С историей — все, теперь о кодировании: Ruby называют «мультипарадигменным» [multiparadigm] языком. Это жутковатое слово означает, что язык включает и объектно ориентированный подход, и процедуры с функциями. Ruby — интерпретирующий язык, и его синтаксис близок к Python и Perl, поэтому он осваивается без труда.

Освоимся

Для начала нам понадобятся интерпретатор языка Ruby и интерактивный интерпретатор irb, поставляемые с большинством дистрибутивов. Последнюю версию этих программ вы найдете в разделе Разработка нашего DVD.

Вызовем интерпретатор, набрав irb в командной строке. На экране появится строка приглашения — можно с ходу вводить операторы языка. По традиции полагалось бы вывести «Hello world» — «Здравствуй, мир», но это старо как мир… Будем оригинальны:

puts "Goodbye moon!"

Вроде все ясно: команда puts просто выводит на экран текстовую строку. Но в Ruby абсолютно все, даже строковые константы, — это объекты. Может, оно и странно, зато позволяет делать штуки вроде

"BlaBlaBlaa".length

С виду чушь, а на выходе печатается 10 — вполне настоящая длина строки. Или, например,

"Mmm, donuts".index("d")

возвращает 5, позицию символа d в заданной строке. (Учтите, нумерация в Ruby начинается с нуля, а не с единицы.)

Итак, Ruby — страна объектов, где программировать значительно проще. Вдобавок, это еще и язык с динамической типизацией: переменные не нужно объявлять до их использования. Вот пример:

puts "Do you love Ruby yet?"
answer = gets
puts "You answered " + answer

На экран выводится вопрос, потом объявляется переменная answer, и в нее тут же записывается результат команды gets (ввод строки с клавиатуры). Наш ответ затем выводится на экран.

Заодно продемонстрирована операция над переменными: строки можно складывать (+) и даже умножать:

mystring = "Some" + "text"
puts mystring
anotherstring = "Wowzers" * 10
puts anotherstring

Сначала две строки объединяются, и результат выводится на экран. Затем строка anotherstring заполняется десятью копиями строки Wowzers, и результат также выводится на экран. Именно эффективные функции обработки текста обеспечили Ruby место под солнцем в мире разработчиков сайтов. Неплохо знать и метод chomp (вы могли встретить его в Perl): он убирает из строки последний символ, перевод строки (\n), который автоматически добавляется командой gets при вводе. Метод понадобится в тех случаях, когда нужно преобразовать введенную строку в число, то есть в «голые цифры»:

x = gets.chomp.to_i

Мы создали переменную x, ввели строку командой gets, откинули у нее символ перевода строки с помощью chomp и методом to_i преобразовали ее в числовое значение, которое затем присвоили x. Тип переменной x можно проверить:

x = gets.chomp.to_i
x.is_a?(Integer)
x.is_a?(String)

Это показывает, что x — число, а не строка. Но мы можем немедля использовать x и как строку, если надо — благодаря динамической типизации. [Вопросительный знак является допустимым символом и часто используется в Ruby в именах методов, которые «отвечают на вопрос», — прим. ред.]

Условия, циклы и функции

Разобравшись с переменными и вводом/выводом строк, перейдем к управляющим конструкциям языка. Каждый из приведенных ниже примеров нужно предварительно сохранить в текстовом файле и запускать командой ruby <имя_файла>. Сохраните следующий пример в файле test.rb и запустите командой ruby test.rb — он иллюстрирует использование условного оператора if и кодовых блоков:

puts "How many kittens do you have?"
x = gets.chomp.to_i
if x > 0 # More than zero kittens
    puts "You have " + x.to_s + " kittens"
else
    puts "Aww, you have no kittens!"
end

Мы запрашиваем у пользователя строку, затем уже известным нам методом to_i преобразуем ее в число. Далее оператор условия if сравнивает введенное число с нулем. Если условие в операторе if истинно, число преобразуется в строку с помощью метода to_s, чтоб вписать его в сообщение, и сообщение выводится его на экран.

Если же пользователь ввел 0, выполняются команды, расположенные после else, то есть выводится другое сообщение. Блок кода завершается командой end. Между прочим, для лучшей читаемости текста мы применили отступы — можно их вводить клавишей табуляции, а можно и просто пробелами. Все как в других языках!

Справа от оператора if помещен комментарий (в языке Ruby они предваряются символом #).

С циклами тоже проблем нет:

10.times do
    puts "Ruby rocks"
end

Все ясно — десять раз выводится строка! Оператор while ничуть не сложнее:

x = 0
while x != 15
    puts "Please enter 15"
    x = gets.chomp.to_i
end

Этот код требует у пользователя ввода строки до тех пор, пока не получит число 15. Тогда он покидает блок while/end и продолжает выполнение кода (правда, в данном случае выполнять уже нечего).

Программирование на языке высокого уровня обязательно подразумевает модульность, так что займемся процедурами. Как мы уже говорили, Ruby — объектно-ориентированный (ОО) язык, аналогично C++, C# или Python. Но даже если вы знакомы только с обычным C, можете не бояться ОО-сложностей, по крайней мере, на начальном этапе. Рассмотрим использование функций:

def doubler(value)
    value = value * 2
    return value
end
puts "Enter a number"
x = gets.chomp.to_i
y = doubler(x)
puts y.to_s

Первая половина скрипта — описание функции, она не будет исполняться при запуске. Функция doubler умножает число value (аргумент функции) на два и возвращает результат. Из кода видно, как используется функция. (Обратите внимание, что функции должны быть объявлены до их использования, иначе Ruby выдаст ошибку.)


Выполнение программы начинается с команды puts: у пользователя запрашивают число, и оно передается в качестве параметра функции doubler. Результат, возвращаемый функцией, записывается в переменную y. Наконец, значение переменной y выводится на экран. Создание объектов в Ruby выходит за рамки данной статьи; хотите узнать больше — обратитесь на сайты, указанные во врезке «Ссылки» на этой странице.

Работать чисто

Обработка исключительных ситуаций в Ruby блаженно проста, например:

puts "Divide 5 by what?"
x = gets.chomp.to_i
begin
    y = 10 / x
rescue ZeroDivisionError
    puts "Eeep, divide by zero!"
end
puts y.to_s

Мы берем у пользователя число, потом входим в блок begin/end с разделом rescue внутри. Если пользователь, допустим, введет 5, в переменную y записывается частное от деления 10 на 5 и результат выводится на экран.

А вдруг он введет ноль? Возникнет ошибка. В таких случаях происходит возврат в командную строку и вывод сообщения, над которым вы и будете ломать голову. Но мы не зря ввели обработчик исключения. Возникшая исключительная ситуация (деление на ноль) будет зафиксирована, и выполнится оператор puts внутри обработчика исключения, который выведет на экран сообщение об ошибке.

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

Создаем web-сервер

Применим полученные знания и напишем собственный… web-сервер! Экстрим? Да нет, в Ruby это совсем несложно, благодаря библиотеке socket. Конечно, для Apache наш сервер конкурентом пока не станет, но зато продемонстрирует возможности Ruby. И вообще, зачем устанавливать и настраивать мощный сервер, если вам всего-то нужно хранить пару web-страничек для доступа к ним по локальной сети? Вы напишете собственный сервер на Ruby быстрее, чем произнесете «/etc/apache/httpd.conf»!

Сохраните следующий код в файле webserver.rb в вашем домашнем каталоге. (Если вам лень набирать, возьмите его из раздела Magazine/Ruby нашего DVD.) Затем создайте в этом же каталоге две HTML-странички: index.html и test.html, с произвольным содержимым, лишь бы выводилось в браузере.

require 'socket'
webserver = TCPServer.new('127.0.0.1', 7125)
while (session = webserver.accept)
    session.print "HTTP/1.1 200/OK\r\nContent-type:text/html\r\n\r\n"
    request = session.gets
    trimmedrequest = request.gsub(/GET\ \//, '').gsub(/\ HTTP.*/, '')
    filename = trimmedrequest.chomp
    if filename == ""
        filename = "index.html"
    end
    begin
        displayfile = File.open(filename, 'r')
        content = displayfile.read()
        session.print content
    rescue Errno::ENOENT
        session.print "File not found"
    end
    session.close
end

Запустите программу командой ruby webserver.rb и проверьте, как она работает. Для этого в адресной строке браузера введите http://127.0.0.1:7125. Если все нормально, вы должны увидеть содержимое странички index.html! Соответственно, набрав http://127.0.0.1:7125/test.html, вы увидите содержимое странички test.html. Код говорит сам за себя, но мы все равно разберем его подробно.


Начинается код с команды require, подключающей внешние библиотеки. В данном случае мы используем библиотеку socket — это набор процедур, сильно упрощающий сетевое программирование (см. врезку «Модные модули» справа). Следующая строка создает объект сервера на локальном IP-адресе 127.0.0.1 и порте 7125. Номер порта может быть любым, но для использования портов до тысячного (например, 80) потребуются права администратора системы.

У нас получился сервер локальной сети; а мы хотим, чтоб с ним могли работать web-браузеры. Цикл while обрабатывает запросы к серверу, пока в окне терминала не нажать клавиши Ctrl+C. Внутри этого цикла сервер принимает запрос клиента и посылает браузеру стандартный ответ из двух строк: сообщение, что запрос принят, и HTML-заголовок. Символы \r и \n означают «возврат каретки» и «перевод строки» соответственно.

Затем обрабатывается запрос, полученный от браузера. Обычно он выглядит примерно так: GET /filename.html HTTP/1.1. Нам нужно определить в нем имя запрошенного файла. Сохраним строку запроса в переменной request и извлечем оттуда имя файла методом gsub: он отделит от строки части GET и HTTP/1.1 при помощи регулярных выражений. Gsub напоминает командную утилиту sed — быстрый способ заместить или отделить части строковой переменной.

От полученного имени файла с помощью метода chomp отделяется последний символ перевода строки, после чего результат сохраняется в переменной filename.

Большинство web-серверов, если имя файла не указано, по умолчанию загружают index.html. Блок if так и делает: если строка с именем файла пуста, переменной filename присваивается index.html. Можно, конечно, использовать и другой файл.

После этого (внутри блока begin/end) мы открываем полученный файл на чтение и записываем в переменную content его содержимое, прочитанное с помощью функции read(). Содержимое файла отсылается браузеру, методом session.print. А вдруг такого файла не найдется? Тогда rescue отправит браузеру сообщение об ошибке.

Мысли напоследок

Вот сервер и готов. Удивительно просто, правда? Конечно, пока он обрабатывает только HTML-файлы — но были бы кости, мясо нарастет. Главное, что это пример применения Ruby в реальной задаче, и по нему видно, что код получается чудесно-простой и легко читаемый.

В Ruby еще много чего можно исследовать, и так как Ruby on Rails продолжает набирать популярность, вы об этом языке, несомненно, еще услышите. Ясный и разумный синтаксис Ruby лучше всех прочих поможет разобраться с объектно-ориентированным программированием тем, кто привык к С или Basic. Внизу слева находится врезка «Ссылки», там вы найдете и учебники, и прочую информацию. А напишете нечто крутое — сообщите нам на форум http://www.linuxforum.ru. Как знать, может, вашей будущей программы не хватает на нашем DVD…

Персональные инструменты
купить
подписаться
Яндекс.Метрика