勉強中!Rubyのoptparseライブラリについて!

はじめに

こんにちは!Akira(彰)です!
今日はRubyのoptparseライブラリについて基本的な使い方をまとめていきたいと思います!
本記事ではlibrary optparse 公式リファレンスを元に

  1. optparseで何ができるのか
  2. optparseの大まかな書き方
  3. parseメソッドの取り扱い
  4. 実際にどのように使うのか

に分けて書いていこうと思います。

optparseで何ができる?

optparseを使うとコマンドラインでオプションを使い値を受け取ることができます。 例えばrbファイルを実行する際に ruby ファイル名.rb -a xx と書いた場合、-a の部分がオプション名、 xx の部分がオプションに対する値です。
このようにoptparseを使うとオプションの内容によって振る舞いを変えるというコードが書けます。

optparseの大まかな書き方

何ができるのかが分かったところで、どのように書いてコード内でどのように値を取り出すのかについて書いていきます。
下記のコードはオプション -a を作成し、オプションを使って入力された値をARGVに格納するといったコードになります。

require 'optparse'

opt = OptionParser.new

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

opt.parse!(ARGV)

p ARGV

実際にオプション付きで実行してみると

ruby ファイル名.rb -a b
true  # コマンドラインにオプション(-a)が付いているとtrueが返る
["b"] # オプション(-a)で入力した b が出力されている

上のようになると思います。 この時、気を付けなければならないのはOptionParser#onメソッドが呼ばれた時点ではブロックはまだ実行されていないということです。
ではどのタイミングでブロックが実行されているのかというと、OptionParser#parseメソッドが呼ばれたタイミングです。
下記のようなコードを実行するとそのことが確認できると思います。

require 'optparse'

opt = OptionParser.new

opt.on('-a') { p ARGV }

opt.parse!(ARGV)

このコードはOptionParser#onメソッドのブロックに ARGV を表示するように記述しています。
onメソッドが呼び出されたタイミングでブロックが実行されているのであれば、ARGVの中身は空のはずなので表示は空の配列が返るはずです。
ですが、実行すると下記のような結果になります。

ruby ファイル名.rb -a b
["b"]

このことからonメソッドのタイミングではブロックは呼び出されておらず、parseメソッドの呼び出し時にブロックが実行されているということがわかると思います。

parseメソッドの取り扱い

上記で扱ったコードではOptionParser#parse!メソッドを使っています。その理由は ! の付いていないparseメソッドはARGVにオプション自身も含まれる & ARGVを破壊的に変更しないためです。

メソッド名 振る舞い
parse ARGVにはオプションと値の両方が解析され、ARGV自体は変更されない
parse! ARGVからオプションが取り除かれ、ARGV自体が変更される(破壊的)

OptionParser自体はどのオプションが指定されたのかを記憶していないため、オプションによる条件分岐を実装する際にはハッシュなどに情報を持たせておく必要があります。

require 'optparse'

opt = OptionParser.new

# ここで定義したハッシュに情報を持たせる
opt_params = {}

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

opt.parse!(ARGV)

p ARGV
p opt_params

このコードをオプション付きで実行すると以下のように出力されます。

ruby ファイル名.rb -a xx -b yy
["xx", "yy"]
{:a=>true, :b=>true} # ハッシュに持たせた情報が出力される

このようにハッシュに情報を持たせるとその情報を用いて分岐処理などを書くことができます。
ですがオプションが多数ある場合、何度もonメソッドにハッシュに値を持たせる処理を記述しなければなりません。
これを簡略化するにはparseメソッドに :into を付けることで自動的にハッシュに値を格納できます。
ハッシュのキーはロングオプション( "--" )で定義されていればロングオプションの値を、ショートオプションのみの場合はショートオプションの値から( "-" )を取り除いた値が使用されます。

require 'optparse'

opt = OptionParser.new

opt_params = {}

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

opt.parse!(ARGV, into: opt_params)

p ARGV
p opt_params

これがparseメソッドに:intoを付けたバージョンです。出力例は↓です。

ruby ファイル名.rb -a xx -b yy
["xx", "yy"]
{:a=>true, :bbb=>true} # ":a"がショートオプションのキー、":bbb"がロングオプションのキー

このように、parseメソッドに :into を記述することで書くonメソッドに処理を書かなくても自動で値を格納してくれるようになります。

そして、下記のコードのようにonメソッドの引数に VAL を付けることでオプションで受け取った値を :into の指定先に格納することもできます。

require 'optparse'

opt = OptionParser.new

opt_params = {}

opt.on('-a VAL') { |v| v }
opt.on('--bbb VAL') { |v| v }

opt.parse!(ARGV, into: opt_params)

p opt_params

上記のコードの出力例↓

ruby ファイル名.rb -a xx --bbb yyy
{:a=>"xx", :bbb=>"yyy"} # オプションで渡した値が表示される

実際の使用例

それでは今まで書いたことを参考に

  1. オプションの有無をハッシュで受け取る
  2. オプションの有無で条件分岐し、出力を変える
  3. 出力先でオプションで受け取った値を使う

ができるコードを書いてみました。

require 'optparse'

opt = OptionParser.new

opt_params = {}

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

opt.parse!(ARGV, into: opt_params)

# オプションのハッシュキー[:a]で取り出した値がtrueならオプションで入力した値出力に分岐
if opt_params[:a]
  puts "オプションが入力された処理#{ARGV}"

# オプションが未入力の場合、未入力用の処理へ分岐
else
  puts 'オプションが未入力の処理'
end

そしてonメソッドに VAL メソッドを付けることで下記のように条件分岐なしで書くこともできます。

require 'optparse'

opt = OptionParser.new

opt_params = {}

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

opt.parse!(ARGV, into: opt_params)

# opt_params[:a] が真であれば option に代入され、空であれば空の処理が代入される
option = opt_params[:a] || 'オプションが未入力の処理'

puts option

こうすると条件分岐を書かなくとも opt_params[:a] が空かどうかで代入する内容を変えられます。
今回のコードは最低限で小規模なものですが、何となくoptparseを使用してコードを書く流れが分かったかなと思います。

おわりに

以上でoptparseの基本的な使い方は以上になります!
とはいえ、公式リファレンスにはまだ当記事で紹介しきれていない情報があるので(help等)必要な際には適宜読んでみるのがいいと思います。
それではここまで読んでいただきありがとうございました!