10.3 使用KirbyBase
KirbyBase是所有程序员都应学会使用的小型库之一,当前它还不是Ruby的标准库,如果是的话,它用途可能更大。
KirbyBase是Jamey Cribbs开发的(显然是以他的狗命名的),虽然从很多方面说它都是一个功能齐备的数据库,但基于几个原因,将它放在这里介绍,而不是同MySQL和Oracle一起介绍。
首先,它不是独立的应用程序。它是一个纯粹的Ruby库,离开Ruby就毫无用处。其次,它完全不知道SQL,因此,如果由于种种原因需要依赖于SQL,则不适合使用它。第三,如果应用程序非常复杂,则KirbyBase的功能和速度是个问题。
尽管如此,还是有很多让人喜欢KirbyBase的原因。它是个单文件的纯Ruby库,不需要安装和配置。它是跨平台的,其数据文件也在不同平台之间交换。它的数据不会同时存储到内存中,从这种意义上说它是一个“真正的”数据库。
它使用起来很容易,且有到小型DBI的Ruby风格接口。一般而言,数据库对应于一个目录,而表格对应于一个文件。它生成的表是人类可读(及可编辑)的,也可以选择将其加密(旨在防止编辑)。它能够识别Ruby对象,可智能地存储和检索对象。
最后,依靠一个dRuby接口,它能够在分布模式下运行。访问远程机器和本地机器的KirbyBase数据一样简单。
要打开数据库,首先需要指出它是否是本地的,接下来的两个参数通常为nil,第四个参数指定数据库文件所在的目录(默认为当前目录)。
要创建表,可对数据库调用create_table,并将表名(以符号方式)传递给它(磁盘中的文件名将基于该名称),然后传递一系列表示字段名和类型的符号对。
require 'kirbybase'
db = KirbyBase.new(:local, nil, nil, "mydata")
books = db.create_table(:books, # name of table
:title, :String, # field, type, ...
:author, :String)
当前,KirbyBase能够识别的字段类型包括String、Integer、Float、Boolean、Time、Date、DateTime、Memo、Blob和YAML。在读者阅读本书时,可能还有其他类型。
要将数据插入表,可调用insert方法。可传递一个值列表、散列或任何与给定字段名对应的对象。
books.insert("The Case for Mars","Robert Zubrin")
books.insert(:title => "Democracy in America",
:author => "Alexis de Tocqueville")
Book = Struct.new(:title, :author)
book = Book.new("The Ruby Way","Hal Fulton")
books.insert(book)
在所有这些情况下,insert方法都将返回新记录的行id(可使用它或忽略它)。这是个“隐藏的”自动递增字段,它存在于每个表的每条记录中。
使用select方法选择记录,如果没有指定参数,它将选择表中每条记录的每个字段。通过将参数指定为符号,可只选择特定的字段。如果指定了代码块,它将用于决定要选择哪些记录(很像数组的find_all方法)。
list1 = people.select # All people, all fields
list2 = people.select(:name,:age) # All people, name/age only
list3 = people.select(:name) {|x| x.age >= 18 && x.age < 30 }
# Names of all people 18 to 30
在代码块中可执行任何操作,这意味着可使用Ruby正则表达式来查询(而不是像典型的面向SQL的数据库那样)。
KirbyBase结果集可根据多个键进行排序,可以是升序,也可以是降序。要按降序排列,可在键名前面加上负号(这是因为在Symbol中有一个一元负号方法)。
sorted = people.select.sort(:name,-:age)
# sort ascending by name, descending by age
结果集还有一个有趣的特性,可以提供对结果进行“横切”的数组,开始这可能有点不好理解。
假设有一个由人组成的结果集,其中每条记录都存储了姓名、年龄、身高和体重。当然,结果集可以像数组一样索引,但它还有与字段同名的方法,这些方法只存储由相应字段的值组成的数组,例如:
list = people.select(:name,:age,:height,:weight)
p list[0] # All info for person 0
p list[1].age # Age for person 1
p list[2].height # Height for person 2
ages = list.age # Array: Ages for all people
names = list.name # Array: Names for all people
KirbyBase有一些报告打印功能,只需对结果集调用to_report即可,如下所示:
rpt = books.select.sort(:title).to_report
puts rpt
# Output:
# recno | title | author
# ----------------------------------------------------
# 2 | Democracy in America | Alexis de Tocqueville
# 1 | The Case for Mars | Robert Zubrin
# 3 | The Ruby Way | Hal Fulton
可将表的encrypt存取器设置为true,从而使表不能像纯文本那样读取和编辑。注意,这是基于Vigenere加密的——不是毫无用处,但也不是非常安全,因此只将其用做防止编辑的手段,而不应将其用于隐藏敏感数据。通常应在创建表时使用代码块来设置它:
db.create_table(:mytable, f1, :String, f2, :Date) {|t| t.encrypt =true }
远程访问是一种有趣的功能,这里简要地介绍其工作原理。下面是一个示例服务器:
require 'kirbybase'
require 'drb'
host = 'localhost'
port = 44444
db = KirbyBase.new(:server) # Create an instance of the database.
DRb.start_service("druby://#{host}:#{port}", db)
DRb.thread.join
这是一个简单的dRuby(参见第20章)应用程序。在客户端连接到该数据库时,应指定:client而不是通常的:local。
db = KirbyBase.new(:client,'localhost',44444)
# All other code remains the same.
还可执行一些常规操作:更新或删除记录、删除表等。另外,还有更复杂的特性在这里没有介绍,如一对多链接、计算字段、自定义记录类,详情请参阅RubyForge的KirbyBase文档。







