50、Ruby 实用库功能解析与应用示例

开发板推荐:天空星STM32F407VET6开发板

超高性价比 STM32主控 | 超高主频 | 一板兼容百芯 | 比赛神器 | 沉金彩色丝印

Ruby 实用库功能解析与应用示例

在 Ruby 编程中,有许多实用的库可以帮助开发者实现各种功能,如邮件处理、网络连接、字符编码转换等。以下将详细介绍一些常用库的功能和使用方法。

1. Net::POP:访问 POP 邮件服务器

Net::POP 库提供了一个简单的客户端,用于在邮局协议(POP)服务器上获取和删除邮件。 Net::POP3 类用于访问 POP 服务器,返回一个 Net::POPMail 对象列表,每个对象代表服务器上存储的一条消息。

示例代码

require 'net/pop'
pop = Net::POP3.new('server.ruby-stuff.com')
pop.start('joe', 'secret') do |server|
  msg = server.mails[0]
  # Print the 'From:' header line
  from = msg.header.split("\r\n").grep(/^From: /)[0]
  puts from
  puts
  puts "Full message:"
  text = msg.pop
  puts text
end

输出结果

From: dave@facet.ruby-stuff.com (Dave Thomas)
Full message:
Return-Path: <dave@facet.ruby-stuff.com>
Received: from facet.ruby-stuff.com (facet.ruby-stuff.com [10.96.0.122])
by pragprog.com (8.11.6/8.11.6) with ESMTP id i2PJMW701809
for <joe@carat.ruby-stuff.com>; Thu, 25 Mar 2004 13:22:32 -0600
Received: by facet.ruby-stuff.com (Postfix, from userid 502)
id 4AF228B1BD; Thu, 25 Mar 2004 13:22:36 -0600 (CST)
To: joe@carat.ruby-stuff.com
Subject: Try out the new features!
Message-Id: <20040325192236.4AF228B1BD@facet.ruby-stuff.com>
Date: Thu, 25 Mar 2004 13:22:36 -0600 (CST)
From: dave@facet.ruby-stuff.com (Dave Thomas)
Status: RO
Ruby 1.8 has a boatload of new features, both in
the core language and in the supplied libraries.
Try it out!

2. Net::SMTP:简单 SMTP 客户端

Net::SMTP 库提供了一个简单的客户端,用于使用简单邮件传输协议(SMTP)发送电子邮件。它不协助创建消息负载,只是在构造好 RFC822 消息后发送消息。

2.1 从字符串发送电子邮件

require 'net/smtp'
msg = "Subject: Test\n\nNow is the time\n"
Net::SMTP.start('pragprog.com') do |smtp|
  smtp.send_message(msg, 'dave@pragprog.com', ['dave'])
end

2.2 使用 SMTP 对象和适配器发送电子邮件

require 'net/smtp'
Net::SMTP::start('pragprog.com', 25, "pragprog.com") do |smtp|
  smtp.open_message_stream('dave@pragprog.com', # from
                           [ 'dave' ]           # to
  ) do |stream|
    stream.puts "Subject: Test1"
    stream.puts
    stream.puts "And so is this"
  end
end

2.3 向需要 CRAM - MD5 认证的服务器发送电子邮件

require 'net/smtp'
msg = "Subject: Test\n\nNow is the time\n"
Net::SMTP.start('pragprog.com', 25, 'pragprog.com',
                'user', 'password', :cram_md5) do |smtp|
  smtp.send_message(msg, 'dave@pragprog.com', ['dave'])
end

3. Net::Telnet:Telnet 客户端

Net::Telnet 库提供了一个完整的 Telnet 客户端实现,并包含一些功能,使其成为与非 Telnet 服务交互的便捷机制。

3.1 连接到本地主机,运行日期命令并断开连接

require 'net/telnet'
tn = Net::Telnet.new({})
tn.login "guest", "secret"
tn.cmd "date"
# → "date\nThu Aug 26 22:38:56 CDT 2004\n% "
tn.close
# → nil

3.2 实时输出服务器响应

require 'net/telnet'
tn = Net::Telnet.new({}) {|str| print str }
tn.login("guest", "secret") {|str| print str }
tn.cmd("date") {|str| print str }
tn.close

3.3 从 NTP 服务器获取时间

require 'net/telnet'
tn = Net::Telnet.new('Host' => 'time.nonexistent.org',
                     'Port' => 'time',
                     'Timeout' => 60,
                     'Telnetmode' => false)
atomic_time = tn.recv(4).unpack('N')[0]
puts "Atomic time: " + Time.at(atomic_time - 2208988800).to_s
puts "Local time: " + Time.now.to_s

4. NKF:网络汉字过滤器接口

NKF 模块是 Itaru Ichikawa 的网络汉字过滤器(NKF)库(版本 1.7)的包装器。它提供了猜测 JIS、EUC 和 SJIS 流编码的功能,并可以进行编码转换。

4.1 编码常量

require 'nkf'
NKF::AUTO # → 0
NKF::JIS  # → 1
NKF::EUC  # → 2
NKF::SJIS # → 3

4.2 猜测字符串编码

require 'nkf'
NKF.guess("Yukihiro Matsumoto") # → 0
NKF.guess("\e$B$^$D$b$H$f$-$R$m\e(B") # → 1
NKF.guess("\244\336\244\304\244\342\244\310\244\346\244\255\244\322\244\355") # → 2
NKF.guess("\202\334\202\302\202\340\202\306\202\344\202\253\202\320\202\353") # → 3

4.3 编码转换

$ ruby -e ’p *ARGV’
"\244\336\244\304\244\342\244\310\244\346\244\255\244\322\244\355"
$ ruby -rnkf -e ’p NKF.nkf(*ARGV)’ - -Es
"\202\334\202\302\202\340\202\306\202\344\202\253\202\320\202\353"
$ ruby -rnkf -e ’p NKF.nkf(*ARGV)’ - -Ej
"\e$B$^$D$b$H$f$-$R$m\e(B"

5. Observable:观察者模式

观察者模式(也称为发布/订阅模式)提供了一种简单的机制,当一个对象(源)的状态发生变化时,通知一组感兴趣的第三方对象。在 Ruby 实现中,通知类混入 Observable 模块,该模块提供了管理关联观察者对象的方法。观察者必须实现 update 方法以接收通知。

示例代码

require 'observer'
class CheckWaterTemperature # Periodically check the water
  include Observable
  def run
    last_temp = nil
    loop do
      temp = Temperature.fetch # external class...
      puts "Current temperature: #{temp}"
      if temp != last_temp
        changed # notify observers
        notify_observers(Time.now, temp)
        last_temp = temp
      end
    end
  end
end

class Warner
  def initialize(&limit)
    @limit = limit
  end

  def update(time, temp)
    # callback for observer
    if @limit.call(temp)
      puts "--- #{time.to_s}: Temperature outside range: #{temp}"
    end
  end
end

checker = CheckWaterTemperature.new
checker.add_observer(Warner.new {|t| t < 80})
checker.add_observer(Warner.new {|t| t > 120})
checker.run

输出结果

Current temperature: 83
Current temperature: 75
--- Thu Aug 26 22:38:59 CDT 2004: Temperature outside range: 75
Current temperature: 90
Current temperature: 134
--- Thu Aug 26 22:38:59 CDT 2004: Temperature outside range: 134
Current temperature: 134
Current temperature: 112
Current temperature: 79
--- Thu Aug 26 22:38:59 CDT 2004: Temperature outside range: 79

6. Open - uri:将 FTP 和 HTTP 资源视为文件

Open - uri 库扩展了 Kernel#open ,允许它接受 FTP 和 HTTP 的 URI 以及本地文件名。打开后,这些资源可以像本地文件一样处理,使用常规的 IO 方法进行访问。

示例代码

require 'open-uri'
require 'pp'
open('http://localhost/index.html') do |f|
  puts "URI: #{f.base_uri}"
  puts "Content-type: #{f.content_type}, charset: #{f.charset}"
  puts "Encoding: #{f.content_encoding}"
  puts "Last modified: #{f.last_modified}"
  puts "Status: #{f.status.inspect}"
  pp f.meta
  puts "----"
  3.times {|i| puts "#{i}: #{f.gets}" }
end

输出结果

URI: http://localhost/index.html
Content-type: text/html, charset: iso-8859-1
Encoding:
Last modified: Wed Jul 18 23:44:21 UTC 2001
Status: ["200", "OK"]
{"vary"=>"negotiate,accept-language,accept-charset",
 "last-modified"=>"Wed, 18 Jul 2001 23:44:21 GMT",
 "content-location"=>"index.html.en",
 "date"=>"Fri, 27 Aug 2004 03:38:59 GMT",
 "etag"=>"\"6657-5b0-3b561f55;411edab5\"",
 "content-type"=>"text/html",
 "content-language"=>"en",
 "server"=>"Apache/1.3.29 (Darwin)",
 "content-length"=>"1456",
 "tcn"=>"choice",
 "accept-ranges"=>"bytes"}
----
0: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
1:
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
2: <html xmlns="http://www.w3.org/1999/xhtml">

7. Open3:运行子进程并连接到所有流

Open3 库用于在子进程中运行命令。写入标准输入的数据可以被子进程读取,子进程中写入标准输出和标准错误的数据可以在 stdout stderr 流中获取。

示例代码

require 'open3'
Open3.popen3('bc') do | stdin, stdout, stderr |
  Thread.new { loop { puts "Err stream: #{stderr.gets}" } }
  Thread.new { loop { puts "Output stream: #{stdout.gets}" } }
  stdin.puts "3 * 4"
  stdin.puts "1 / 0"
  stdin.puts "2 ^ 5"
  sleep 0.1
end

输出结果

Output stream: 12
Err stream:
Runtime error (func=(main), adr=3): Divide by zero
Output stream: 32
Err stream:

8. OpenSSL:SSL 库

Ruby 的 OpenSSL 扩展包装了免费的 OpenSSL 库,提供了安全套接层和传输层安全(SSL 和 TLS)协议,允许在网络上进行安全通信。

8.1 访问安全网站

require 'net/https'
USER = "xxx"
PW = "yyy"
site = Net::HTTP.new("www.securestuff.com", 443)
site.use_ssl = true
response = site.get2("/cgi-bin/cokerecipe.cgi",
                     'Authorization' => 'Basic ' +
                     ["#{USER}:#{PW}"].pack('m').strip)

8.2 创建使用 SSL 的套接字

require 'socket'
require 'openssl'
socket = TCPSocket.new("www.secure-stuff.com", 443)
ssl_context = OpenSSL::SSL::SSLContext.new()
unless ssl_context.verify_mode
  warn "warning: peer certificate won't be verified this session."
  ssl_context.verify_mode = OpenSSL::SSL::VERIFY_NONE
end
sslsocket = OpenSSL::SSL::SSLSocket.new(socket, ssl_context)
sslsocket.sync_close = true
sslsocket.connect
sslsocket.puts("GET /secret-info.shtml")
while line = sslsocket.gets
  p line
end

9. OpenStruct:开放(动态)结构

OpenStruct 是一种开放结构,其属性在首次赋值时动态创建。

示例代码

require 'ostruct'
os = OpenStruct.new( "f1" => "one", :f2 => "two" )
os.f3 = "cat"
os.f4 = 99
os.f1 # → "one"
os.f2 # → "two"
os.f3 # → "cat"
os.f4 # → 99

10. OptionParser:选项解析

OptionParser 是一种灵活且可扩展的方式,用于解析命令行参数。

示例代码

require 'optparse'
require 'date'
# Add Dates as a new option type
OptionParser.accept(Date, /(\d+)-(\d+)-(\d+)/) do |d, mon, day, year|
  Date.new(year.to_i, mon.to_i, day.to_i)
end

opts = OptionParser.new
opts.on("-x") {|val| puts "-x seen" }
opts.on("-s", "--size VAL", Integer) {|val| puts "-s #{val}" }
opts.on("-a", "--at DATE", Date) {|val| puts "-a #{val}" }

my_argv = [ "--size", "1234", "-x", "-a", "12-25-2003", "fred", "wilma" ]
rest = opts.parse(*my_argv)
puts "Remainder = #{rest.join(', ')}"
puts opts.to_s

输出结果

-s 1234
-x seen
-a 2003-12-25
Remainder = fred, wilma
Usage: myprog [options]
-x
-s, --size VAL
-a, --at DATE

Option 定义参数表

参数形式 说明
“-x” “-xARG” “-x=ARG” “-x[OPT]” “-x[=OPT]” “-x PLACE” 选项有短名称 x。第一种形式无参数,接下来两种有强制参数,再接下来两种有可选参数,最后一种指定参数跟随选项。短名称也可以指定为范围(如 “-[a - c]”)
“–switch” “–switch=ARG” “–switch=[OPT]” “–switch PLACE” 选项有长名称 switch。第一种形式无参数,第二种有强制参数,第三种有可选参数,最后一种指定参数跟随开关
“–no - switch” 定义一个默认值为 false 的选项
“=ARG” “=[OPT]” 此选项的参数是强制或可选的。例如,以下代码表示有一个由 -x、-y 和 -z 别名表示的选项,它接受一个强制参数,在使用信息中显示为 N: opt.on("-x", "-y", "-z", "=N")
“description” 任何不以 - 或 = 开头的字符串都用作此选项在摘要中的描述。可以给出多个描述,它们将显示在额外的行上
“/pattern/” 任何参数必须匹配给定的模式
array 参数必须是数组中的值之一
proc or method 参数类型转换由给定的 proc 或方法执行(而不是使用 on def 方法调用关联的块)
ClassName 参数必须与为 ClassName 定义的匹配,ClassName 可以是预定义的或使用 OptionParser.accept 添加的。内置参数类包括:Object(任何字符串,不转换,默认)、String(任何非空字符串,不转换)、Integer(Ruby/C 风格的整数,可选符号,0ddd 是八进制,0bddd 是二进制,0xddd 是十六进制,转换为 Integer)、Float(浮点数格式,转换为 Float)、Numeric(通用数字格式,整数转换为 Integer,浮点数转换为 Float)、Array(参数必须是由逗号分隔的字符串列表)、OptionParser::DecimalInteger(十进制整数,转换为 Integer)、OptionParser::OctalInteger(Ruby/C 风格的八进制/十六进制/二进制整数)、OptionParser::DecimalNumeric(十进制整数/浮点数,整数转换为 Integer,浮点数转换为 Float)、TrueClass, FalseClass(布尔开关)

11. ParseDate:解析日期字符串

ParseDate 模块定义了一个方法 ParseDate.parsedate ,用于将日期和/或时间字符串转换为表示日期和/或时间组成部分的 Fixnum 值数组。

示例

字符串 猜测参数 时区 星期
1999 - 09 - 05 23:55:21 + 0900 F 1999 9 5 23 55 21 + 0900
1983 - 12 - 25 F 1983 12 25
1965 - 11 - 10 T13:45 F 1965 11 10 13 45
10/9/75 1:30pm F 75 10 9 13 30
10/9/75 1:30pm T 1975 10 9 13 30
Wed Feb 2 17:15:49 CST 2000 F 2000 2 2 17 15 49 CST 3
Tue, 02 - Mar - 99 11:20:32 GMT F 99 3 2 11 20 32 GMT 2
Tue, 02 - Mar - 99 11:20:32 GMT T 1999 3 2 11 20 32 GMT 2
12 - January - 1990, 04:00 WET F 1990 1 12 4 0 WET
4/3/99 F 99 4 3
4/3/99 T 1999 4 3
10th February, 1976 F 1976 2 10
March 1st, 84 T 1984 3 1
Friday F 5

12. Pathname:文件路径表示

Pathname 表示文件的绝对或相对名称,有两个主要用途:一是允许操作文件路径的各个部分,二是作为 Dir File FileTest 模块中某些方法的外观,将调用转发给由 Pathname 对象命名的文件。

12.1 路径名操作

require 'pathname'
p1 = Pathname.new("/usr/bin")
# → #<Pathname:/usr/bin>
p2 = Pathname.new("ruby")
# → #<Pathname:ruby>
p3 = p1 + p2
# → #<Pathname:/usr/bin/ruby>
p4 = p2 + p1
# → #<Pathname:/usr/bin>
p3.parent
# → #<Pathname:/usr/bin>
p3.parent.parent
# → #<Pathname:/usr>
p1.absolute?
# → true
p2.absolute?
# → false
p3.split
# → [#<Pathname:/usr/bin>, #<Pathname:ruby>]
p5 = Pathname.new("testdir")
# → #<Pathname:testdir>
p5.realpath
# → #<Pathname:/Users/dave/Work/rubybook/testdir>
p5.children
# → [#<Pathname:testdir/config.h>, #<Pathname:testdir/main.rb>]

12.2 Pathname 作为文件和目录状态请求的代理

require 'pathname'
p1 = Pathname.new("/usr/bin/ruby")
p1.file?
# → true
p1.directory?
# → false
p1.executable?
# → true
p1.size
# → 1913444
p2 = Pathname.new("testfile")
# → #<Pathname:testfile>
p2.read
# → "This is line one\nThis is line two\nThis is line three\nAnd so on...\n"
p2.readlines
# → ["This is line one\n", "This is line two\n", "This is line three\n", "And so on...\n"]

13. PP:漂亮打印对象

PP 使用 PrettyPrint 库来格式化 Ruby 对象的检查结果。它定义了一个全局函数 pp ,其工作方式类似于现有的 p 方法,但会格式化输出。

13.1 比较 “p” 和 “pp”

require 'pp'
Customer = Struct.new(:name, :sex, :dob, :country)
cust = Customer.new("Walter Wall", "Male", "12/25/1960", "Niue")
puts "Regular print"
p cust
puts "\nPretty print"
pp cust

输出结果

Regular print
#<struct Customer name="Walter Wall", sex="Male", dob="12/25/1960", country="Niue">
Pretty print
#<struct Customer
  name="Walter Wall",
  sex="Male",
  dob="12/25/1960",
  country="Niue">

13.2 避免重复显示对象

require 'pp'
a = "string"
b = [ a ]
c = [ b, b ]
PP.sharing_detection = false
pp c
PP.sharing_detection = true
pp c

输出结果

[["string"], ["string"]]
[["string"], [...]]

综上所述,这些 Ruby 库为开发者提供了丰富的功能,涵盖了邮件处理、网络连接、日期解析、文件操作等多个方面,能够帮助开发者更高效地完成各种编程任务。

14. 总结与应用建议

14.1 各库功能总结

库名称 主要功能
Net::POP 访问 POP 邮件服务器,获取和删除邮件
Net::SMTP 使用 SMTP 协议发送电子邮件
Net::Telnet 实现 Telnet 客户端,与非 Telnet 服务交互
NKF 猜测 JIS、EUC 和 SJIS 流编码并进行转换
Observable 实现观察者模式,状态变化时通知观察者
Open - uri 将 FTP 和 HTTP 资源视为文件进行操作
Open3 运行子进程并连接到所有流
OpenSSL 提供 SSL 和 TLS 协议,实现安全网络通信
OpenStruct 动态创建对象属性
OptionParser 灵活解析命令行参数
ParseDate 解析日期和时间字符串
Pathname 操作文件路径,代理文件和目录状态请求
PP 漂亮打印 Ruby 对象

14.2 应用场景建议

  • 邮件处理 :如果需要从 POP 服务器获取邮件或使用 SMTP 发送邮件,可分别使用 Net::POP Net::SMTP 库。例如,开发邮件客户端时, Net::POP 可用于接收邮件, Net::SMTP 可用于发送邮件。
  • 网络连接 Net::Telnet 适用于需要与 Telnet 服务或非 Telnet 服务进行交互的场景,如远程服务器管理。 OpenSSL 则用于实现安全的网络通信,如访问 HTTPS 网站。
  • 编码处理 :当处理包含不同编码的文本时, NKF 库可以帮助猜测和转换编码,确保文本的正确显示。
  • 设计模式 Observable 模块实现的观察者模式,适用于需要在对象状态变化时通知其他对象的场景,如监控系统中温度变化的通知。
  • 文件操作 Open - uri 允许将网络资源视为文件进行操作,方便获取远程文件。 Pathname 则用于处理文件路径,进行路径操作和文件状态查询。
  • 命令行解析 OptionParser 提供了灵活的命令行参数解析功能,适用于开发命令行工具。
  • 日期解析 ParseDate 模块可将各种日期和时间字符串解析为标准的日期和时间组件,方便进行日期处理。
  • 对象打印 PP 库可以将 Ruby 对象以更美观的格式打印出来,便于调试和查看对象信息。

14.3 开发流程建议

以下是一个简单的 mermaid 流程图,展示了在开发过程中选择合适库的基本流程:

graph TD;
    A[确定开发需求] --> B{需求类型};
    B -->|邮件处理| C(Net::POP/Net::SMTP);
    B -->|网络连接| D(Net::Telnet/OpenSSL);
    B -->|编码处理| E(NKF);
    B -->|设计模式| F(Observable);
    B -->|文件操作| G(Open - uri/Pathname);
    B -->|命令行解析| H(OptionParser);
    B -->|日期解析| I(ParseDate);
    B -->|对象打印| J(PP);

15. 注意事项与常见问题

15.1 注意事项

  • 依赖问题 :部分库可能依赖于其他库或外部工具,如 OpenSSL 依赖于 OpenSSL 库。在使用这些库之前,需要确保相关依赖已正确安装。
  • 编码兼容性 :在使用 NKF 进行编码转换时,要注意源编码和目标编码的兼容性,避免出现乱码问题。
  • 资源管理 :使用 Net::POP Net::SMTP Net::Telnet 等网络相关库时,要及时关闭连接,释放资源,避免资源泄漏。

15.2 常见问题及解决方法

问题描述 可能原因 解决方法
邮件发送失败 SMTP 服务器配置错误、认证失败 检查 SMTP 服务器地址、端口、用户名和密码是否正确
Telnet 连接失败 服务器地址或端口错误、服务器未开启 Telnet 服务 检查服务器地址和端口,确保服务器开启 Telnet 服务
编码转换后出现乱码 源编码猜测错误、目标编码不支持 检查源编码,确保目标编码支持转换
观察者未收到通知 观察者未实现 update 方法、 changed 方法未调用 确保观察者实现了 update 方法,在状态变化时调用 changed 方法

16. 未来发展与趋势

16.1 安全性增强

随着网络安全的重要性日益增加, OpenSSL 等安全相关库将不断发展,提供更强大的加密算法和安全机制,以应对日益复杂的网络攻击。

16.2 功能扩展

各库可能会不断扩展功能,以满足开发者日益多样化的需求。例如, Net::SMTP 可能会支持更多的邮件发送协议和认证方式。

16.3 与其他技术的集成

Ruby 库可能会与其他热门技术进行更紧密的集成,如与云计算、大数据等领域的技术结合,为开发者提供更全面的解决方案。

16.4 性能优化

为了提高开发效率和程序性能,各库将不断进行性能优化,减少资源消耗,提高响应速度。

17. 结语

Ruby 提供的这些丰富的库为开发者提供了强大的工具,能够帮助开发者更高效地完成各种编程任务。通过深入了解这些库的功能和使用方法,开发者可以根据具体需求选择合适的库,提高开发效率和代码质量。同时,关注这些库的未来发展趋势,能够使开发者更好地适应不断变化的技术环境,为开发出更优秀的软件奠定基础。在实际开发过程中,要注意各库的使用细节和注意事项,避免出现常见问题,确保程序的稳定性和可靠性。

开发板推荐:天空星STM32F407VET6开发板

超高性价比 STM32主控 | 超高主频 | 一板兼容百芯 | 比赛神器 | 沉金彩色丝印

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值