はじめに
Ruby初心者がオプション付きのプログラムをゼロから自前で実装する場合かなり大変です。そんな時に大活躍してくれるがのoptparseライブラリです。オプション解析を良い感じにやってくれます。
最初に知っておくと良いこと
- Rubyのoptparseは使用時にロードが必要なタイプの標準ライブラリで
require "optparse"
と書いてから使用します。 - optparseの記事をインタネットで調べた際、ARGVとう変数によく出くわします。しかしARGVはoptparseとは直接は関係ありません。ARGVはRubyの特別な変数でコマンドライン引数を格納する配列となります。
実例を使ってoptparseを理解しよう!
- 例として年と月を引数に取るカレンダープログラムを考えます。年のオプションを
-y
、月のオプションを-m
とします。
例えば2023年10月のカレンダーを表示するプログラムなら下記のように記述するとします。
ruby calendar.rb -y 2023 -m 10
calendar.rbを実行した際一体どのようにして 2023
や 10
といった情報を取得できるのでしょうか?optparseを使うと簡単に2023
や 10
といった情報を取得できます。
optparseの基本動作
- 最小限の構成からなるプログラムをつかって基本的な仕組みを理解しましょう。プログラムと実行例を以下に記載します。
ruby calendar.rb -y 2023 -m 10
require 'optparse'
opt = OptionParser.new
opt.on('-y') {|v| p v }
opt.on('-m') {|v| p v }
p ARGV # =>["-y", "2023", "-m", "10"]
opt.parse!(ARGV)
p ARGV # =>["2023", "10"]
p "#{ARGV[0]}年" # =>"2023年"
p "#{ARGV[1]}月" # =>"10月"
解説
require 'optparse'
optparseはRubyの組み込みライブラリではないのでこのように書いて使える状態にしてあげる必要があります。これがないと例えば次のOptionParserクラスを使うことができません。
opt = OptionParser.new
OptionParserクラスのnewメソッド使ってOptionParserクラスから作成されたインスタンスを作成。作成されたインスタンスをoptに格納しています。
opt.on('-y')
optのonメソッドの引数にオプションを指定します。ここでは、-y
オプションを指定してます。こうすることで、-y
がオプションとして認識されます。
{|v| p v }
コマンド引数に-y
が渡された時、仮引数vにtrueが格納されます。(それ以外はfalseが格納されます)
このブロックでは、例として仮引数の値を返す処理が記述されています。
parse!メソッドでARGVが解析された時にonメソッドで指定したオプションが含まれていたらブロックの中身が実行されます。ここでは処理内容が設定されているだけで実行はされません。
opt.on('-m')
説明省略
一つ目の p ARGV
ARGVはコマンドライン引数が配列の要素として格納されています。例を見てもわかるように-y
や-m
オプションも含め引数すべてが配列の要素として格納されています。
opt.parse!(ARGV)
optのparse!という破壊的メソッド使って配列ARGVを解析します。具体的にはonメソッドで指定した-y
や-m
オプションを除いた引数を要素した配列をARGVに格納します。
二つ目の p ARGV
-y
オプションが除かれ、2023
, 10
がARGVの要素として格納されています。
p "#{ARGV[0]}年"
p "#{ARGV[1]}月"
無事年と月を取得することができました。
上のプログラムの問題点
とりあえず、年と月を取得することができました。でもこのプログラムには問題があります。
それはruby calendar.rb -m 10 -y 2023
のようにオプションの順番を入れ替えて入力されてしまうと 10年2013月と表示されてしまうことです。どうすればよいのでしょうか?calendar.rbを次のように書き換えます。
require 'optparse'
opt = OptionParser.new
options = {} # 追加
opt.on('-y year') { |y| options[:year] = y } # 変更
opt.on('-m month') { |m| options[:month] = m } # 変更
p ARGV # =>["-m", "10", "-y", "2023"]
opt.parse!(ARGV)
p ARGV # =>[]
p "#{options[:year]}年" # 変更 =>"2023年"
p "#{options[:month]}月" # 変更 =>"10月"
解説
options = {}
空のハッシュを用意します。年と月の情報を管理する目的で使います。
opt.on('-y year') { |y| options[:year] = y }
onメソッドのオプション定義で末尾に何か(ここではyear
)を書くと、仮引数y
にはyear
で指定した引数が入るようになります。
例えばruby calendar.rb -y 2023
とした場合、仮引数y
には2023
が渡されます。
またさらにここでは後でこの値を参照できるようキー :year と値 2023 の組み合わせをoptionsハッシュに追加しています。
opt.on('-m month') { |m| options[:month] = m }
説明省略
p ARGV
onメソッドで指定した-y year
や-m month
オプションを除いた引数がARGVに格納されます。ruby calendar.rb -y 2023 -m 10
の場合は、-y 2023 -m 10
がオプションで指定された部分と解釈されるためARGVは最終的に空の配列となります。
(年月の情報はoptionsにて管理するため、この例でARGVは無用の長物です。)
p "#{options[:year]}年"
ハッシュにキー:yearを指定して2023を取得します。
p "#{options[:month]}月"
説明省略
以上で、ruby calendar.rb -y 2023 -m 10
と指定しても、
ruby calendar.rb -m 10 -y 2023
と指定しても無事同じ結果を得ることができるようになりました。