This is IT

技術、日常

(Ruby)optparseの基本をまとめた

はじめに

library optparse (Ruby 3.1 リファレンスマニュアル)に記載してある

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

を理解するために、optparseの基本をまとめました。

  • opt.on('-X') { ブロック処理 }
  • ARGV
  • opt.parse(ARGV) / opt.parse!(ARGV)

の3点が分かれば土台的な部分の理解はOKだと思うので、これらについて記事を書きます。

間違っている部分がありましたら是非ご指摘ください。

opt.on('-X') { ブロック処理 }を理解する

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

引数をオプションとして登録します。 なお、この段階ではブロックの処理は行われません

longオプションや、help時に記載される説明も、ここのメソッドで定義することが出来ますが、あくまで「オプションの登録」と「ブロックは実行されない」ことを意識していればOKだと思います。

ブロックの処理は、後述する opt.parse(ARGV) / opt.parse!(ARGV)で実行されます。

ARGVを理解する

ARGVには、スクリプト実行時に利用したオプションと、その引数を文字列要素として格納した配列が代入されています。

実際に簡単なコードを書いて確認してみたいと思います。

# opt.rb

require 'optparse'
opt = OptionParser.new

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

p ARGV
# 実行結果

❯ ruby opt.rb -a foo -b bar hoge
["-a", "foo", "-b", "bar", "hoge"]

opt.rbという名前のRubyスクリプトに、

  • オプション: -a, -b
  • 引数: (-a) foo, (-b) bar hoge

を渡して、最後にARGVを表示させる処理を書いてみたところ、このような実行結果になりました。

このことから、オプション・引数を文字列とした要素を持つ配列がARGVに代入されていることが確認できます。

opt.parse(ARGV) / opt.parse!(ARGV)を理解する

OptionParseクラスのparseメソッドは、ARGVから、オプションの要素を取り除いたものを戻り値とするメソッドとなります。 また、opt.onのブロックの実行も行います。

こちらも実行結果を確認したいと思います。

# opt.rb

require 'optparse'
opt = OptionParser.new

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

parse = opt.parse(ARGV)

p parse
# 実行結果

❯ ruby opt.rb -a foo -b bar hoge
true
true
["foo", "bar", "hoge"]

実行結果を見ると、trueという表示が2行続けて並んでいます。これが、opt.onメソッドのブロック内の処理となります。 parseメソッドを呼び出したタイミングで、ブロックの処理が行われていることが分かります。

また、戻り値を確認するためのp parseの結果を見ると、ARGVからオプションの要素のみが取り除かれた配列が表示されています。

parse!の場合

破壊的なメソッドになります。 そのため、ARGVからもオプションの要素を除外してしまいます。

# parse!に変え、ARGVを見てみる

parse = opt.parse!(ARGV)

p ARGV
# 実行結果

❯ ruby opt.rb -a foo -b bar hoge
true
true
["foo", "bar", "hoge"]

ARGVには本来、オプションも引数も両方格納されているはずですが、parse!の破壊的メソッドによってオプションが取り除かれていることが分かります。

なぜtrueという表示をするのか?

もう一度ここで、opt.onメソッドのブロックを見てみます。

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

実はブロックパラメータには、オプションを使用したか否かのBooleanオブジェクトが渡されています。 今回は、-a -b共にオプションとして指定していたため、どちらもtrueが各パラメータに渡されています。

そのため、一方のオプションを指定しないと、下記のように指定した方のtrueのみが表示されます。

❯ ruby opt.rb -a
true

結合したオプション(-ab-alrなど)の場合

# opt.rb

require 'optparse'
opt = OptionParser.new

opt.on('-a') {|va| p va}
opt.on('-b') {|vb| p vb}
opt.on('-c') {|vc| p vc}

opt.parse(ARGV)
# 実行結果

❯ ruby opt.rb -abc
true
true
true

御覧の通り、オプションを-abcと連結して渡しても、各ブロックパラメータにはtrueが渡されています。 連結しても、バラバラで書いてもしっかりとオプションは渡せるようです。

最後に

オプションの理解が浅かったため、基本的な部分をまとめました。 リファレンスだけでは把握するのは難しいため、実験的に色々自分で実行してみるのが一番良いですね。