trollopでコマンドラインオプションをparseする


CLI で動作するアプリを書くときは、たいていコマンドラインから与えられた引数を相手にすることになる。その度に自前でARGVときゃっきゃうふふするロジックを書いてもいいが、手軽で使いやすいライブラリがあるので使ってみるのもいいだろう。

ということで今回はrubygemsから「trollop」のご紹介。今のプロジェクトでも「なぜもっと早く入れなかったか」と悔やみたくなるお得なライブラリである。

導入

gem install trollop

以上。この記事の時点では1.16.2がインストールされた。

このライブラリは1ファイルかつ他に依存もしていないので、直接ダウンロードしてloadpathの通ったところに配置してもいい。最近はbundlerのおかげでgemの整理に気を使う必要は減っているけど。

使ってみる:初級編

いちばんかんたんな使い方

Trollop.optionにブロックを渡すとハッシュが返ってくる。ブロックの中ではoptメソッドでパラメータの名前、型、デフォルト値などを指定する。

# trollop_simple0.rb
require 'trollop'
opts = Trollop::options do
  opt :foo,  'option foo'
  opt :bar,  'option bar',  :default => true
  opt :hoge, 'optioh hoge', :default => 2
  opt :fuga, 'option fuga', :type    => :float
  opt :piyo, 'option piyo', :default => '3'
end
p opts
オプションを与えない
% ruby trollop_simple0.rb
{:foo=>false, :bar=>true, :hoge=>2, :fuga=>nil, :piyo=>"3", :moge=>nil, :help=>false}
boolean型
% ruby trollop_simple0.rb --foo 'foo' --bar true
{:foo=>true, :bar=>false, (snip) :foo_given=>true, :bar_given=>true}

ここでひとつ注意したいポイント。booleanのオプションには何を渡しても、もしくは渡さなくても、「指定していなければデフォルト値 / 指定していれば not デフォルト値」が返ってくる。例えば…

% ruby trollop_simple0.rb --foo --bar true
{:foo=>true, :bar=>false, (snip) :foo_given=>true, :bar_given=>true}

パラメータを渡してないけどfooはtrue、「true」を渡してるのにbarはfalse、という挙動をする。ちょっと気になったのでソースをチェック。

# trollop.rb line 369〜
case opts[:type]
when :flag
  vals[sym] = !opts[:default]

さもありなん。

ほかの型

あとはだいたい予想通りの挙動をする。float / intはparseできなければエラーを返す。

% ruby trollop_simple0.rb --hoge integer
Error: option '--hoge' needs an integer.
Try --help for help.
% ruby trollop_simple0.rb --fuga 2
{ (snip) :fuga=>2.0, (snip) :help=>false, :fuga_given=>true}
% ruby trollop_simple0.rb --piyo abc --moge '1 2 3'
{ (snip) :piyo=>"abc", :moge=>"1 2 3", :help=>false, :piyo_given=>true, :moge_given=>true}
指定できる型

トップページに表示はなかったのでソースから。

# trollop.rb
opts[:type] = # normalize
case opts[:type]
when :boolean, :bool; :flag
when :integer; :int
when :integers; :ints
when :double; :float
when :doubles; :floats
when Class
case opts[:type].name
when 'TrueClass', 'FalseClass'; :flag
when 'String'; :string
when 'Integer'; :int
when 'Float'; :float
when 'IO'; :io
when 'Date'; :date
パラメータが与えられたかどうか

例示にちょこちょこ出ている通り、パラメータが与えられると、その名前に「_given」というサフィックスがついたboolean値が設定される。

パラメータの名前

optメソッドの第1引数(を文字列化したもの)がパラメータ名になる。アンダースコアを含む場合、ハイフンに変換される。

また、:long / :shortオプションで指定した文字列がパラメータ名となる。この場合、アンダースコアはそのまま。

# trollop_simple1.rb
require 'trollop'
opts = Trollop::options do
  opt :foo_bar,   'name with underscore', :default => 'foo'
  opt :hoge_piyo, 'with long / short option', :long => 'hogehoge_piyopiyo', :short => 'p'
end
p opts
% ruby trollop_simple1.rb --help
Options:
--foo-bar, -f <s>:   name with underscore (default: foo)
--hogehoge_piyopiyo, -p:   with long / short option
--help, -h:   Show this message

:shortを指定しないと、短いオプションは自動生成される。先頭から他との衝突をチェックし、使える文字列がなければ設定しない。

# trollop_simple2.rb
require 'trollop'
opts = Trollop::options do
  opt :abc, 'one'
  opt :ab,  'two'
  opt :a,   'thrree'
end
p opts
% ruby trollop_simple2.rb --help
Options:
--abc, -a:   one
--ab, -b:   two
--a:   thrree
--help, -h:   Show this message

:shortを明示するとそちらが優先される。

# trollop_simple3.rb
require 'trollop'
opts = Trollop::options do
  opt :abc, 'one'
  opt :ab,  'two'
  opt :a,   'thrree', :short => 'a'
end
p opts
% ruby trollop_simple3.rb --help
Options:
--abc, -b:   one
--ab:   two
--a, -a:   thrree
--help, -h:   Show this message

指定が重なった場合はArgumentErrorがraiseされる(例示略)。

複数の値 / 複数回指定

パラメータの型を指定するとき、末尾に「s」をつけることで複数の値を受け取ることができる。ハッシュには配列として格納される。また、:multiにtrueをつけると複数回指定できる。併用もできる。

# trollop_simple4.rb
require 'trollop'
opts = Trollop::options do
  opt :numbers,  'integer multi-values',                          :type => :ints
  opt :messages, 'string multi-time',             :multi => true, :type => :string
  opt :values,   'float multi-time, multi-value', :multi => true, :type => :floats
end
p opts
% ruby trollop_simple4.rb --numbers 1 2 --messages hoge --messages piyo --values 1.0 2.0 --values 3.0
{:numbers=>[1, 2], :messages=>["hoge", "piyo"], :values=>[[1.0, 2.0], [3.0]], :help=>false, :numbers_given=>true, :messages_given=>true, :values_given=>true}
versionとbanner

versionメソッドで、--version / -vオプションを指定したときの表示を指定できる。

bannerメソッドで、実行のたびに表示されるテキストを指定できる。

# trollop_simple5.rb
require 'trollop'
opts = Trollop::options do
  version 'TrollopSimpleSample 0.0.1'
  banner  'this string will be shown every execute.'
  opt :hoge, 'short option [-h] is overridden.'
end
p opts
% ruby trollop_simple5.rb --version
TrollopSimpleSample 0.0.1
% ruby trollop_simple5.rb --help
this string will be shown every execute.
--hoge, -h:   short option [-h] is overridden.
--version, -v:   Print version and exit
--help, -e:   Show this message

「:hoge」を指定したので「--help」のshort optionが「-e」になっているのにも注目。

まとめ

初級編でもずいぶん長くなってしまったのでこの辺で。そのうち続きを書きたいと思うので、TODOをメモっておく。

TODO
  • パラメータの型
    …:io、:dateを試していない
  • 中級編
    …バージョン表記とbanner(usage表示)

  • サブコマンド
    …svnやgitのようにサブコマンドを取る
  • カスタムパーザ
    …パーザの挙動をカスタマイズできる
おまけ

trollopを辞書で引くと「えっ」と思うような意味が出てくる。自分で作ったライブラリにすごい名前をつけるもんだな…と思ってFAQを見ると、理由がちゃんと書いてある。その他にもFAQは結構ワルノリしていて愉快なので、頑張って読んでみると面白い。

Links

Trollop
http://trollop.rubyforge.org/

FAQ
http://trollop.rubyforge.org/FAQ.txt

eitoballの練習帳: Trollop
http://eitoball.blogspot.com/2009/10/trollop.html

Leave a comment

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください