Ruby操纵外部数据(四)

来源:互联网 发布:中邮网络培训学院入口 编辑:程序博客网 时间:2024/04/27 16:10
3、使用Marshal完成有限制的"深层拷贝"

Ruby没有深层拷贝"deep copy"操作符。方法dupclone不会总像你想像的那样工作。 对象可以包含嵌套的对象引用,它转向一个拷贝操作到Pick Up Sticks中。


我们提供了一个途径来处理一个有限制的深层拷贝(它有限制,是因为它还以Marshal为基础所以有同样内在限制)
def deep_copy(obj)

Marshal.load(Marshal.dump(obj))
end
a = deep_copy(b)


4Better Object Persistence with PStore
PStore库提供了文件为基础的Ruby对象的永续存储。PStore对象可以持有许多Ruby对象层次。每个层次通过一个键有个被识别的根。开始时从磁盘文件上读取层次结束时写回文件。这儿是个例子:
require "pstore"


# save
db = PStore.new("employee.dat")
db.transaction do

db["params"] = { "name" => "Fred", "age" => 32,

"salary" => 48000 }
end
# retrieve
require "pstore"
db = PStore.new("employee.dat")
emp = nil
db.transaction {
emp = db["params"] }
典型地,我们将Pstore对象传入到处理块内。但是,我们也可以直接使用调用者。
这个技术是事务导向的;块开始时,数据被从磁盘文件中取回并进行处理。然后,它被显式地写回到磁盘上。

在事务的中间,我们即可以中断也可放弃;但前者将保留我们做的修改,而后者将丢掉它们。参考Listing4.2这个更长的例子。

Listing 4.2 Using PStore
require "pstore"


store = PStore.new("objects")
store.transaction do |s|

a = s["my_array"]

h = s["my_hash"]

# Imaginary code omitted, manipulating

# a, h, etc.

# Assume a variable named "condition" having

# the value 1, 2, or 3...

case condition

when 1

puts "Oops... aborting."

s.abort
# Changes will be lost.

when 2

puts "Committing and jumping out."

s.commit
# Changes will be saved.

when 3

# Do nothing...

end

puts "We finished the transaction to the end."

# Changes will be saved.
end
在一个事务内部,你也可以使用方法roots来返回根的数组(root?测试成员)。同样,delete方法将有效地移除一个根。这儿个例子:
store.transaction do |s|

list = s.roots
# ["my_array","my_hash"]

if s.root?("my_tree")

puts "Found my_tree."

else

puts "Didn't find # my_tree."

end

s.delete("my_hash")

list2 = s.roots
# ["my_array"]
end


5Using the dbm Library
dbm库是一个简单依赖系统的,以字符为基础的哈希表的,以文件存储的机制。它存储键和关联的数据,两者必须是字符串。Rubydbm接口是被标准按装的。
要使用这个类,创建一个与文件名字关联的dbm对象,并且你希望以字符为基础的哈希表工作。当你完成时,你应该关闭文件。这儿是个例子:
require 'dbm'


d = DBM.new("data")
d["123"] = "toodle-oo!"
puts d["123"]
# "toodle-oo!"
d.close
puts d["123"]
# RuntimeError: closed DBM file
e = DBM.open("data")
e["123"]
# "toodle-oo!"
w=e.to_hash
# { "123"=>"toodle-oo!"}
e.close
e["123"]
# RuntimeError: closed DBM file
w["123"]
# "toodle-oo!
这儿,dbm被做为混插了Enumerable的单独类实现的。两个类方法,newopen,是单态的,它的意思是任何时候,你的每个数据文件只可以有一个dbm对象:
q=DBM.new("data.dbm")
#
f=DBM.open("data.dbm")
# Errno::EWOULDBLOCK:

#
Try again - "data.dbm"
它有34个实例方法,很多都是别名或与Hash方法类似。基本上,如果你能熟练地使用哈希表,你可以对一个dbm对象应用同样的操作。
方法to_hash将在内存中为哈希表文件制做一个拷贝,close方法将永久地关闭与哈希表文件的连接。其余的方法和Hash方法类似,但没有rehsh,sort,default,efault=方法。to_s方法只返回用字符串表示的对象ID






三、连接外部数据库

Ruby可以连接由许多不同的人开发的,各种各样的数据库。这些范围从整体系统譬如Oracle到对更小的MySQL

这些包的功能层会持续地被修改。请务必提到网上参考最新的信息。Ruby的应用文档(RAA)总是最好的起点。



1、连接到MySQL
RubyMySQL接口是最稳定的和有完整功能的数据库接口。它是扩展的,必须在RubyMySQL被安装并运行后才可安装。如果你升级Ruby,你将需要重新安装它。它的安装很简单,使用Rubymake过程。

一旦你安装了它,可以有三个步骤来使用它。首先,在你的脚本中加载它;然后连接到数据库。最后,用你的表工作。连接请求通常使用的参数主机名,用户名,口令,数据库,等等,像这儿显示的:


require 'mysql'


m = Mysql.new("localhost","ruby","secret","maillist")
r = m.query("SELECT * FROM people ORDER BY name")
r.each_hash do |f|

print "#{ f['name']}
- #{ f['email']} "
end
这儿是部分输出:
John Doe - jdoe@rubynewbie.com
Fred Smith - smithf@rubyexpert.com
Don Jackson - don@perl2.com
Jenny Williams - jwill27@miss-code.com
类方法Mysql.newMysqlRes.each_hash是非常有用的,还有随同的实例方法query
这个模块由四个类组成: Mysql, MysqlRes, MysqlField,MysqlError,分别在README文件中描述。我们在这儿总结了一些有用的方法,但你可以实际文档中找到更多信息。
类方法Mysql.new接受几个字符串参数,所有都被定义为nil,并且它返回一个connection对象。参数是host,user,passwd,db,port,sock,flag new的别名real_connectconnect
方法create_db, select_db, drop_db都接受数据库名称做为参数;它们用法显示在下面(方法close将关闭与服务端的连接)
m=Mysql.new("localhost","ruby","secret")
m.create_db("rtest")
# Create a new database
m.select_db("rtest2")
# Select a different database
m.drop_db("rtest")
# Delete a database
m.close
# Close the connection
The method 方法list_dbs将返回有效的数据库名称列表在一个数组内:
dbs = m2.list_dbs
# ["people","places","things"]
query接受一个字符串参数并缺省地返回一个MysqlRes对象。这依赖于query_with_result是如何被设置的,它可以返回一个Mysql对象。
如果事件出现错误,错误号码可由errno取回;换句话说,error将返回实际的错误信息。这儿是个例子:
begin

r=m.query("create table rtable

(

id int not null auto_increment,

name varchar(35) not null,

desc varchar(128) not null,

unique id(id)

)")
# exception happens...
rescue

puts m.error

# Prints: You have an error in your SQL syntax

# near 'desc varchar(128) not null ,

#
unique id(id)

# )' at line 5"

puts m.errno

# Prints 1064

# ('desc' is reserved for descending order)
end
MysqlRes内很少被使用的方法被总结列在下面:
1.
fetch_fields 从下一行中返回MysqlField对象的数组。
2.
fetch_row 从下一行中返回字段值的数组。
3.
fetch_hash(with_table=false) 返回包含下一行的名称和值的哈希表。
4.
num_rows 返回结果集中行数。
5.
each 按次序返回字段值数组的迭代器。
6.
each_hash(with_table=false) 按次序返回一个{fieldname => fieldvalue}样哈希表的迭代器。(使用x['field name']来获取字段值。)
这儿是MysqlField的一些实例方法:
1.
name 返回指定字段的名字。
2.
table 返回指定字段所属表的名字。
3.
length 返回字段定义长度。
4.
max_length 从结果集中返回长度最长的字段。
5.
hash Returns a hash with a name and values for name, table, def, type, length, max_length, flags, and decimals
这儿的材料总是代替不了在线文档的。更多信息可参考MySQL Web 站点 (www.mysql.com)Ruby应用文档。