Rubyのoptparseについて(初学者向け)


Rubyを学習する中で、optparseを活用する機会があったため、こちらの内容について学習したことをまとめます。
私はRuby初学者でまだまだ学習中です。
optparseの公式ドキュメントを参照したのですが、前提知識が抜けているが故に難しく感じる部分もありました。

本記事では基本的な部分からoptparseについて解説したいと思います。

# optparseの概要

- optparseはRubyの標準ライブラリの一つです。
- rubyのプログラムを実行するときに、例えば`-a [引数]`など、コマンドラインのオプションの対応を行うことができます。
- コマンドラインのオプションのように、引数を渡すことができるようになります。

# (前提知識)　ARGVとは？

rubyでoptparseを初めて使用するにあたって[公式ドキュメント](https://docs.ruby-lang.org/ja/latest/library/optparse.html)を参照しました。
ここで登場する「`ARGV`」という用語についてよくわかっていなかったので、まずはこの部分から解説します。

- `ARGV`はRubyで最初からObjectクラスに定義されている**組み込み定数**の一つです。
通常であれば未定義の変数はエラーが起きますが、`ARGV`はとりあえず呼び出すと空配列が出力されます。


```Ruby:test.rb
p ARGV
```

```Ruby:実行結果
[]
```

- `ARGV`はrubyコマンドの起動時引数を配列として取得することができます。
引数を複数指定した場合は記述順に配列として格納されます。


```Ruby:test.rb
p ARGV
p "name : #{ARGV[0]}"
p "age : #{ARGV[1]}"
```

```:実行例
$ ruby test.rb Alice 20
```

```:実行結果
["Alice", "20"]
"name : Alice"
"age : 20"
```

- ちなみにARGVは**argument vector(引数の配列)** の略です。
Ruby以外に、pythonやC言語でも同じような用途で使用されています。



以上のように、`ARGV`を活用することで、Ruby実行時にオプション引数を変数として渡すことができます。

しかし、このままではコマンドラインのようにオプションを指定して引数を渡すことはできないですね。
`ARGV`だけでは、例えば`-a`などのオプションを指定するコマンドも引数として扱われてしまいます。

そこで活用するのが**optparse**です。


# optparseの一番基本的な使い方

optparseを活用したオプション受付の最もシンプルなサンプルコードは以下の通りです。

```Ruby:test.rb
require 'optparse'
opt = OptionParser.new

opt.on('-a')
opt.on('-b')

opt.parse!(ARGV)
p ARGV
```

`-a`,`-b`のオプションと引数を指定して上記コードを実行すると、ARGVにオプション引数が配列として代入されます。

```:実行例
$ ruby test.rb -a hoge -b fuga
```

```:実行結果
["hoge", "fuga"]
```

`-c`など、設定していないオプションが指定された場合はエラーになります。

```:実行例
$ ruby test.rb -a hoge -c fuga
```

```:実行結果
test.rb:7:in `<main>': invalid option: -c (OptionParser::InvalidOption)
test.rb:7:in `<main>': invalid option: c (OptionParser::InvalidOption)
```

コードについて簡単に解説します。

`OptionParser`の`.on`メソッドの引数でオプションを定義し、引数が指定された時の処理をブロックに記述します。(今回はブロックを用意してません)

また、`.parse!`でコマンドラインの解析を行い、`ARGV`からオプション(今回は`-a`,`-b`)が取り除かれます。　この変更は破壊的に行われます。

以上が最もシンプルなoptparseの使用方法です。

# オプションの指定有無を判定する

OptionParserだけではオプションが指定されたか記憶はしていません。
オプションの指定有無を判別するためには、`.on`メソッドのブロックで変数(ハッシュ)に代入します。

```Ruby:test.rb
require 'optparse'
opt = OptionParser.new

params = {}

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

opt.parse!(ARGV)
p params[:a]

if params[:a]
  # オプション-aが指定された時の処理
end
```

```:実行例
$ ruby test.rb -a hoge
```

```:実行結果
true
```

# オプションの引数を変数に代入、引数の必須/任意を設定

上記のコードは、オプションの引数自体はARGVの配列に格納されています。
引数を任意の変数に代入するには`.on('-a VAL')` のように`-a`(オプション)の後に引数名を指定します。
このように記述することでハッシュに渡す値が引数になります。

これを指定した場合、**引数の入力が必須**となります。
引数を指定せず実行数とエラーが発生します。

引数の入力を任意としたい場合は、`.on('-b [VAL]')`のように、引数名を`[]`で囲みます。

```Ruby:test.rb
require 'optparse'
opt = OptionParser.new

params = {}

opt.on('-a') {|v| params[:a] = v } # 引数なし
opt.on('-b VAL') {|v| params[:b] = v } # 引数の指定必須
opt.on('-c [VAL]') {|v| params[:c] = v } # 引数の指定任意

opt.parse!(ARGV)

p params[:a]
p params[:b]
p params[:c]

```

```:実行例
$ ruby test.rb -a hoge -b fuga -c piyo
```

```:実行結果
true
"fuga"
"piyo"
```

上記のように引数を変数に代入することができました。


# ロングオプションを設定する

コマンドラインのオプションにはロングオプションが指定されていることも多いです。
`.on`メソッドで、カンマ区切りでオプションを複数指定することで、ロングオプションを設定することができます。

```Ruby:test.rb

require 'optparse'
opt = OptionParser.new

params = {}

opt.on('-a','--foo') {|v| params[:a] = v }
opt.on('-b','--bar') {|v| params[:b] = v } 

opt.parse!(ARGV)

p params[:a]
p params[:b]

```

```:実行例
$ ruby test.rb -a hoge --bar fuga
```

```:実行結果
true
true
```

上記のように、通常のオプションとロングオプション、両方に対応させることができました。


# まとめ

以上、optparseの基本的な使い方の解説でした。
Rubyでコマンドラインのオプション対応させたい時に活用しましょう。

参考：[Rubyリファレンスマニュアル(optparse)](https://docs.ruby-lang.org/ja/latest/library/optparse.html)