Программирование на языке Ruby - Хэл Фултон
Шрифт:
Интервал:
Закладка:
http://127.0.0.1:2000/main.html/6b38f6fb-4f087af7-ab6JaqUM9KyWE.a.1.7
Такие URL позволяют IOWA отслеживать состояние сеанса. Если несколько раз щелкнуть по ссылке, то вы увидите, что URL изменяется. Если вручную восстановить предыдущее значение, вы получите состояние сеанса, соответствующее URL.
В данном случае состояние — это значение переменной экземпляра @count. Вот как выглядит файл Main.iwa:
class Main < Iowa::Component
attr_accessor :count
def awake
@count = 0
end
def setup
@count += 1
end
def now
Time.now.asctime
end
end
19.6.2. Шаблоны в IOWA
Большинство Web-приложений только выигрывает от разделения кода и шаблонов представления, но IOWA, как и Nitro, позволяет вообще обходиться без компонентов и помещать весь код на Ruby в представление. Ниже приведен файл PureView.html, содержащий как код класса, так и HTML-разметку:
<%
class PureView < Iowa::Component
def right_now
Time.now
end
end
%>
<html>
<head><titlе>Автономный вид</title></head>
<body>
<р>Текущее время @right_now.</p>
</body>
</html>
Но, в отличие от Nitro, это работает только в том случае, когда для представления нет соответствующего компонента. Если имеются оба файла, то IOWA не станет анализировать код, встроенный в HTML-файл.
Шаблон может содержать циклы и условные предложения. Добавим такой метод в файл Main.iwa:
def after_dinner?
Time.now.hour >19
end
Тогда можно реализовать в Main.html условную прорисовку с помощью элемента if:
<if oid='after_dinner?'>
<р>Обед закончен. Что на десерт?</р>
</if>
Хороший вопрос! Что на десерт? Пусть IOWA и ответит. Мы поручим Main.iwa подготовить меню десертов в виде массива:
def desserts
%w{
Пирожные
Печенье
Фрукты
Мороженое
}
end
А в файле Main.html выведем его. Изменим содержимое элемента if, включив список десертов:
<р>Обед закончен. Вот что мы можем предложить на десерт:</р>
<ul oid="dessert_list">
<li>@dessert_item</li>
</ul>
</if>
<p>
Мы еще должны сообщить IOWA, что выводить на каждой итерации, поэтому в конце файла Main.iwa после определения класса добавим раздел определения связей:
<?
dessert_list {
item = dessert_item
list = desserts
} ?>
Тем самым производится связывание списка dessert_list в шаблоне. На каждой итерации элемент списка заполняется из переменной dessert_item, а данные в целом поступают от метода компонента desserts.
19.6.3. Передача управления компоненту
Бывает полезно разнести логику приложения по нескольким классам компонентов. Мы видели, как можно отобразить URL на компоненты. Имеется также способ передать управление, не изменяя базового пути в URL.
Добавим в файл Main.iwa метод для обработки щелчка по ссылке в меню десертов:
def dessert_choice
new_page = page_named( 'DessertChoice')
new_page.choice = @dessert_item
yield new_page
end
Также изменим цикл формирования списка десертов в Main.html:
<ul oid="dessert_list">
<li><a oid= 'dessert_choice'>@dessert_item</a></li>
</ul>
Тут происходит немало интересного; атрибут oid элемента ul управляет формированием цикла, а такой же атрибут элемента а создает специальную ссылку на только что добавленный метод dessert_choice. Для довершения дела странице передается еще и текст ссылки (хотя и несколько загадочным способом). Метод dessert_choice сам по себе короткий, в нем вызывается метод page_named для создания экземпляра еще одного класса компонента DessertChoice. Для передачи выбранного десерта вызывается метод choice=. Затем yield передает управление новому компоненту.
Новый компонент также определяется с помощью пары файлов с расширениями .iwa и .html. Вот код класса:
class DessertChoice < Iowa::Component
attr_accessor :choice
def details
"Детали #{@choice} нужно было брать из базы данных."
end
end
А в файле DessertChoice.html хранится разметка:
<html>
<head><title>Выбранный вами десерт</title></head>
<body>
<h1>Десерт!</h1>
<p>@details</p>
</body>
</html>
Об IOWA можно было бы рассказывать еще долго. Для получения дополнительной информации зайдите на домашнюю страницу IOWA (http://enigo.com/proiects/iowa/) или на страницу проекта IOWA на сайте RubyForge (http://rubyforge.org/projects/iowa).
19.7. Ruby и Web-сервер
На сегодняшний день одним из самых популярных Web-серверов является Apache. Если вы работаете с ним, то должны знать о модуле mod_ruby, который описывается в разделе 19.7.1.
Еще одна полезная возможность на стороне сервера — встроенный Ruby; эту технологию поддерживают инструменты erb (рассматриваемый ниже) и eruby. Они позволяют встраивать код на Ruby в текст страницы (обычно HTML или XML), вследствие чего данные можно вставлять динамически. Данный подход описывается в разделе 19.7.2.
Некоторые разработчики реализовали Web-серверы, написанные целиком на Ruby. Естественно возникает вопрос: зачем писать новый Web-сервер, когда их уже и так существует немало — взять хотя бы тот же Apache?
Во-первых, есть ситуации, когда желательно иметь специализированный Web-сервер, например ради нестандартного способа обработки страниц, когда можно пожертвовать функциональностью ради скорости, или для автоматической трансляции специальной разметки в HTML.
Во-вторых, может возникнуть желание поэкспериментировать с поведением сервера и его взаимодействием с внешним кодом, например с CGI-программами. Возможно, у вас есть какие-то идеи относительно создания сервера приложений и среды разработки на стороне сервера. А все мы знаем, что Ruby прекрасно подходит для экспериментов.
В-третьих, иногда бывает разумно встроить Web-сервер в другое приложение. К этой возможности прибегают разработчики, желающие предоставить функциональность программной системы внешнему миру; протокол HTTP прост и четко определен, а Web-браузеры в качестве клиентов есть повсюду. Этот прием можно даже использовать для удаленной отладки, если система часто обновляет свое внутреннее состояние и делает его доступным встроенному серверу.
И последняя причина заключается в том, что небольшой автономный Web-сервер может упростить развертывание и конфигурирование. Например, перезапустить сервер для приложения Rails гораздо проще, если в этом качестве выступает WEBrick, а не Apache.
Имея все это в виду, посмотрим, что Ruby предлагает в плане Web-серверов. В прошлом было по крайней мере четыре таких сервера, но летом 2006 года остались два наиболее значимых: WEBrick и Mongrel. Они описаны в разделах 19.7.3 и 19.7.4 соответственно.
19.7.1. Модуль mod_ruby
Обычно, если CGI-сценарий пишется на интерпретируемом языке, то при каждом запросе загружается новый экземпляр интерпретатора. Это дорого обходится с точки зрения потребления ресурсов сервера и времени выполнения.
Сервер Apache решает эту проблему путем создания загружаемых модулей, которые, по существу, становятся частью сервера. Они загружаются динамически по мере необходимости и становятся общими для всех зависящих от них сценариев. Одним из таких модулей является mod_ruby (имеется в архиве RAA).
Модуль mod_ruby реализует несколько директив Apache, в частности:
• RubyRequire определяет одну или несколько потребных библиотек;
• RubyHandler определяет обработчик для объекта Ruby;
• RubyPassEnv определяет имена переменных окружения, передаваемых сценариям;
• RubySetEnv устанавливает переменные окружения;
• RubyTimeOut задает величину тайм-аута для Ruby-сценариев;
• RubySafeLevel задает уровень безопасности $SAFE;
• RubyKanjiCode устанавливает кодировку символов для Ruby.
В состав пакета входят также классы и модули Ruby для взаимодействия с Apache. Модуль Apache (здесь слово «модуль» употребляется в смысле, принятом в Ruby) включает несколько функций, например server_version и unescape_url; там же определены классы Request и Table.
Apache::Request — это обертка для типа данных request_rec, определяющая такие методы, как request_method, content_type, readlines и т.д. Класс Apache::Table — обертка для типа данных table; он определяет, среди прочих, методы get, add и each.