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 に答える