LoginSignup
10
2

More than 3 years have passed since last update.

thorでオプションを定義する6つの方法

Posted at

Rubyでcliを作るときに定番のgem thorではコマンドのオプション(--key value みたいなやつ)を定義するときにmethod_optionを利用する.
しかし,いくつかのブログやドキュメント等を参照すると他にもいくつかの方法がある.
この違いがよくわからなかったのでいろいろ確認した.

オプション定義方法を解説する2種類のドキュメント

thorのドキュメントとしては,GitHub wiki公式webサイトの2種類存在する.

GitHub wikiでは method_optionmethod_options で定義する方法が紹介されている.
こちらのwikiには option / options を用いて定義する方法については触れられていない.

Thor allows you to specify options for its tasks, using method_options to supply a hash of options, or method_option to provide more detail about an individual option.

GitHub/wiki記載のサンプル
method_option :value, :default => "some value"
#=> Creates a string option with a default value of "some value"

一方で,公式webサイトでは Options and Flags の章にて optionoptions を用いて定義する方法が紹介されている.
こちらのドキュメントには method_option / method_options を用いて定義する方法については触れられていない.

Thor makes it easy to specify options and flags as metadata about a Thor command:

公式webサイト記載のサンプル
class MyCLI < Thor
  desc "hello NAME", "say hello to NAME"
  option :from
  def hello(name)
    puts "from: #{options[:from]}" if options[:from]
    puts "Hello #{name}"
  end
end

なお method_optionsmethod_option の違いについて GitHub wiki には,
method_option は個別のオプションに対してより詳細な項目を定義するために利用すると説明がある.
optionsoption の違いについて公式webサイトには,
options は複数の option を一度に定義できると説明がある.
上記の説明では, method_optionmethod_options の関係は optionsoption の関係とは異なるように読める.

You can use a shorthand to specify a number of options at once if you just want to specify the type of the options.

また,公式webサイトには上記に加えて Class Options の章で class_option という別の方法が記載されている.
class_option はGitHub wikiでは説明はなく,GeneratorsGroupsで参照されているだけだった.
ただし,公式webサイトでは触れられていない class_options も参照されている.

You can specify an option that should exist for the entire class by using class_option. Class options take exactly the same parameters as options for individual commands, but apply across all commands for a class.

公式webサイト記載のclass_optionサンプル
class MyCLI < Thor
  class_option :verbose, :type => :boolean

  desc "hello NAME", "say hello to NAME"
  options :from => :required, :yell => :boolean
  def hello(name)
    puts "> saying hello" if options[:verbose]
    output = []
    output << "from: #{options[:from]}" if options[:from]
    output << "Hello #{name}"
    output = output.join("\n")
    puts options[:yell] ? output.upcase : output
    puts "> done saying hello" if options[:verbose]
  end

  desc "goodbye", "say goodbye to the world"
  def goodbye
    puts "> saying goodbye" if options[:verbose]
    puts "Goodbye World"
    puts "> done saying goodbye" if options[:verbose]
  end
end

使い分け

method_options と options

この疑問についてはまさに同じ内容のissueが報告されている.
参考: Difference between method_options and options #596

結論としてはどちらも同じ.GitHub wikiは内容が古くなっているということ.
実際,GitHub wikiには内容が古くなっているので公式wbサイトを参照してくれと注意書きがある

NOTE: a good part of the documentation here is outdated, see the website instead: http://whatisthor.com

実装を見ても, method_optionsで実装されて options でエイリアスが張られている
同様に, method_option で実装されて optionでエイリアスが張られてもいる

lib/thor.rb#128
alias_method :options, :method_options
lib/thor.rb#165
alias_method :option, :method_option

method_options と method_option

一方で, method_optionsmethod_option (および optionsoption)の違いについて,
単に method_options は複数の method_option を同時に指定できるというだけでなく,
method_option でしか定義できない詳細オプションがある様子.
すなわち GitHub wikiが正しい (公式webサイトの記載を自分が読み違えている?).

具体的には,method_options では :required, :type, :default, :aliases の4つしか指定できない.
これはmethod_optionsを指定したときの処理の実装上,この4つしか対応していないように読める.
その他の指定可能な項目として,公式webサイトでは :desc, :banner を,
GitHub wikiでは上記に加えて :lazy_default, :enum を,
オプション項目の生成処理の実装を見ると上記に加えて :hide
それぞれ指定可能のように見える.

method_options と class_options

class_options および class_option は説明の通り,指定したクラスに定義されたコマンドすべてに適用される.
利用可能な項目は method_options および method_option と等しい.

なお,class_option実装のコメントを見ると lazy_default の記載がない.
しかし実際には class_optionmethod_option も共通の build_optionで生成しているので
おそらく laze_defaultも含めて共通化されている.

結論

  • method_optionsoptions, method_optionoption の機能はそれぞれ同じ.どちらを利用してもよい.
  • method_optionsmethod_option は役割が異なる.
    • method_options は異なる複数のオプションに対して, method_option は単一のオプションに対して項目を指定する.
    • method_optionsrequired, type, default, aliases の計4項目を指定できる.
    • method_option では上記に加えて desc, banner, lazy_default, enum, hide の計9項目を指定できる.
  • method_optionsclass_options は対象となるコマンドが違うだけで同じ項目を指定できる. class_option も同様.
  • ドキュメントは GitHub wikiと公式webサイトがあるが,どちらも古いので両方とも鵜呑みにできない.
10
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
10
2