我正在编写CLI工具并拥有以下代码:
commands = {
:'-h' => :help,
:'--help' => :help,
:help => :help,
:r => :remove,
:rm => :remove,
# ...
}
if some_obj.respond_to? commands[ARGV.first.to_sym]
some_obj.send commands[ARGV.first.to_sym]
end
但是,如果在ARGV.first.to_sym
中找不到commands
,则respond_to?
会抱怨
./tool.rb:121:in `respond_to?': nil is not a symbol (TypeError)
from ./tool.rb:121:in `<main>'
是否可以在没有此错误的情况下使用其他方法,并且无需明确检查nil
?
感谢。
答案 0 :(得分:2)
一个明显的解决方法是事先检查是否存在该命令
if cmd = commands[ARGV.first.to_sym]
if some_obj.respond_to? cmd
some_obj.send cmd
end
else
# complain about unrecognized command
end
更好的方法是使用专为此类任务构建的工具OptionParser。
# example from the doc
options = {}
OptionParser.new do |opts|
opts.banner = "Usage: example.rb [options]"
opts.on("-v", "--[no-]verbose", "Run verbosely") do |v|
options[:verbose] = v
end
end.parse!
respond_to?
也会愉快地接受一个字符串。所以,为了快速解决这个问题:
if some_obj.respond_to? commands[ARGV.first.to_sym].to_s
# ...
end
nil.to_s
为空字符串,respond_to?
将返回false
。
答案 1 :(得分:1)
作为Sergio答案的替代方案(也很好),您可以使用哈希值的默认值:
commands = Hash.new("").merge(
:'-h' => :help,
:'--help' => :help,
:help => :help,
:r => :remove,
:rm => :remove,
# ...
)
然后您无需检查nil
。
commands[ARGV.first.to_sym]
.tap{|cmd| some_obj.send(cmd) if some_obj.respond_to?(cmd)}