methods=Kernel/c.ARGV.optparse
sublibraries=optparse.shellwords,optparse.uri,optparse.time,optparse.date
requires=
classes=OptionParser=Arguable,OptionParser,OptionParser=ParseError,OptionParser=AmbiguousOption,OptionParser=NeedlessArgument,OptionParser=MissingArgument,OptionParser=InvalidOption,OptionParser=InvalidArgument,OptionParser=AmbiguousArgument
is_sublibrary=false

コマンドラインのオプションを取り扱うためのライブラリです。

=== optparse::チュートリアル

optparse を使う場合、基本的には

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

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


==== オプションの定義

以下はオプション -a, -b を受け付けるコマンドを作成する例です。

        require 'optparse'
        opt = OptionParser.new

        opt.on('-a') {|v| p v }
        opt.on('-b') {|v| p v }

        opt.parse!(ARGV)
        p ARGV

        ruby sample.rb -a foo bar -b baz
        # => true
             true
             ["foo", "bar", "baz"]

on() メソッドの引数でオプションを定義し、引数が指定された時の処理を
ブロックで記述します。ブロックの引数にはオプションが指定されたことを
示す true が渡されます(((<optparse::チュートリアル/オプションの引数>))も参照)。

Enumerable#each などと違い、on() メソッドが呼ばれた時点ではブロックは実行されません。
あくまで登録されるだけです。
parse が呼ばれた時に、コマンドラインにオプションが指定されていれば実行されます。

オプションの指定はコマンドの直後である必要はありません(上の例で、-b はオプションと
して認識されている)。ただし、環境変数 POSIXLY_CORRECT が定義してあると
この挙動は変更されます。

        env POSIXLY_CORRECT=1 ruby ./sample.rb -a foo bar -b baz
        # => true                               # -a はオプションと解釈
             ["foo", "bar", "-b", "baz"]        # -b は非オプションと解釈

parse! により、コマンドライン(ARGV)の解析を行います。
parse! では、ARGV からオプションが取り除かれます。
これを避けるには parse を使います。

        require 'optparse'
        opt = OptionParser.new

        opt.on('-a') {|v| p v }
        opt.on('-b') {|v| p v }

        # parse() の場合、ARGVは変更されない。
        # オプションを取り除いた結果は argv に設定される。
        argv = opt.parse(ARGV)

        p argv

定義していないオプションを指定すると例外 [[c:OptionParser::InvalidOption]] が
発生します。

        ruby ./sample.rb -c
        /usr/local/lib/ruby/1.9/optparse.rb:1428:in `complete': invalid option: -c (OptionParser::InvalidOption)
                from /usr/local/lib/ruby/1.9/optparse.rb:1426:in `catch'
                from /usr/local/lib/ruby/1.9/optparse.rb:1426:in `complete'
                from /usr/local/lib/ruby/1.9/optparse.rb:1287:in `order!'
                from /usr/local/lib/ruby/1.9/optparse.rb:1256:in `catch'
                from /usr/local/lib/ruby/1.9/optparse.rb:1256:in `order!'
                from /usr/local/lib/ruby/1.9/optparse.rb:1336:in `permute!'
                from /usr/local/lib/ruby/1.9/optparse.rb:1363:in `parse!'
                from /usr/local/lib/ruby/1.9/optparse.rb:1356:in `parse'
                from ./sample.rb:9

OptionParser 自体は、どのオプションが指定されたかを記憶しません。
後の処理の方で、オプションによる条件判断を加えるには、
他のコンテナに格納します。

        require 'optparse'
        opt = OptionParser.new

        OPTS = {}

        opt.on('-a') {|v| OPTS[:a] = v }
        opt.on('-b') {|v| OPTS[:b] = v }

        opt.parse!(ARGV)
        p ARGV
        p OPTS

        ruby sample.rb -a foo bar -b baz
        # => ["foo", "bar", "baz"]
             {:a=>true, :b=>true}

==== オプションの引数

on() メソッドのオプション定義で末尾に何かを書くと、そのオプション
は引数を受け付けることの指定となります。

        require 'optparse'
        opt = OptionParser.new

        opt.on('-a VAL') {|v| p v }         # <- " VAL" を追加
        opt.on('-b') {|v| p v }

        opt.parse!(ARGV)
        p ARGV

        ruby sample.rb -a foo bar -b baz

        # => "foo"
             true
             ["bar", "baz"]

オプションの末尾の書き方の基準は、「ヘルプの見栄えが良くなるように書く」です。
オプションの引数を省略すると例外 [[c:OptionParser::MissingArgument]] が発生します。

        ruby ./sample.rb -a
        /usr/local/lib/ruby/1.9/optparse.rb:455:in `parse': missing argument: -a (OptionParser::MissingArgument)
                from /usr/local/lib/ruby/1.9/optparse.rb:1295:in `order!'
                from /usr/local/lib/ruby/1.9/optparse.rb:1256:in `catch'
                from /usr/local/lib/ruby/1.9/optparse.rb:1256:in `order!'
                from /usr/local/lib/ruby/1.9/optparse.rb:1336:in `permute!'
                from /usr/local/lib/ruby/1.9/optparse.rb:1363:in `parse!'
                from ./sample.rb:7

オプションの引数が必須でないことを示すには、" [" を付けます。

        require 'optparse'
        opt = OptionParser.new

        opt.on('-a [VAL]') {|v| p v }          # <- [VAL] を追加
        opt.on('-b') {|v| p v }

        opt.parse!(ARGV)
        p ARGV

        ruby sample.rb -a

        # => nil
             []

同様に、ヘルプの見栄えが良いように "VAL]" を付加しています。

ショートオプションの引数指定は使いにくいので、このような場合はロング
オプションの方が使う方もわかりやすいです。例えば、上記の場合、-ab を
指定すると -a b と解釈されます。-a が引数を持たない最初の例なら -a -b と
解釈されます。

==== ロングオプション

ロングオプションは on() の引数に '--'で始まるオプションを指定します。

        require 'optparse'
        opt = OptionParser.new

        opt.on('-a', '--foo') {|v| p v }
        opt.on('--bar') {|v| p v }

        opt.parse!(ARGV)
        p ARGV

        ruby sample.rb -a foo bar --bar baz
        # => true
             true
             ["foo", "bar", "baz"]

--[no-]...などとすることで、否定型のオプションを指定することができます。

        require 'optparse'
        opt = OptionParser.new

        opt.on('-a', '--foo') {|v| p v }
        opt.on('--[no-]bar') {|v| p v }

        opt.parse!(ARGV)
        p ARGV

        ruby sample.rb -a foo bar --bar baz --no-bar
        # => true
             true
             false                              # <- --no-bar の指定による。
             ["foo", "bar", "baz"]

オプションに対する引数も指定できます。ショートオプションと同じだが、
GNUの慣習にあわせて

        opt.on('-a', '--foo=VAL') {|v| p v }
        opt.on('--[no-]bar[=VAL]') {|v| p v }

と "=" を使うのが良いと思われます。

オプションを指定する時は、どのオプションか一意に決まる長さまで指定す
れば良いです。

        require 'optparse'
        opt = OptionParser.new

        opt.on('-a', '--foo') {|v| p v }
        opt.on('--[no-]bar') {|v| p v }

        opt.parse!(ARGV)
        p ARGV

        ruby sample.rb --fo

この例では、--fo は、--foo を指定したのと同じになります。この例なら --f 
まで省略できます。

==== ヘルプ

デフォルトで --help と --version オプションを認識します。

        ruby ./sample.rb --help
        # => Usage: sample [options]

        ruby ./sample.rb --version
        # => *出力なし*

--version は、トップレベルに Version 定数が定義されていると出力されます。
(優先度は低いが VERSION 定数も参照します。Ruby のバージョンを示す VERSION
定数が ruby 1.8 までは定義されているので注意)

        require 'optparse'
        opt = OptionParser.new
        Version = "1.2.3"       # opt.version = "1.2.3"
        opt.parse!(ARGV)

        ruby ./sample.rb --version
        # => sample 1.2.3

on の引数にそのオプションの説明を加えると --help の出力に反映されます。

        require 'optparse'
        opt = OptionParser.new

        opt.on('-a', 'description of -a') {|v| p v }
        opt.on('-b', 'description of -b') {|v| p v }

        opt.parse!(ARGV)
        p ARGV
        
        ruby ./sample.rb --help
        # => Usage: sample [options]        
                -a                               description of -a
                -b                               description of -b


==== サブコマンド
以下は cvs や svn のようにサブコマンドを解釈する例です。
  
    #! /usr/bin/ruby
    # contributed by Minero Aoki.
    
    require 'optparse'
    
    parser = OptionParser.new
    parser.on('-i') { puts "-i" }
    parser.on('-o') { puts '-o' }
    
    subparsers = Hash.new {|h,k|
      $stderr.puts "no such subcommand: #{k}"
      exit 1
    }
    subparsers['add'] = OptionParser.new.on('-i') { puts "add -i" }
    subparsers['del'] = OptionParser.new.on('-i') { puts "del -i" }
    subparsers['list'] = OptionParser.new.on('-i') { puts "list -i" }
    
    parser.order!(ARGV)
    subparsers[ARGV.shift].parse!(ARGV) unless ARGV.empty?

実行すると以下のようになります。

    $ ruby subcom.rb -i add -i
    -i
    add -i
    
    $ ruby subcom.rb list -i
    list -i

[[m:OptionParser#order!]] がオプションではない
コマンドの引数に出会うとそこでパースを中断することを利用しています。

==== ARGV の機能
optparse を require すると ARGV に [[c:OptionParser::Arguable]] の機能
が加わります。以下の書き方ができるようになります。
[[c:OptionParser::Arguable#getopts]] はオプションを保持した Hash を返します。
  # sample.rb の内容
  require 'optparse'
  params = ARGV.getopts("a:b:", "foo", "bar:")
  p params
この sample.rb を実行すると
  $ ruby sample.rb -a 1 --foo --bar xxx
  {"a"=>"1", "b"=>nil, "foo"=>true, "bar"=>"xxx"}
のようになります。

==== '-'で始まるファイル名

'-'で始まるファイル名をコマンドに渡したい場合は以下のように間に"--"を挟みます。

      $ ruby sample.rb -- -file

"-file" がオプションではない引数として解釈されます。
これは POSIX.2 の getopt(3) に由来します。"--" 以降はすべてオプションではない引数として解釈されます。
