ClassX::Commandableで簡単CLIアプリ
東京Ruby会議の懇親会で一番反響が良かったのはClassX::Commandableだったということでブログでもあたらめて紹介しておく。
MooseにはMooseX::GetoptとかMooseX::App::Cmdという便利なモジュールがあったのでMooseX::GetoptをパクってClassX::Commandableというのを作ったという話。
require 'classx' $ClassXCommandableMappingOf[Symbol] = String class YourApp include ClassX extend ClassX::Commandable has :arg1, :kind_of => Symbol, :desc => 'please specify arg1', :coerce => { String => proc {|val| val.to_sym } } has :arg2, :kind_of => Integer, :desc => "this is arg2", :optional => true def run # do something!! p attribute_of end end if $0 == __FILE__ YourApp.from_argv.run end
↑のように書いて実行すると、
yoshimi% ruby example/commandable.rb [ ~/Sources/ruby/classx ] example/commandable.rb [options] -a, --arg1 String please specify arg1 --arg2 [Integer] this is arg2 -h, --help show this document
のようにヘルプが出てくる。
ヘルプに書いてあるようにこのプログラムを実行するためには--arg1は必須。
yoshimi% ruby example/commandable.rb -a hoge [ ~/Sources/ruby/classx ] {"arg1"=><#ClassX::Attribute {:kind_of=>Symbol, :coerce=>{String=>#<Proc:0x00363300@example/commandable.rb:13>}, :desc=>"please specify arg1"}:1662200 @data=:hoge >, "arg2"=><#ClassX::Attribute {:kind_of=>Integer, :desc=>"this is arg2", :optional=>true}:1662120 >}
のように指定すると実行される。
yoshimi% ruby example/commandable.rb -a hoge --arg2 fuga [ ~/Sources/ruby/classx ] example/commandable.rb [options] -a, --arg1 String please specify arg1 --arg2 [Integer] this is arg2 -h, --help show this document
マニュアルによると --arg2はIntegerだが、文字列を指定しているのでヘルプが出る。
yoshimi% ruby example/commandable.rb -a hoge --arg2 10 [ ~/Sources/ruby/classx ] {"arg1"=><#ClassX::Attribute {:kind_of=>Symbol, :coerce=>{String=>#<Proc:0x00363684@example/commandable.rb:13>}, :desc=>"please specify arg1"}:1662280 @data=:hoge >, "arg2"=><#ClassX::Attribute {:kind_of=>Integer, :desc=>"this is arg2", :optional=>true}:1662200 @data=10 >}
こんどはちゃんと数字を指定しているのでおk
ところでarg1の定義のところで
has :arg1, :kind_of => Symbol, :desc => 'please specify arg1', :coerce => { String => proc {|val| val.to_sym } }
Symbolと指定しているのにどうやって変換しているかというと、
まずこのattributeにcoerceオプションを渡してStringで引数を渡した場合にSymbolに変換できるようにしておく。
そのあと、
$ClassXCommandableMappingOf[Symbol] = String
のように$ClassXCommandableMappingOfというグローバル変数にattributeの型名がSymbolの場合はコマンドラインでは文字列を取るように指定してあげる。
これで文字列で受けとる → Symbolで変換 というのを実現している。
グローバル変数というのがどうなのかなと思いつつもっといい仕様があれば教えていただけると嬉しいです。
ちなみにショートオプションは会議後に角谷さんから「ショートオプションサポートしてほしい」といわれてつけたのでHEADにしか入ってないです。
さきほど0.0.3をリリースしたのでそれに入っています。