Глава 19. Ruby и Web-приложения
Как ловко мы сплетаем сеть…
Ruby — универсальный язык, его ни в коей мере нельзя считать исключительно «языком Web». Но, несмотря на это, одно из наиболее типичных его применений — создание приложений (да и вообще инструментов в широком смысле) для Web.
Существует множество способов разрабатывать приложения для Web на Ruby — от сравнительно небольших и низкоуровневых библиотек до каркасов, которые диктуют стиль кодирования и мышления.
Начнем с низкого уровня и рассмотрим библиотеку cgi.rb
, входящую в стандартный дистрибутив Ruby.
19.1. Программирование CGI на Ruby
Всякий, кто знаком с программированием для Web, хотя бы раз встречал аббревиатуру
Программирование с применением CGI, да и вообще для протокола HTTP, должно учитывать отсутствие «состояния» в механизме запрос-ответ. В общем случае клиент (обычно браузер) для каждого запроса создает новое соединение и посылает по нему единственную команду HTTP. Чаще всего используются команды GET
и POST
(к смыслу этих слов мы вернемся чуть позже). Сервер посылает ответ, после чего закрывает свой конец соединения.
В следующем примере, который лишь немногим сложнее пресловутой программы «Hello, world», показано, как выполняются ввод и вывод по спецификации CGI.
def parse_query_string
inputs = Hash.new
raw = ENV['QUERY_STRING']
raw.split('&').each do |pair|
name,value = pair.split('=')
inputs[name] = value
end
inputs
end
inputs = parse_query_string
print 'Content-type: text/html
'
print '<HTML><BODY>'
print '<B><I>Hello</I>, #{inputs['name*]}!</B>'
print '</BODY></HTML>'
Так, обращение с помощью этой программы к URL http://mywebserver/cgi-bin/hello.cgi?name=Dali приведет к отправке браузеру сообщения «Hello, Dali!».
Мы уже упомянули, что есть два основных способа обратиться к UTL: методы GET
и POST
, определенные в протоколе HTTP. Для краткости мы предложим простые объяснения, а не строгие определения. Метод GET
обычно вызывается, когда вы щелкаете по ссылке или указываете URL непосредственно (как в предыдущем примере). Параметры передаются в строке запроса, которую CGI-программы видят как значение переменной окружения QUERY_STRING
. Метод POST
обычно применяется для отправки HTML-форм. Параметры включаются в тело сообщения и в URL не видны. CGI-программе они доставляются через стандартный поток ввода.
Предыдущий пример был предельно простым, но в менее тривиальных случаях программа быстро становится запутанной. Приходится иметь дело с различными методами HTTP, загрузкой файлов, куками, сеансами «с состоянием» и другими сложностями, которые лучше оставить библиотеке общего назначения, поддерживающей спецификацию CGI. К счастью, в Ruby имеется обширный набор классов для автоматизации рутинной работы.
Есть еще немало библиотек и инструментов, стремящихся упростить разработку в рамках CGI. К числу лучших следует отнести библиотеку ruby-web (прежнее название Narf) Патрика Мэя (Patrick May). Если вам нужно работать на низком уровне, но стандартная библиотека почему-либо не устраивает, попробуйте эту (http://ruby-web.org).
Если необходимо решение на основе шаблонов, возможно, подойдет библиотека Amrita (http://amrita.sourceforge.jp). Обратите также внимание на Cerise — сервер приложений на базе Amrita (http://cerise.rubyforge.org).
Наверное, существуют и другие библиотеки. Если вы не нашли того, что искали, среди упомянутых здесь продуктов, обратитесь к поисковой машине или задайте вопрос в конференции.
19.1.1. Введение в библиотеку cgi.rb
Библиотека cgi.rb
включена в стандартный дистрибутив Ruby. Ее функциональность в основном реализована в центральном классе CGI
. Первое, что нужно сделать при работе с данной библиотекой, — создать экземпляр этого класса.
require 'cgi'
cgi = CGI.new('html4')
Инициализатор класса CGI принимает единственный параметр — уровень спецификации языка HTML, который должен поддерживаться методами генерации разметки, входящими в пакет CGI. Эти методы избавляют программиста от ручного написания длинных фрагментов экранированной разметки в достаточно простом коде на Ruby:
cgi.out do
cgi.html do
cgi.body do
cgi.h1 { 'Hello Again, '} +
cgi.b { cgi['name']}
end
end