0

我正在编写一个 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中找不到时commandsrespond_to?抱怨

./tool.rb:121:in `respond_to?': nil is not a symbol (TypeError)
        from ./tool.rb:121:in `<main>'

是否可以在没有此错误的情况下使用其他方法,并且也无需nil明确检查?

谢谢。

4

2 回答 2

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

于 2013-01-03T09:33:29.693 回答
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)}
于 2013-01-03T10:08:47.250 回答