Программирование на языке Ruby - Хэл Фултон
Шрифт:
Интервал:
Закладка:
Ясно, что это не настоящая база данных. Но более подходящего места, чем эта глава, для нее не нашлось.
Модуль CSV (csv.rb) разбирает или генерирует данные в формате CSV. О том, что представляет собой последний, нет общепринятого соглашения. Автор библиотеки определяет формат следующим образом:
• разделитель записей: CR + LF;
• разделитель полей: запятая (,);
• данные, содержащие символы CR, LF или запятую, заключаются в двойные кавычки;
• двойной кавычке внутри двойных кавычек должен предшествовать еще один символ двойной кавычки ("→"");
• пустое поле в кавычках обозначает пустую строку (данные,"",данные);
• пустое поле без кавычек означает NULL (данные,,данные).
В настоящем разделе мы рассмотрим лишь часть функциональных возможностей библиотеки. Этого достаточно для введения в предмет, а самую актуальную документацию, как всегда, можно найти в сети (начните с сайта ruby-doc.org).
Начнем с создания файла. Чтобы вывести данные, разделенные запятыми, мы просто открываем файл для записи; метод open передает объект-писатель в блок. Затем с помощью оператора добавления мы добавляем массивы данных (при записи они преобразуются в формат CSV). Первая строка является заголовком.
require 'csv'
CSV.open("data.csv","w") do |wr|
wr << ["name", "age", "salary"]
wr << ["mark", "29", "34500"]
wr << ["joe", "42", "32000"]
wr << ["fred", "22", "22000"]
wr << ["jake", "25", "24000"]
wr << ["don", "32", "52000"]
end
В результате исполнения этого кода мы получаем такой файл data.csv:
"name","age","salary"
"mark",29,34500
"joe",42,32000
"fred",22,22000
"jake",25,24000
"don",32,52000
Другая программа может прочитать этот файл:
require 'csv'
CSV.open('data.csv', ' r') do |row|
p row
end
# Выводится:
# ["name", "age", "salary"]
# ["mark", "29", "34500"]
# ["joe", "42", "32000"]
# ["fred", "22", "22000"]
# ["jake", "25", "24000"]
# ["don", "32", "52000"]
Этот фрагмент можно было бы записать и без блока, тогда метод open просто вернул бы объект-читатель. Затем можно было бы вызвать метод shift читателя (как если бы это был массив) для получения очередной строки. Но блочная форма мне представляется более естественной.
В библиотеке есть и более развитые средства, а также вспомогательные методы. Для получения дополнительной информации обратитесь к сайту ruby-doc.org или архиву приложений Ruby.
10.2.6. Маршалинг в формате YAML
Аббревиатура YAML означает «YAML Ain't Markup Language» (YAML — не язык разметки). Это не что иное, как гибкий, понятный человеку формат хранения данных. Он напоминает XML, но «красивее».
Затребовав директивой require библиотеку yaml, мы добавляем в каждый объект метод to_yaml. Поучительно будет посмотреть на результат вывода в этом формате нескольких простых и более сложных объектов.
require 'yaml'
str = "Hello, world"
num = 237
arr = %w[ Jan Feb Mar Apr ]
hsh = {"This" => "is", "just a"=>"hash."}
puts str.to_yaml
puts num.to_yaml
puts arr.to_yaml
puts hsh.to_yaml
# Выводится:
# --- "Hello, world"
# --- 237
# ---
# - Jan
# - Feb
# - Mar
# - Apr
# ---
# just a: hash.
# This: is
Обратным по отношению к to_yaml является метод YAML.load, который принимает в качестве параметра строку или поток.
Предположим, что имеется такой файл data.yaml:
---
- "Hello, world"
- 237
-
- Jan
- Feb
- Mar
- Apr
-
just a: hash.
This: is
Это те же четыре элемента данных, которые мы видели раньше, только они сгруппированы в единый массив. Если загрузить этот поток, то получим массив-
require 'yaml'
file = File.new("data.yaml")
array = YAML.load(file)
file.close
p array
# Выводится:
# ["Hello, world", 237, ["Jan", "Feb", "Mar", "Apr"],
# {"just a"=>"hash.", "This"=>"is"} ]
В общем и целом YAML — еще один способ выполнить маршалинг объектов. На верхнем уровне его можно использовать для самых разных целей. Например, человек может не только читать данные в этом формате, но и редактировать их, поэтому его естественно применять для записи конфигурационных файлов и т.п.
YAML позволяет и многое другое, о чем мы не можем здесь рассказать. Дополнительную информацию вы найдете на сайте ruby-doc.org или в справочном руководстве.
10.2.7. Преобладающие объекты и библиотека Madeleine
В некоторых кругах популярна идея преобладающих объектов (object prevalence). Смысл ее в том, что память дешева и продолжает дешеветь, а базы данных в большинстве своем невелики, поэтому о них можно вообще забыть и хранить все объекты в памяти.
Классической реализацией является пакет Prevayler, написанный на языке Java. Версия для Ruby называется Madeleine.
Madeleine годится не для всех приложений. У методики преобладающих объектов есть собственные правила и ограничения. Все объекты должны, во-первых, помещаться в памяти; во-вторых, быть сериализуемы.
Объекты должны быть детерминированы, то есть вести себя одним и тем же образом при получении одних и тех же данных. (Следовательно, применение системного таймера или случайных чисел оказывается под вопросом.)
Объекты должны быть по возможности изолированы от ввода/вывода (файлов и сети). Обычно весь ввод/вывод выполняется вне системы преобладающих объектов.
Наконец, любая команда, которая изменяет состояние системы преобладающих объектов, должна иметь вид объекта-команды (то есть для таких объектов тоже должна иметься возможность сериализации и сохранения).
Madeleine предлагает два основных метода доступа к системе объектов. Метод execute_query позволяет выполнить запрос или получить доступ для чтения. Метод execute_command инкапсулирует любую операцию, которая изменяет состояние объектов в системе.
Оба метода принимают в качестве параметра объект Command. По определению такой объект должен иметь метод execute.
Работа системы состоит в том, что во время исполнения приложения она периодически делает моментальные снимки всей системы объектов. Команды сериализуются наравне с другими объектами. В настоящее время не существует способа «откатить» набор транзакций.
Трудно привести содержательный пример использования этой библиотеки. Если вы знакомы с Java-версией, рекомендую изучить API для Ruby и освоить ее таким образом. Хороших руководств нет — может быть, вы напишете первое.
10.2.8. Библиотека DBM
DBM — платформенно-независимый механизм для хранения строк в файле, как в хэше. И ключ, и ассоциированные с ним данные должны быть строками. Интерфейс dbm включен в стандартный дистрибутив Ruby.
Для использования этого класса нужно создать объект DBM, указав для него имя файла, а дальше работать с ним, как с обычным хэшем. По завершении работы файл следует закрыть.
require 'dbm'
d = DBM.new("data")
d["123"] = "toodle-oo!"
puts d["123"] # "toodle-oo!"
d.close
puts d["123"] # RuntimeError: закрытый DBM-файл.
e = DBM.open("data")
e["123"] # "toodle-oo!"
w=e.to_hash # {"123"=>"toodle-oo!"}
e.close
e["123"] # RuntimeError: закрытый DBM-файл.
w["123"] # "toodle-oo!
Интерфейс к DBM реализован в виде одного класса, к которому подмешан модуль Enumerable. Два метода класса (синонимы) new и open являются синглетами, то есть в любой момент времени можно иметь только один объект DBM, связанный с данным файлом.
q=DBM.new("data.dbm") #
f=DBM.open("data.dbm") # Errno::EWOULDBLOCK:
# Try again - "data.dbm"
Всего есть 34 метода экземпляра, многие из которых являются синонимами или аналогичны методам хэша. Почти все операции с настоящим хэшем применимы и к объекту dbm.
Метод to_hash создает представление файла в виде хэша в памяти, а метод close закрывает связь с файлом. Остальные методы по большей части аналогичны методам хэшам, однако дополнительно есть методы rehash, sort, default, default=. Метод to_s возвращает строковое представление идентификатора объекта.
10.3. Библиотека KirbyBase
KirbyBase — небольшая библиотека, с которой должен освоиться каждый программист на Ruby. В настоящее время она не входит в стандартный дистрибутив, а если бы входила, то была бы еще полезнее.