在 Ruby 中的命令行参数 ( 上 ) 章节中,我们介绍了 Ruby 处理命令行参数时的 ARGV
数组和 ARGF
文件流对象。
但是,这两个全局变量远远不能满足我们的要求,复杂的命令行参数往往涉及到解析问题。何况,如果命令行参数多了,我们总不能每一个都去数一数它位于第几个位置吧。
所以本章节,我们来讲讲 Ruby 中的命令行参数解析问题,包括以下几个知识点:
OptionParser
类OptionParser#on
方法OptionParser#on
和强制类型
加载模块
使用 OptionParser
类之前必须先加载模块
require 'optparse'
OptionParser
类
OptionParser
是一个简化命令行选项解析和解释的类,这个类提供了一堆方法来处理横幅 ( banners ),选项帮助消息 ( option help ),类型强制 ( type coercion ) 等
OptionParser#on
方法
OptionParser#on
方法将与处理 ( handler
) 程序关联的 switch
添加到解析器
任意一个 switch
必须是 OptionParser::Switch
及其派生类的实例。
常见的派生类如下
OptionParser::Switch::NoArgument
OptionParser::Switch::RequiredArgument
OptionParser::Switch::OptionalArgument
这些类根据它们自己的专业性负责处理 ( 或不处理 ) 参数
OptionParser#on
方法还保留了能够作为参数传递的块。该块作为 proc
存储在相应的 switch
内
这些 switch
涉及到非常多的专业术语,且一时难以解释,因此,让我们通过每个 switch
的一些示例来分解这些概念
OptionParser::Switch::NoArgument
OptionParser#on
方法的基本用法是处理一个不期望任何参数的选项
# in parser.rb require 'optparse' require 'optparse/time' OptionParser.new do |parser| parser.on('-t', '--time') do |time| p time end end.parse!
上面这段代码中,程序将能够将短选项 -t
和长选项 --time
与传递给 parser.on()
方法的参数块相关联。
上面这个示例中,-t
和 --t
选项不需要传递任何值,因此生成的 switch
将是 OptionParser::Switch::NoArgument
的实例。
这也意味着任何传递给 -t
或 --t
的值将会被忽略
?> ruby parser.rb --time=11:12:13 true
从上面的代码中可以看到,传递的值 11:12:13
被忽略了,而返回的值却是 true
接下来,我们看看如何为给定的选项要求一个值。
OptionParser::Switch::RequiredArgument
让我们看一下需要参数的语法。
# in parser.rb require 'optparse' require 'optparse/time' OptionParser.new do |parser| parser.on('-t', '--time=TIME') do |time| p time end end.parse!
上面的程序中,-t
参数指明了需要传递值,因为使用了 =TIME
。
因此,为 -t
选项生成的 switch
将是 OptionParser::Switch::RequiredArgument
的实例
?> ruby parser.rb --time=11:12:13 "11:12:13" ?> ruby parser.rb --time parser.rb:8:in `<main>’: missing argument: --time (OptionParser::MissingArgument)
上面的代码中,给 --time
选项传递的值 11:12:13
会作为参数块传递给 parse.on()
方法
需要注意的是,选项 --time
的值是 字符串
同样的,因为必须传递一个值,所以,如果没有给 --time
选项指定值的话,那么就会抛出 OptionParser::MissingArgument
异常。
接下来,我们看看如何定一个可选项,它的值也是可选的 ( optional )
OptionParser::Switch::OptionalArgument
让我们看一下命令行参数添加可选值的语法。
# in parser.rb require 'optparse' require 'optparse/time' OptionParser.new do |parser| parser.on('-t', '--time[=TIME]') do |time| p time end end.parse!
从上面的代码中可以看出,定一个值可选的命令行参数的语法是用中括号将 =TIME
扩起来,变成 [=TIME]
在这种情况下,为 -t
选项生成的 switch
是 OptionParser::Switch::OptionalArgument
的实例
?> ruby parser.rb --time=11:12:13 "11:12:13" ?> ruby parser.rb --time nil
此外,如果没有为 --time
命令行选项提供任何值,那么 time
参数的值就是 nil
默认情况下, --time
命令行选项接受的是一个字符串类型的值 11:12:13
。如果能接收 Time 对象应该是更酷的。
OptionParser#on
方法和强制类型
前面的范例中,11:12:13
始终是字符串 ( String ) 的一个实例。
但是,如果能够直接接受一个 Time
类的实例的块作为参数就更加棒了。
为了实现这个目的,我们可以给 OptionParser#on
方法传递第三个参数。此参数应该是类一个类 Ruby 类,以便将传递给选项的值转换为给定类类型的实例
require 'optparse' require 'optparse/time' OptionParser.new do |parser| parser.on('-t', '--time=TIME', Time) do |time| p time.class end end.parse!
让我们运行下这个程序
?> ruby parser.rb --time=11:12:13 Time
从上面的代码中可以看出,time
参数现在是 Time
类的实例,这是通过将类 Time
做为第三个参数传递给 parser.on()
方法实现的。