对于开发信息管理系统的程序员而言,在从一个语言过渡到另一个语言时一般情况下都应该先了解新语言的物性,同时就最起码能使用新语言完成以下功能:
1、了解语言的特点。比如:.net中的Attribute 和 java中的 annotation 等等,而语言物性在Ruby这样的动态语言中更是隐藏了更多的细节需要慢慢体会。
2、能读取XML文件信息的信息。对于Ruby来说,也要了解YAML文件的读取。
3、实现数据库的连接、增删改等操作和一些事务的操作。
4、最少要了解一个这个新语言的ORM框架,其中.net里有NHibernate,java中的Hibernate,Ruby中的ActiveRecord都是不错的选择。
5、最少要了解一个日志框架,如.net中的Log4net,java中的Log4j等。
6、一些最基本的加密算法。如MD5,SHA等
我个人认为对一个刚接触一个新语言的程序员或是刚毕业或在读的学生来说。这几点是最基本的了。这些技术再结合一些好的设计方法和一些更深入的知识就能设计出比较实用的软件出来了。下面就以我学习Ruby语言的过程,写出上面这些东西的Ruby的实现
一、Ruby 我刚接触没多久,只是抱着玩一下的态度去学习。但我发现他语言上确实很灵活面向对角之余又没有什么限制。在学习过程中比较关注的就是
1、类的多重继承:Ruby中不支持多重继承,也没有.net中的interface的概念。要一个类继承多个类的方法用一个类包含多个模块。
module Mod1
def method1
puts
"
do Module1's method1
"
end
def method2
puts
"
do Module1's method2
"
end
end
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
module Mod2
def method2
puts
"
do Module2's method2
"
end
def method3
puts
"
do Module2's method3
"
end
end
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
class
MyClass1
include Mod1
include Mod2
end
c
=
MyClass1.
new
;
c.method1 #
=>>
"
do Module1's method1
"
c.method2 #
=>>
"
do Module2's method2
"
注意这里因为两个模块都有method2方法,所以以最后包含的为最终的实现
c.method3 #
=>>
"
do Module2's method3
"
更多的细节可查看Programming Ruby中的Modules一节。
2、在Ruby中还要了解变量命名的方式。以“$”开头的变量为全局变量,以“@”开头的变量为实例变量,以“@@”开头的变量为静态变量。以“大写字母开头的”为常量和类名。更多的细节可查看Programming Ruby中的Ruby.new一节中的"Some Basic Ruby"。
3、还有异常的捕获、代码块、正则表达式等。实在太多了,这里暂不讲述这些内容。
二、关于XML文件的操作我个人认为最少要实现下面两点.
下面的例使用到的XML文件内容如下:
<?
xml version="1.0" encoding="gb2312"
?>
<
data
table_name
="table1"
>
<
record
attribute1
="记录一属性一"
attribute2
="记录一属性二"
>
<
field
name
="field1"
>
字段一的内容
</
field
>
<
field
name
="field2"
>
字段一的内容
</
field
>
</
record
>
<
record
attribute1
="记录二属性一"
attribute2
="记录二属性二"
>
<
field
name
="field1"
>
字段二的内容
</
field
>
<
field
name
="field2"
>
字段二的内容
</
field
>
</
record
>
</
data
>
1、自由地浏览整XML文件的结构,下面给出Ruby的具体实现:
require
"
rexml/document
"
open
(
'
1.xml
'
)
do
|
f
|
xml_data
=
f
.
read
#
读取XML内容
doc
=
REXML
::
Document
.
new(xml_data)
#
生成Document对象
puts
"
表名=#{doc.root.attributes[
"
table_name
"
]}
"
#
读取根节点的属性
puts
"
<<============>>
"
doc
.
root
.
each_element
do
|
record
|
puts
"
节点属性一:#{record.attributes[
"
attribute1
"
]}
"
puts
"
节点名称:#{record.name}
"
puts
"
父节点名称:#{record.parent.name}
"
puts
"
子节点的数量:#{record.elements.size}
"
#
==>>这里包含了两个field节点。
puts
"
是否有子节点:#{record.has_elements? }
"
puts
"
field1节点的name属性:#{record.elements[1]}
"
#
这里要注意,很奇怪,与数组不同索引是从1开始。
puts
"
field2节点的name属性:#{record.elements[2]}
"
puts
"
field2节点的name属性:#{record.elements[2].text}
"
end
end
2、能使用XPath语句对XML文件进行节点的查询。
require
"
rexml/document
"
open
(
'
1.xml
'
)
do
|
f
|
xml_data
=
f
.
read
#
读取XML内容
doc
=
REXML
::
Document
.
new(xml_data)
#
生成Document对象
e
=
REXML
::
XPath
.
first(doc
,
'
//field
'
);
puts e
#
==>> 输出:<field name='field1'>字段一的内容</field>
#上面这个语句是查找第一个field1节点.
#我们也可以使用match函数来返回一个符合条件的节点的数据组
REXML
::
XPath
.
match(doc
,
'
//[@name="field1"]
'
)
.
each
do
|
node
|
puts node
#
另外每一个Element对象都有一个xpath方法返回该对象的XPATH路径
puts node
.
xpath
#
这样我们就可以在后顺的代码中用类似下面这条语句来得到这些节点了。
puts REXML
::
XPath
.
first(doc
,
node
.
xpath)
end
end
3、YAML文件的操作
require
"
yaml
"
class MyClass
attr_accessor
:
aa
end
c1
=
MyClass
.
new;
c1
.
aa
=
"
Hello Class
"
puts c1
.
to_yaml
#
输同对象的yaml内容
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
#把一个对象序列化
open
(
'
c1.txt
'
,
'
w
'
) {
|
f
|
YAML
.
dump
(c1
,
f) }
#
反序列化,从文件中得到原来的对象
newc1
=
open
(
"
c1.txt
"
) {
|
f
|
YAML
.
load(f) }
puts c1
.
aa
三、数据库的操作:
1、Oracle数据库
先去
http://ruby-oci8.rubyforge.org/下载oci8库。以下是使用这个库的简单例子
require
'
oci8
'
conn
=
OCI8
.
new(
"
thxj
"
,
"
thxj
"
,
"
thga
"
)
#
一般的查询,反回的是数组,所以不能使用r["字段名"]的方式来访问数据
conn
.
exec
(
"
select * from books
"
)
do
|
r
|
#
这里不要多此一举加上conn.exec("select * from books").each
puts(
"
#{r[0]},#{r[1]},#{r[2]}
"
)
end
puts
"
===========
"
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
#
使用cursor 来查询
cursor
=
conn
.
parse(
"
SELECT * from books where book_name like :bn1 or book_name=:bn2
"
)
#
准备SQL语句
cursor
.
bind_param(
1
,
'
%
'
)
#
邦定查询语句用到的第一个参数
cursor
.
bind_param(
"
:bn2
"
,
'
%
'
)
#
邦定查询语句用到的第一个参数
cursor
.
exec
cursor
.
fetch
do
|
r
|
puts(
"
#{r[1]}
"
)
puts (
"
#{r[cursor.get_col_names.index(
"
BOOK_NAME
"
)]
"
)
#
如果要用字段名来显示信息,暂时可以用这个文法
end
puts
"
=====返回所有的列名======
"
puts cursor
.
get_col_names
cursor
.
close
conn
.
logoff
注意如果是调用conn.exec进行增删改操作,默认情况下事务是不会自动提交的,可以使用conn.commit 和conn.rollback进行事务的提交和回滚。
2、MySql数据库
暂无
四、使用ActiveRecord进行数据库操作。
require
'
dbi
'
require
'
active_record
'
ActiveRecord
::
Base
.
establish_connection(
:
adapter
=>
"
oracle
"
,
:
username
=>
"
thxj
"
,
:
password
=>
"
thxj
"
,
:
database
=>
"
thga
"
)
class Book
<
ActiveRecord
::
Base
set_primary_key
"
book_id
"
end
book
=
Book
.
new
book
.
id
=
"
aaaa1
"
#
注意这里,需然上面定义了book_id为主键,但设置主键值时不能使用book_id=值。
book
.
book_name
=
"
书名是XXX
"
book
.
save
下面再试试给上面的代码加上事务处理功能:
require
'
dbi
'
require
'
active_record
'
require
'
active_record/transactions
'
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
ActiveRecord
::
Base
.
establish_connection(
:
adapter
=>
"
oracle
"
,
:
username
=>
"
thxj
"
,
:
password
=>
"
thxj
"
,
:
database
=>
"
thga
"
)
class Book
<
ActiveRecord
::
Base
set_primary_key
"
book_id
"
end
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
ActiveRecord
::
Base
.
transaction
do
#
第一层事务
book
=
Book
.
new
book
.
id
=
"
aaaa9
"
book
.
book_name
=
"
书名是XXX39
"
book
.
save
book2
=
Book
.
new
book2
.
id
=
"
aaaa7
"
book2
.
book_name
=
"
内层事务
"
book2
.
save
book3
=
Book
.
new
book3
.
id
=
"
aaaa8
"
book3
.
book_name
=
"
书名是XXX3
"
book3
.
save
end
有时候想实现多重事务,可能会写出下面这种错误的代码。
require
'
dbi
'
require
'
active_record
'
require
'
active_record/transactions
'
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
ActiveRecord
::
Base
.
establish_connection(
:
adapter
=>
"
oracle
"
,
:
username
=>
"
thxj
"
,
:
password
=>
"
thxj
"
,
:
database
=>
"
thga
"
)
class Book
<
ActiveRecord
::
Base
set_primary_key
"
book_id
"
end
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
ActiveRecord
::
Base
.
transaction
do
#
第一层事务
book
=
Book
.
new
book
.
id
=
"
aaaa7
"
book
.
book_name
=
"
外层事务
"
book
.
save
ActiveRecord
::
Base
.
transaction
do
#
第二层事务
book2
=
Book
.
new
book2
.
id
=
"
aaaa7
"
book2
.
book_name
=
"
内层事务
"
book2
.
save
book3
=
Book
.
new
book3
.
id
=
"
aaaa8
"
book3
.
book_name
=
"
书名是XXX3
"
book3
.
save
end
raise
end
以上代码有的人可能会以为异常在外层代码块中抛出,所以内层的事务应该是可以提交的。
注意,上面的写法更本没有实现两层事务。任何一个代码块中出现异常所有对象都无法保存。
五、日志功能
以下这段描述是在网上拷贝下来的,原出处在哪就不清楚了:
Rails应用中的所有代码都可以访问一个Logger对象。
Logger是一个简单的日志框架,随最近版本的Ruby一道发行(在命令行中输入ri Logger,就可以看到更多关于Logger的信息。也可以查看Programming Ruby[TH01]中的标准库文档)。对我们而言,只需要知道我们可以生成warning、info、error和fatal这几个级别的日志信息就够了。随后,我们可以根据需要决定将哪些级别的日志信息写入日志文件。
logger.warn("I don't think that's a good idea")
logger.info("Dave's trying to do something bad")
logger.error("Now he's gone and broken it")
logger.fatal("I give up")
在Rails应用中,这些消息会被写入log目录下的某个文件中——具体是哪个文件,取决于应用程序运行在什么环境下:开发环境下,日志会被写入log/development.log文件;测试环境下则会写入test.log文件;生产环境下的日志文件则是production.log。
六、加密算法:
MD5:
require
'
digest/md5
'
puts Digest
::
MD5
.
hexdigest(
"
Hello
"
)
SHA1:
require
'
digest/sha1
'
puts Digest
::
SHA1
.
hexdigest(
''
)