getopts -> OptionParser

Rubyコマンドラインオプションを取り扱うにはどうするのか、調べようと思いました。
(たしかgetoptsという関数があったはず…)

> refe getopts
not match: getopts

(あれれ?違ったかしらん。)

> refe opt
OpenSSL::SSL::SSLContext#options
OpenSSL::SSL::SSLContext#options=
OptionParser::Arguable#options
OptionParser::Arguable#options= Regexp#options
Syslog.options

(ははあ、OptionParserクラスかな)

> refe OptionParser
==== OptionParser ====
optparse.rb
optparse::チュートリアル
執筆者募集

コマンドラインのオプションを取り扱うためのクラスです。
オプションが指定された時に呼ばれるブロックを OptionParser#on [OptionParser/on] メソッドで
登録していきます。つまり、
OptionParser を使う場合、基本的には

(1) OptionParser オブジェクト opt を生成する。
(2) オプションを取り扱うブロックを opt に登録する。
(3) opt.parse(ARGV) でコマンドラインを実際に parse する。

というような流れになります。

  require "optparse"
  ProgramConfig = Hash.new
  opts = OptionParser.new
  opts.on("-a"){|v| ProgramConfig[:a] = true } # -a オプションがコマンドラインで指定されていた場合の動作。
  opts.parse!(ARGV)                            # 実際にコマンドラインの parse を行う。
...

ふむふむ。onメソッドは「登録」なのですね。
Google先生に聞いてみると、getopts.rb は Ruby 1.8.1 より後では非推奨というのが見つかりました。はあ、そうですか。
では、たとえば、次のようなオプションを理解させてみましょう。

  • -d
  • -x
require "optparse"

ProgramConfig = Hash.new
opt = OptionParser.new
opt.on("-x") do |f|
  ProgramConfig[:x] = true
end
opt.on("-d") do |f|
  ProgramConfig[:d] = true
end
opt.parse!(ARGV)

ProgramConfig.each_pair do |k,v|
  puts "#{k} => #{v}"
end

動かしてみます。

> ruby a.rb

> ruby a.rb -d
d => true

> ruby a.rb -dx
d => true
x => true

> ruby a.rb -xd
d => true
x => true

> ruby a.rb --help
Usage: a [options]
    -x
    -d

> ruby a.rb -h
Usage: a [options]
    -x
    -d

> ruby a.rb -3
c:/ruby/lib/ruby/1.8/optparse.rb:1445:in `complete': invalid option: -3 (OptionParser::InvalidOption)
        from c:/ruby/lib/ruby/1.8/optparse.rb:1443:in `complete'
        from c:/ruby/lib/ruby/1.8/optparse.rb:1302:in `order!'
        from c:/ruby/lib/ruby/1.8/optparse.rb:1271:in `order!'
        from c:/ruby/lib/ruby/1.8/optparse.rb:1351:in `permute!'
        from c:/ruby/lib/ruby/1.8/optparse.rb:1378:in `parse!'
        from a.rb:11

余談ですが、マニュアルのようなドキュメントでは例が重要だということがよくわかりました。OptionParserのドキュメントも、使い方が書いてあるからすぐに使えるのですね。そういえば、Perlのperldocでも、一番最初にSYNOPSISが出てきます。たいていはここをコピー&ペーストして書き直すと8割方は十分という気がします。
疑問: -d 3とか、値を取るオプションはどうするのかしらん→以下で解決しました。
追記: id:secondlifeさんからopt.on('-d') {|v| p v }というのを教えていただいたのですが、どうもvにはtrueしか来ないようなんです…。

require "optparse"

opt = OptionParser.new
opt.on("-d") {|v| puts "v=#{v}" }
opt.parse!(ARGV)

実行例です。

> ruby a.rb -d 123
v=true

追記: すみません、わたしこそ人に調べさせておりますm(_ _)m id:secondlifeさんありがとうございます。

require "optparse"

opt = OptionParser.new
opt.on("-d VAL") {|v| puts "v=#{v}" }
opt.parse!(ARGV)

実行例です。

> ruby a.rb -d 123
v=123