optparseについて

## optparseとは
Rubyでコマンドライン引数を扱うための標準ライブラリ。

例えば、test.rbというファイルを実行するとして`ruby test.rb -a 100`のようにコマンドライン引数で値を渡すことができる
`-a 100`の中身はファイル内で使用することができる

## 使い方
1. OptionParseオブジェクトoptを生成する
1. オプションを取り扱うブロックをoptに登録する
1. opt.parse(ARGV)でコマンドラインを実際にparseする

### 1.　OptionParseオブジェクトoptを生成する

```:sum.rb
require 'optparse'
opt = OptionParser.new
```
上記でoptparseライブラリを読み込み、変数optにOptionParseクラスから生成したインスタンスを格納している
このインスタンスに対して操作を加えることでオプション引数を扱えるようになる

### 2.　オプションを取り扱うブロックをoptに登録する

```ruby:sum.rb
require 'optparse'
opt = OptionParse.new

opt.on('-a') {|v| p v }
opt.on('-b') {|v| p v }
```
OptionParse#onメソッドの引数でオプション`-a`と`-b`を定義し、引数が指定されたときの処理をブロック内に記述する
ブロックの引数にはオプションが指定されたことを示すtrueが渡される
※ただし、この時点ではブロックは実行されない。実行されるのは、後述する`OptionParse#parse`が呼ばれたとき

### 3.　opt.parse(ARGV)でコマンドラインを実際にparseする

- デフォルトのオプションや変数を設定する
`OptionParser#parse!`を使い、コマンドラインの解析を行う
以下を追記して`ruby sum.rb -a 10 -b 20`を実行する
```sum.rb
require 'optparse'

#create opt object
opt = Optionparser.new

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

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

```:結果
["10", "20"]
```
コマンドラインの引数の値を取得することができた

ちなみに、`opt.parse(ARGV)`とすると値だけでなくオプションも取得することができる
```:結果
["-a", "10", "-b", "20"]
```

## オプションの記憶
`OptionParse`はどのオプションが指定されたのか記憶しない
そのため後で処理が必要なものはコンテナに格納する必要がある
```ruby:sample.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 ARGV
p params
```
↓ 実行結果
```
ruby sample.rb -a foo bar -b baz
# => ["foo", "bar", "baz"]
     {:a=>true, :b=>true}
```




## ロングオプションを定義する
例えば、ショートオプションだけでなくロングオプションを定義したい場合は`onメソッド`でオプションを定義するときにショートオプションと一緒にロングオプションとして渡したい値を指定する

以下のようにすることで、ショート、ロングバージョンどちらでもオプションを指定することができる
```:ロングオプション
require 'optparse'
opt = OptionParse.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
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
```
↓ 実行結果
```
$ 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"}
```

`Integer`クラスを指定すると、文字列が引数としてきたらエラーを返す
`String`クラスを指定すると数値を引数に渡した場合でも文字列として受け取る

## 便利なARGV機能
今までの方法でコマンドのオプションや引数を処理することができるが、もっと簡単に扱える`OptionParser::Arguable`モジュールの`getopts`メソッドがある
`getopts`モジュールを使用することで、ワンラインでコードでオプションと引数を指定することができ、受け取ったものをHashとして受け取ることができる

### 使い方
ショートオプション、またはロングオプションを指定することができる。引数が必要なオプションにはコロンをオプションの後ろにつける
オプションは`opt.on`のときと異なり、1つ1つ指定するのではなくまとめて記述するため`getopts`メソッド使うと簡単になる

```ruby:sample.rb
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"}
```
ロングオプションを使いたい場合も同様。ショートオプションが不要な場合は、`""`のように空文字を渡してあげる必要がある

:::note
ショートオプションのときのようにまとめてオプションは指定せず、分けて書く。
:::
```ruby:sampl.rb
require 'optparse'
# ショートオプションなし、ロングオプション引数なし or あり
params = ARGV.getopts("", "all", "before:")
p params
```
オプションのデフォルト値も指定することが可能
```ruby:sample.rb
require 'optparse'
# ショートオプションなし、ロングオプション引数あり、デフォルト値あり
params = ARGV.getopts("", "all", "before:", "maxsize:1024")
p params
```

## 参考文献
https://docs.ruby-lang.org/ja/latest/library/optparse.html#subcmd

https://akng-engineer.hatenablog.com/entry/2021/12/02/225959