回应?抱怨nil不是一个象征

时间:2013-01-03 09:30:41

标签: ruby metaprogramming

我正在编写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

感谢。

2 个答案:

答案 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)}