意識の高いLISPマシン

藤原惟/すかいゆき(@sky_y)の技術用ブログ

Ruby: コマンドライン引数の解析で使うoptparseをもっと柔軟に

オプションの無い引数を扱いたい

Rubyコマンドライン引数を解析するときは、optparse (OptionParser) を使うと便利です。

library optparse


しかし、OptionParser#parse! は、"-a", "--long-option"みたいなオプションを使わない引数を扱う場合に不便です。

つまり、コマンドライン

$ ruby foo.rb -o file_output.txt file_input.html 

みたいなことをしようと思うと、RubyでOptionParserを使う前に

# ruby
opt = OptionParser.new
@option[:file] = ARGV.pop
# ...
opt.on('-o FILE','--output FILE','Output Filename') {|v| @option[:file_output] = v }
# ...
opt.parse!(ARGV)

みたいに、ARGV.popで引数を取り出す必要があります。


この場合、オプションの無い引数が必ず末尾に来ないといけないので、
かなり窮屈なコマンドインタフェースになります。

オプション無しの引数をもっと柔軟に扱う

それを解決する方法は、OptionParser#parse! を使うのではなく、OptionParser#permute! を使うことです。

instance method OptionParser#permute!

permute!(argv = self.default_argv) -> [String]
与えられた argv を破壊的にパースします。argv からオプションがすべて取り除かれます オプションではないコマンドの引数(下の例で言うと somefile)があってもパースを中断しません。 argv を返します。

下の例で言うと、order と違いコマンドの引数 somefile よりも後ろにオプションを置くことが できます。

例:

$ cat opt.rb
require 'optparse'
opt = OptionParser.new

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

opt.permute!(ARGV)
p ARGV

$ ruby opt2.rb -a foo somefile -b
:a
:b
["somefile"]


これを使うと、パース(permute)後のARGVにオプション無し引数が残ってくれるので、
ARGV.popでオプション無し引数を簡単に取り出せます。
(順番さえ守れば)オプション無し引数の位置も好きな位置に置けます。


例えば、以下のように、オプション付き引数(-o file_output.txt)の前に
オプション無しの引数(file_input.html)を与えることもできます。

$ ruby foo.rb file_input.html -o file_output.txt