要約
コマンドラインのオプションを取り扱うためのライブラリです。
チュートリアル
optparse を使う場合、基本的には
- OptionParser オブジェクト opt を生成する。
- オプションを取り扱うブロックを opt に登録する。
- 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"]
OptionParser#on メソッドの引数でオプションを定義し、引数が指定された時の処理をブロックで記述します。ブロックの引数にはオプションが指定されたことを示す true が渡されます(オプションの引数の項も参照)。
Enumerator#each などと違い、OptionParser#on メソッドが呼ばれた時点ではブロックは実行されません。あくまで登録されるだけです。OptionParser#parse が呼ばれた時に、コマンドラインにオプションが指定されていれば実行されます。
オプションの指定はコマンドの直後である必要はありません(上の例で、-b はオプションとして認識されている)。ただし、環境変数 POSIXLY_CORRECT が定義してあるとこの挙動は変更されます。
env POSIXLY_CORRECT=1 ruby ./sample.rb -a foo bar -b baz # => true # -a はオプションと解釈 ["foo", "bar", "-b", "baz"] # -b は非オプションと解釈
OptionParser#parse! により、コマンドライン(ARGV)の解析を行います。 OptionParser#parse! では、ARGV からオプションが取り除かれます。これを避けるには OptionParser#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
定義していないオプションを指定すると例外 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
params = {}
opt.on('-a') {|v| params[:a] = v }
opt.on('-b') {|v| params[:b] = v }
opt.parse!(ARGV)
p ARGV
p params
↓
ruby sample.rb -a foo bar -b baz # => ["foo", "bar", "baz"] {:a=>true, :b=>true}
明示的にコンテナへ格納する以外に、parse(及びparse!)メソッドの引数に :into オプションを指定することでハッシュへ自動的に値を格納することができます。この時ハッシュのキーとして利用される名前はロングオプションが定義されていればロングオプションの値を、ショートオプションのみの場合はショートオプションの値から、先頭の "-" を除いてシンボル化した値が使用されます。
require 'optparse'
opt = OptionParser.new
params = {}
opt.on('-a') {|v| v }
opt.on('-b', '--bbb') {|v| v }
opt.parse!(ARGV, into: params) # intoオプションにハッシュを渡す
p ARGV
p params
↓
ruby sample.rb -a foo bar -b baz # => ["foo", "bar", "baz"] {:a=>true, :bbb=>true}
オプションの引数
OptionParser#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"]
オプションの末尾の書き方の基準は、「ヘルプの見栄えが良くなるように書く」です。オプションの引数を省略すると例外 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 と解釈されます。
ロングオプション
ロングオプションは OptionParser#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
OptionParser#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
OptionParser#order! がオプションではないコマンドの引数に出会うとそこでパースを中断することを利用しています。
ARGV の機能
optparse を require すると ARGV に OptionParser::Arguable の機能が加わります。以下の書き方ができるようになります。 OptionParser::Arguable#getopts はオプションを保持した Hash を返します。
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) に由来します。"--" 以降はすべてオプションではない引数として解釈されます。
クラス
OptionParser | コマンドラインのオプションを取り扱うためのクラスです。 |
モジュール
OptionParser::Arguable | 主に Object::ARGV を拡張するために用意されたモジュールです。 optparse を require することにより、ARGV は OptionParser::Arguable を Object#extend します。 |
例外クラス
OptionParser::ParseError | OptionParser の例外クラスの基底クラスです。 |
OptionParser::AmbiguousArgument | オプションの引数が曖昧にしか補完できない場合に投げられます。 |
OptionParser::AmbiguousOption | 補完が曖昧にしかできないオプションがあった場合に投げられます。 |
OptionParser::InvalidArgument | オプションの引数が指定されたパターンにマッチしない時に投げられます。 |
OptionParser::InvalidOption | 定義されていないオプションが与えられた場合に投げられます。 |
OptionParser::MissingArgument | 引数が必要なオプションに引数が与えられなかった場合に投げられます。 |
OptionParser::NeedlessArgument | 引数を取らないはずのオプションに引数が与えられた場合に投げられます。 |
サブライブラリ
optparse/date | OptionParser#on で使用可能なクラスに Date と DateTime が追加されます。オプションの引数はそれぞれのクラスのインスタンスに変換されてから、 OptionParser#on のブロックに渡されます。 |
optparse/shellwords | OptionParser#on で使用可能な引数に Shellwords 追加されます。オプションの引数は Shellwords.#shellwords によって配列に変換されてから、 OptionParser#on のブロックに渡されます。 |
optparse/time | OptionParser#on で使用可能なクラスに Time が追加されます。オプションの引数は Time クラスのインスタンスに変換されてから、 OptionParser#on のブロックに渡されます。 |
optparse/uri | OptionParser#on で使用可能なクラスに URI が追加されます。オプションの引数は URI クラスのインスタンスに変換されてから、 OptionParser#on のブロックに渡されます。 |