Ruby 库功能全解析
1. dRuby 分布式对象
dRuby 允许 Ruby 对象通过网络连接进行分布式处理。虽然以客户端和服务器的形式表达,但一旦初始连接建立,协议实际上是对称的,双方都可以调用对方对象的方法。通常,远程调用传递和返回的对象是按值传递的;若对象包含
DRbUndumped
模块,则按引用传递,这在实现回调时很有用。
1.1 服务器程序示例
require 'drb'
require 'drb/observer'
class Counter
include DRb::DRbObservable
def run
5.times do |count|
changed
notify_observers(count)
end
end
end
counter = Counter.new
DRb.start_service('druby://localhost:9001', counter)
DRb.thread.join
1.2 客户端程序示例
require 'drb'
class Listener
include DRbUndumped
def update(value)
puts value
end
end
DRb.start_service
counter = DRbObject.new(nil, "druby://localhost:9001")
listener = Listener.new
counter.add_observer(listener)
counter.run
2. English 库:全局符号的英文名称
在 Ruby 脚本中包含
English
库文件,就可以使用更清晰的名称来引用全局变量,如下表所示:
| 原符号 | 英文名称 |
| — | — |
|
$*
|
$ARGV
|
|
$"
|
$LOADED_FEATURES
|
|
$?
|
$CHILD_STATUS
|
|
$&
|
$MATCH
|
|
$<
|
$DEFAULT_INPUT
|
|
$.
|
$NR
|
|
$>
|
$DEFAULT_OUTPUT
|
|
$,
|
$OFS
|
|
$!
|
$ERROR_INFO
|
|
$\
|
$ORS
|
|
$@
|
$ERROR_POSITION
|
|
$,
|
$OUTPUT_FIELD_SEPARATOR
|
|
$;
|
$FIELD_SEPARATOR
|
|
$\
|
$OUTPUT_RECORD_SEPARATOR
|
|
$;
|
$FS
|
|
$$
|
$PID
|
|
$=
|
$IGNORECASE
|
|
$'
|
$POSTMATCH
|
|
$.
|
$INPUT_LINE_NUMBER
|
|
$`` |
$PREMATCH
|
|
$/
|
$INPUT_RECORD_SEPARATOR
|
|
$$
|
$PROCESS_ID
|
|
$~
|
$LAST_MATCH_INFO
|
|
$0
|
$PROGRAM_NAME
|
|
$+
|
$LAST_PAREN_MATCH
|
|
$/
|
$RS
|
|
$_
|
$LAST_READ_LINE` |
2.1 示例代码
require 'English'
$OUTPUT_FIELD_SEPARATOR = ' -- '
"waterbuffalo" =~ /buff/
print $LOADED_FEATURES, $POSTMATCH, $PID, "\n"
print $", $', $$, "\n"
运行结果:
English.rb -- alo -- 28035 --
English.rb -- alo -- 28035 --
3. Enumerator 库:定义外部迭代器
Ruby 约定可枚举对象应定义一个
each
方法,每次返回一个元素。
Enumerator
模块基于现有对象创建新的可迭代对象,将新对象的
each
方法映射到原对象的任意方法,从而可以在任意方法上使用标准的 Ruby 枚举技术。
3.1 返回哈希所有键的外部迭代器示例
require 'enumerator'
hash = { "cow" => "bovine", "cat" => "feline", "dog" => "canine" }
key_iter = Enumerable::Enumerator.new(hash, :each_key)
puts "Max key is #{key_iter.max}"
for key in key_iter
puts "Key is #{key}"
end
运行结果:
Max key is dog
Key is cat
Key is cow
Key is dog
3.2
to_enum
和
enum_for
方法示例
require 'enumerator'
hash = { "cow" => "bovine", "cat" => "feline", "dog" => "canine" }
key_iter = hash.enum_for(:each_key)
puts key_iter.min # 输出: cat
puts key_iter.max # 输出: dog
3.3
each_slice
和
each_cons
方法示例
require 'enumerator'
(1..7).each_slice(3) {|slice| print slice.inspect, " " }
puts
(1..7).each_cons(3) {|cons| print cons.inspect, " " }
运行结果:
[1, 2, 3] [4, 5, 6] [7]
[1, 2, 3] [2, 3, 4] [3, 4, 5] [4, 5, 6] [5, 6, 7]
4. ERB 库:轻量级 HTML 模板
ERB 是一个轻量级的模板系统,允许将 Ruby 代码和纯文本混合,常用于创建 HTML 文档,也适用于其他纯文本场景。
4.1 ERB 基本示例
require 'erb'
input = %{\
<% high.downto(low) do |n|
# set high, low externally %>
<%= n %> green bottles, hanging on the wall
<%= n %> green bottles, hanging on the wall
And if one green bottle should accidentally fall
There'd be <%= n-1 %> green bottles, hanging on the wall
<% end %>
}
high,low = 10, 8
erb = ERB.new(input)
erb.run
运行结果:
10 green bottles, hanging on the wall
10 green bottles, hanging on the wall
And if one green bottle should accidentally fall
There'd be 9 green bottles, hanging on the wall
...
4.2 ERB 指令说明
| 序列 | 动作 |
|---|---|
<% ruby code %>
| 在生成的程序中插入给定的 Ruby 代码,若有输出则包含在结果中 |
<%= ruby expression %>
| 计算表达式并将其值插入生成程序的输出中 |
<%# ... %>
| 注释,忽略 |
<%%
和
%%>
|
分别在输出中替换为
<%
和
%>
|
4.3 ERB 辅助模块
ERB::Util
ERB::Util
模块包含两个方法:
html_escape
(别名
h
)和
url_encode
(别名
u
),分别等同于 CGI 方法
escapeHTML
和
escape
。
include ERB::Util
str1 = %{\
h(a) = <%= h(a) %>
u(a) = <%= u(a) %>
}
a = "< a & b >"
ERB.new(str1).run
运行结果:
h(a) = < a & b >
u(a) = %3C%20a%20%26%20b%20%3E
5. Etc 库:访问用户和组信息
Etc
模块提供了许多方法,用于查询 Unix 系统上的
passwd
和
group
信息。
5.1 获取当前登录用户信息
require 'etc'
name = Etc.getlogin
info = Etc.getpwnam(name)
puts info.name # 输出用户名
puts info.uid # 输出用户 ID
puts info.dir # 输出用户目录
puts info.shell # 输出用户 shell
group = Etc.getgrgid(info.gid)
puts group.name # 输出用户组名
5.2 获取系统所有用户和组的名称
require 'etc'
users = []
Etc.passwd {|passwd| users << passwd.name }
puts users.join(", ")
groups = []
Etc.group {|group| groups << group.name }
puts groups.join(", ")
6. expect 库:IO 对象的 expect 方法
expect
库为所有 IO 对象添加了
expect
方法,允许编写等待特定字符串或模式从 I/O 流中出现的代码。
6.1 连接本地 FTP 服务器示例
require 'expect'
require 'socket'
$expect_verbose = true
socket = TCPSocket.new('localhost', 'ftp')
socket.expect("ready")
socket.puts("user testuser")
socket.expect("Password required for testuser")
socket.puts("pass secret")
socket.expect("logged in.\r\n")
socket.puts("pwd")
puts(socket.gets)
socket.puts "quit"
运行结果:
220 localhost FTP server (lukemftpd 1.1) ready.
331 Password required for testuser.
230-
Welcome to Darwin!
230 User testuser logged in.
257 "/Users/testuser" is the current directory.
7. Fcntl 库:IO#fcntl 命令的符号名称
Fcntl
模块为每个主机系统可用的
fcntl
常量提供符号名称。
7.1 查看 Mac OS X 系统上的 Fcntl 常量值
require 'fcntl'
Fcntl.constants.sort.each do |name|
printf "%10s: %04x\n", name, Fcntl.const_get(name)
end
运行结果:
FD_CLOEXEC: 0001
F_DUPFD: 0000
F_GETFD: 0001
F_GETFL: 0003
F_GETLK: 0007
F_RDLCK: 0001
F_SETFD: 0002
F_SETFL: 0004
F_SETLK: 0008
F_SETLKW: 0009
F_UNLCK: 0002
F_WRLCK: 0003
O_ACCMODE: 0003
O_APPEND: 0008
O_CREAT: 0200
O_EXCL: 0800
O_NDELAY: 0004
O_NOCTTY: 0000
O_NONBLOCK: 0004
O_RDONLY: 0000
O_RDWR: 0002
O_TRUNC: 0400
O_WRONLY: 0001
8. FileUtils 库:文件和目录操作
FileUtils
是一组用于操作文件和目录的方法,在编写安装脚本时特别有用。
8.1 方法选项说明
| 选项 | 含义 |
|---|---|
:verbose
|
跟踪每个函数的执行(默认输出到 STDERR,可通过设置类变量
@fileutils_output
覆盖)
|
:noop
| 不执行函数的操作,用于测试脚本 |
:force
| 覆盖方法的一些默认保守行为(如覆盖现有文件) |
:preserve
|
尝试保留源文件的
atime
、
mtime
和
mode
信息到目标文件(
setuid
和
setgid
标志始终清除)
|
8.2 示例代码
require 'fileutils'
include FileUtils::Verbose
cd("/tmp") do
cp("/etc/passwd", "tmp_passwd")
chmod(0666, "tmp_passwd")
cp_r("/usr/include/net/", "headers")
rm("tmp_passwd")
rm_rf("headers")
end
运行结果:
cd /tmp
cp /etc/passwd tmp_passwd
chmod 666 tmp_passwd
cp -r /usr/include/net/ headers
rm tmp_passwd
rm -rf headers
cd -
9. Find 库:遍历目录树
Find
模块支持对一组文件路径进行自上而下的遍历。
9.1 示例代码
require 'find'
Find.find("/etc/passwd", "code/cdjukebox") do |f|
type = case
when File.file?(f): "F"
when File.directory?(f): "D"
else "?"
end
puts "#{type}: #{f}"
Find.prune if f =~ /CVS/
end
运行结果:
F: /etc/passwd
D: code/cdjukebox
F: code/cdjukebox/Makefile
F: code/cdjukebox/libcdjukebox.a
D: code/cdjukebox/CVS
F: code/cdjukebox/cdjukebox.o
F: code/cdjukebox/cdjukebox.h
F: code/cdjukebox/cdjukebox.c
10. Forwardable 库:对象委托
Forwardable
提供了一种机制,允许类将命名方法调用委托给其他对象。
10.1 符号表示例
require 'forwardable'
class SymbolTable
extend Forwardable
def_delegator(:@hash, :[], :lookup)
def_delegator(:@hash, :[]=, :add)
def_delegators(:@hash, :size, :has_key?)
def initialize
@hash = Hash.new
end
end
st = SymbolTable.new
st.add('cat', 'feline animal')
st.add('dog', 'canine animal')
st.add('cow', 'bovine animal')
puts st.has_key?('cow') # 输出: true
puts st.lookup('dog') # 输出: canine animal
10.2 单个对象委托示例
require 'forwardable'
TRICKS = [ "roll over", "play dead" ]
dog = "rover"
dog.extend SingleForwardable
dog.def_delegator(:TRICKS, :each, :can)
dog.can do |trick|
puts trick
end
运行结果:
roll over
play dead
11. ftools 库:File 类的额外工具
ftools
库为
File
类添加了一些方法,主要用于移动和复制文件的程序,但现在推荐使用
FileUtils
库。
11.1 示例代码
require 'ftools'
def install_if_different(source, dest)
if File.exist?(dest) && File.compare(source, dest)
puts "#{dest} is up to date"
else
File.copy(source, dest)
puts "#{source} copied to #{dest}"
end
end
install_if_different('testfile', '/tmp/testfile')
puts "Second time..."
install_if_different('testfile', '/tmp/testfile')
puts "Done"
运行结果:
testfile copied to /tmp/testfile
Second time...
/tmp/testfile is up to date
Done
11.2 使用
FTool
的
install
方法
require 'ftools'
File.install('testfile', '/tmp', 0644, true)
puts "Second time..."
File.install('testfile', '/tmp', 0644, true)
puts "Done"
运行结果:
testfile -> /tmp/testfile
chmod 0644 /tmp/testfile
Second time...
Done
12. GDBM 库:GDBM 数据库接口
GDBM
库提供了对 GDBM 数据库的接口,能访问一些底层的 GDBM 特性。
12.1 存储和读取数据示例
require 'gdbm'
GDBM.open("data.dbm", 0644, GDBM::WRCREAT | GDBM::SYNC) do |dbm|
dbm['name'] = "Walter Wombat"
dbm['dob'] = "1969-12-25"
dbm['uses'] = "Ruby"
end
GDBM.open("data.dbm") do |dbm|
p dbm.keys
p dbm['dob']
dbm.delete('dob')
p dbm.keys
end
运行结果:
["uses", "dob", "name"]
"1969-12-25"
["uses", "name"]
12.2 只读打开数据库示例
require 'gdbm'
GDBM.open("data.dbm", 0, GDBM::READER) do |dbm|
p dbm.keys
dbm.delete('name')
end
运行结果:
["uses", "name"]
prog.rb:4:in `delete': Reader can't delete (GDBMError)
from prog.rb:4
from prog.rb:2:in `open'
13. Generator 库:外部迭代器
Generator
库基于可枚举对象或一个产生值的块实现外部迭代器。
13.1 遍历可枚举对象示例
require 'generator'
gen = Generator.new(1..4)
while gen.next?
print gen.next, "--"
end
运行结果:
1--2--3--4--
13.2 遍历块示例
require 'generator'
gen = Generator.new do |result|
result.yield "Start"
3.times {|i| result.yield i}
result.yield "done"
end
while gen.next?
print gen.next, "--"
end
运行结果:
Start--0--1--2--done--
13.3 同时遍历两个集合示例
require 'generator'
gen = SyncEnumerator.new(1..3, "a".."c")
gen.each {|num, char| print num, "(", char, ") " }
运行结果:
1(a) 2(b) 3(c)
14. GetoptLong 库:解析命令行选项
GetoptLong
类支持 GNU 风格的命令行选项解析。
14.1 示例代码
require 'getoptlong'
opts = GetoptLong.new(
[ "--size", "-s", GetoptLong::REQUIRED_ARGUMENT ],
[ "--verbose", "-v", GetoptLong::NO_ARGUMENT ],
[ "--query", "-q", GetoptLong::NO_ARGUMENT ],
[ "--check", "--valid", "-c", GetoptLong::NO_ARGUMENT ]
)
opts.each do |opt, arg|
puts "Option: #{opt}, arg #{arg.inspect}"
end
puts "Remaining args: #{ARGV.join(', ')}"
运行命令:
ruby example.rb --size 10k -v -q a.txt b.doc
运行结果:
Option: --size, arg "10k"
Option: --verbose, arg ""
Option: --query, arg ""
Remaining args: a.txt, b.doc
15. 各库使用场景总结
为了更清晰地了解各个库的使用场景,下面通过表格进行总结:
| 库名称 | 使用场景 |
| — | — |
| dRuby | 实现 Ruby 对象的分布式处理,适用于需要在网络中不同节点间共享和交互对象的场景,如分布式系统开发 |
| English | 让 Ruby 脚本中引用全局变量时使用更清晰的名称,提高代码的可读性 |
| Enumerator | 当需要对对象的任意方法使用标准枚举技术时,可基于现有对象创建新的可迭代对象 |
| ERB | 用于创建 HTML 文档或处理其他纯文本场景,将 Ruby 代码和纯文本混合,实现轻量级模板功能 |
| Etc | 在 Unix 系统中,用于查询用户和组的信息,如用户登录信息、用户组信息等 |
| expect | 对于 IO 对象,需要等待特定字符串或模式从 I/O 流中出现时使用,常用于与外部交互式进程的协调 |
| Fcntl | 为系统的 fcntl 常量提供符号名称,方便在代码中使用 |
| FileUtils | 进行文件和目录的操作,如复制、移动、删除等,在编写安装脚本时非常有用 |
| Find | 对文件路径进行自上而下的遍历,可用于查找文件或处理目录树 |
| Forwardable | 实现对象委托,将类的命名方法调用委托给其他对象,简化代码结构 |
| ftools | 为 File 类添加额外方法,用于移动和复制文件,但现在推荐使用 FileUtils 库 |
| GDBM | 提供对 GDBM 数据库的接口,可进行数据的存储和读取,访问底层 GDBM 特性 |
| Generator | 基于可枚举对象或块实现外部迭代器,适用于需要自定义迭代逻辑的场景 |
| GetoptLong | 解析 GNU 风格的命令行选项,处理命令行参数 |
16. 库使用的流程图示例
下面以使用 dRuby 库实现客户端 - 服务器通信为例,给出 mermaid 格式的流程图:
graph LR
classDef startend fill:#F5EBFF,stroke:#BE8FED,stroke-width:2px;
classDef process fill:#E5F6FF,stroke:#73A6FF,stroke-width:2px;
classDef decision fill:#FFF6CC,stroke:#FFBC52,stroke-width:2px;
A([开始]):::startend --> B(服务器启动服务):::process
B --> C(等待客户端连接):::process
D([客户端启动服务]):::startend --> E(客户端连接服务器):::process
E --> F{连接成功?}:::decision
F -- 是 --> G(客户端注册监听器):::process
F -- 否 --> E
G --> H(服务器运行并通知客户端):::process
H --> I(客户端接收通知并处理):::process
I --> J([结束]):::startend
C --> H
17. 代码复用与组合使用
在实际开发中,我们可以将多个库组合使用,以实现更复杂的功能。例如,结合 FileUtils 和 Find 库,我们可以实现一个文件备份脚本:
require 'fileutils'
require 'find'
# 定义备份目录
backup_dir = "/backup"
# 定义需要备份的目录
source_dir = "/data"
# 创建备份目录
FileUtils.mkdir_p(backup_dir)
# 遍历源目录
Find.find(source_dir) do |file|
if File.file?(file)
# 计算备份文件的目标路径
relative_path = file.sub(source_dir, "")
target_path = backup_dir + relative_path
target_dir = File.dirname(target_path)
# 创建目标目录
FileUtils.mkdir_p(target_dir)
# 复制文件
FileUtils.cp(file, target_path)
puts "#{file} 已备份到 #{target_path}"
end
end
在这个示例中,我们使用 Find 库遍历源目录下的所有文件,然后使用 FileUtils 库创建备份目录和复制文件。
18. 性能考虑
在使用这些库时,也需要考虑性能问题。例如,在使用 FileUtils 进行大量文件操作时,频繁的文件读写可能会影响性能。可以通过批量操作或异步操作来优化性能。另外,在使用 GDBM 数据库时,由于同一时间只能有一个进程对数据库进行写操作(除非禁用锁定),因此在多进程环境下需要注意并发控制。
19. 总结
本文详细介绍了 Ruby 中的多个库,包括它们的功能、使用方法和示例代码。通过对这些库的学习,我们可以更高效地开发 Ruby 程序,处理各种不同的场景。在实际应用中,我们可以根据具体需求选择合适的库,并将它们组合使用,以实现复杂的功能。同时,也要注意性能和并发控制等问题,确保程序的稳定性和高效性。希望这些内容能帮助你更好地掌握 Ruby 编程。
超级会员免费看

62

被折叠的 条评论
为什么被折叠?



