Rubyのoptparseについて。

皆様こんにちは、Amiaです。

今回はタイトルにもある通りRubyの『optparseライブラリ』についてまとめていきたいと思います。
インプットしたら忘れないうちにアウトプット!!

よろしければ最後までご覧になっていただければと思います。

⚫︎optparseライブラリとは

Rubyの標準ライブラリの1つ。
コマンドラインのオプションを取り扱うためのライブラリ。
optparseライブラリを使う場合は、基本的に下記のステップで使用します。
optparserequireする。
OptionParserオブジェクトoptを生成する。
.onメソッドを用いてオプションを取り扱うブロックをoptに登録する。
.parseメソッドを用いて、与えられたARGVparse(パース)する。

⚫︎使い方について

Rubyのリファレンスに記載されているサンプルコードを使用して挙動を確認していきたいと思います。
sample.rb

require 'optparse'
opt = OptionParser.new

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

opt.parse!(ARGV)
p ARGV

実行結果

["-a", "foo", "bar", "-b", "baz"]
true
true
["foo", "bar", "baz"]

.onメソッドは、optオフジェクトに登録するオプションを定義しています。
ARGVにはコマンドラインで渡されたオプション、引数が配列として渡されます。parse(パース)することで引数だけ取り出すことができます。
ARGVからオプションを取り除く必要がない場合は、破壊的メソッドは使用せずにopt.parse(ARGV)とすれば良いです。

上記のsample.rbプログラムではオプションをa,bとして定義しましたが、ヘルプオプションと(h)はデフォルトで定義されています。

ruby sample.rb -h
["-h"]
Usage: sample [options]
    -a
    -b

⚫︎ロングオプションを定義

ショートオプションだけでなくロングオプションを定義したい場合は、.onメソッドでオプション定義する時にショートオプションと一緒にロングオプションとして渡したい値を指定します。
下記のように指定することでショート、ロングのどちらでもオプションを指定できるようになります。

require 'optparse'
opt = OptionParser.new

opt.on('-a', '--all') {|v| p v }
opt.on('-b', '--before') {|v| p v }
opt.parse(ARGV)
p ARGV
ruby sample.rb --all foo --before bar
true
true
["--all", "foo", "--before", "bar"]

またヘルプオプションについてもショート、ロングのどちらでも表示されていることがわかります。

ruby sample.rb -h
Usage: sample [options]
    -a, --all
    -b, --before

⚫︎オプションの説明を明記

ヘルプオプションでヘルプを表示した時に使用できるオプションだけでなく、そのオプションの説明を追加することができます。その場合はロングオプション同様に.onメソッドに説明文を渡します。

require 'optparse'
opt = OptionParser.new

opt.on('-a', '--all', 'description:a') {|v| p v }
opt.on('-b', '--before', 'description:b') {|v| p v }
opt.parse(ARGV)
p ARGV

ヘルプオプションを指定した時に説明文が表示されるようになります。

ruby sample.rb -h
Usage: sample [options]
    -a, --all                        description:a
    -b, --before                     description:b

⚫︎どのオプションが指定されたか記憶させる

OptionParser自体はどのオプションが指定されたかは記憶していません。そのためどのオプションがコマンドラインで渡されてきたか覚えさせておく必要がある場合は、コンテナに格納しておきます。

require 'optparse'
opt = OptionParser.new

option = {}
opt.on('-a', '--all', 'description:a') {|v| option[:a] = v }
opt.on('-b', '--before', 'description:b') {|v| option[:b] = v }
opt.parse(ARGV)
p ARGV
p option

オプションが指定された場合は、コンテナにkey,valueが保存されます。オプションが指定されなかった場合は、nilが返ります。

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

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

⚫︎オプションに引数が必須か否か指定する

  • 引数が必須の場合
    .onメソッドでオプションの末尾に文字列を追加します。
    ・下記例の例ですとVALを追加しています。

  • 引数が省略可能な場合
    .onメソッドでオプションの末尾に[]で囲った文字列を追加します。
    ・下記例ですと[VAL]を追加しています。

require 'optparse'
opt = OptionParser.new

option = {}
# 引数なし(通常)の記述
opt.on('-a', '--all', 'description:a') {|v| option[:a] = v }
# 引数必須の記述
opt.on('-b VAL', '--before', 'description:b') {|v| option[:b] = v }
# 引数必省略可能の記述
opt.on('-c [VAL]', '--ccc', 'description:c') {|v| option[:c] = v }
opt.parse!(ARGV)

引数必須な場合に引数を渡さないと下記のようなエラーが発生します。

ruby sample.rb -b
sample.rb:8:in `<main>': missing argument: -b (OptionParser::MissingArgument)

また、オプションと引数を一緒に渡すことで引数をそのままハッシュ(Hash)にkeyとvalueを格納できます。 引数なしのオプションには真偽値が返り、オプションb,cに引数を渡すと引数がハッシュに入ります。

ruby sample.rb -a -b test -c test
{:a=>true, :b=>"test", :c=>"test"}

⚫︎受け取る引数のクラスを指定する

あるオプションの引数で受け取るクラスを限定したい場合は、下記のように記述します。

require 'optparse'
opt = OptionParser.new

option = {}
# 引数はIntegerのみ
opt.on('-a', '--all=N', Integer, 'description:a') {|v| option[:a] = v }
# 引数はStringのみ
opt.on('-b', '--before=S', String, 'description:b') {|v| option[:b] = v }
opt.on('-c [VAL]', '--ccc', 'description:c') {|v| option[:c] = v }
opt.parse!(ARGV)
p option

Intergerクラスを指定すると、文字列が引数として渡った場合エラーを返します。また、Stringクラスを指定すると数値を引数に渡した場合でも文字列として受け取ります。

 ruby sample.rb -a 1 -b aaa
{:a=>1, :b=>"aaa"}

ruby sample.rb -a aaa
sample3.rb:7:in `<main>': invalid argument: -a aaa (OptionParser::InvalidArgument)

ruby sample.rb -b 1
{:b=>"1"}

⚫︎ARGVの機能

ARGVコマンドラインから渡された引数が配列として渡されます。
ARGVでオプションを定義することができます。
オプションの指定はOptionParser::Arguableモジュールのgetoptsメソッドでオプションを指定することができます。getoptsメソッド使うとワンラインでコードでオプションと引数を指定することができ、受け取ったものをハッシュとして受け取ることができます。

getoptsメソッドにはショートネームのオプション、またはロングネームのオプションを指定することができます。引数が必要なオプションにはコロンをオプションの後ろにつけます。オプションはopt.onの時と異なり1つ1つ指定するのではなくまとめて記述するため、オプションや引数をシンプルに扱うだけであればgetoptsメソッド使うと楽になります。

◎ショートネームのオプション

  • ショートネームのオプションを文字列で指定します。
  • オプションが引数を取る場合は直後に:を付けます。
    ・aという引数を取るオプションを追加する場合:a:
    ・aとbという引数を取るオプションを追加する場合:a:b:
    ・aという引数を取らないオプションとbという引数を取るオプションを追加する場合:ab:

◎ロングネームのオプション

  • ショートネームのオプションを文字列で指定します。
  • オプションが引数を取る場合は直後に:を付けます。
  • デフォルト値は:の直後に指定します。
    ・bufsizeという引数を取らないオプションを追加する場合:bufsize
    ・bufsizeという引数を取るオプションを追加する場合:bufsize:
    ・デフォルト値1024のbufsizeという引数を取るオプションを追加する場合:bufsize:1024
require 'optparse'

# 引数なしのオプションa, 引数ありのオプションbを指定
params = ARGV.getopts("ab:")
p params
ruby sample2.rb -h
Usage: sample2 [options]
    -a
    -b VAL

ruby sample2.rb -a -b bbb
{"a"=>true, "b"=>"bbb"}

ロングネームのオプションを使用したい場合も同様に引数が必要なオプションには:をオプションの後ろに付けます。ですが、ショートネームのオプションの時のようにまとめてオプションは指定せずに分けて書きます。ショートネームのオプションが不要な場合は、""のように空文字を渡してあげる必要があります。

require 'optparse'
# ショートオプションなし、ロングオプション引数なし or あり
params = ARGV.getopts("", "all", "before:")
p params
ruby sample2.rb -h
Usage: sample2 [options]
        --all
        --before=VAL

ruby sample2.rb --all --before 1
{"all"=>true, "before"=>"1"}

また、オプションのデフォルト値も指定することが可能です。

require 'optparse'
# ショートオプションなし、ロングオプション引数なし、ロングオプション引数あり、デフォルト値あり
params = ARGV.getopts("", "all", "before:", "maxsize:1024")
p params
ruby sample2.rb -h
Usage: sample2 [options]
        --all
        --before=VAL
        --maxsize=1024

ruby sample2.rb
{"all"=>false, "before"=>nil, "maxsize"=>"1024"}

デフォルト値はコマンド実行時に上書きすることも可能です。

ruby sample2.rb --maxsize=100
{"all"=>false, "before"=>nil, "maxsize"=>"100"}

⚫︎最後に

今回はRubyのoptparseについて学習する中で調べたことを簡単にですが記事としてまとめてみました。
Rubyもですがoptparseについてはまだまだ理解の浅い部分が多いため、復習したいと思います。

最後までご覧いただきありがとうございました。

⚫︎参考文献

docs.ruby-lang.org

docs.ruby-lang.org