12

Thor を使用method_optionすると、特定のタスクのオプションを設定できます。クラス内のすべてのタスクのオプションを設定するには、 を使用できますclass_option。しかし、クラスのすべてではなく一部のタスクでオプションを共有したい場合はどうでしょうか?

次のtask1とはオプションをtask2共有しますが、すべてのオプションを共有するわけではなく、 とはオプションを共有しませんtask3

require 'thor'

class Cli < Thor
  desc 'task1', 'Task 1'
  method_option :type, :type => :string, :required => true, :default => 'foo'
  def task1
  end

  desc 'task2', 'Task 2'
  method_option :type, :type => :string, :required => true, :default => 'foo'
  method_option :value, :type => :numeric
  def task2
  end

  desc 'task3', 'Task 3'
  method_option :verbose, :type => :boolean, :aliases => '-v'
  def task3
  end
end

Cli.start(ARGV)

method_option :type, :type => :string, :required => true, :default => 'foo'との両方task1を記述することの問題点は、DRY の原則task2に違反していることです。これを処理する慣用的な方法はありますか?

4

5 に答える 5

14

method_optionthor.rbで定義されており、ドキュメントに従って次のパラメーターを取ります。

  • name<Symbol>::引数の名前。
  • options<Hash>::以下で説明します。

これを知っていれば、パラメーターをmethod_option配列に格納し、その配列を呼び出されたときに個別のパラメーターに展開できますmethod_option

require 'thor'

class Cli < Thor
  shared_options = [:type, {:type => :string, :required => true, :default => 'foo'}]

  desc 'task1', 'Task 1'
  method_option *shared_options
  def task1
  end

  desc 'task2', 'Task 2'
  method_option *shared_options
  method_option :value, :type => :numeric
  def task2
  end

  desc 'task3', 'Task 3'
  method_option :verbose, :type => :boolean, :aliases => '-v'
  def task3
  end
end

Cli.start(ARGV)

これが慣用句かどうかはわかりませんし、それほどエレガントではないと思います。それでも、DRY 原則に違反するよりはましです。

于 2013-01-16T14:23:23.883 に答える
3

次のようなスーパークラスを使用します。

require 'thor'

class CliBase < Thor
  def self.shared_options

    method_option :verbose,
                  :aliases => '-v',
                  :type => :boolean,
                  :desc => 'Verbose',
                  :default => false,
                  :required => false

  end
end

... 次に、次のようにサブクラス化します。

require 'cli_base'

class Cli < CliBase
  desc 'task1', 'Task 1'
  shared_options
  def task1
  end

  desc 'task2', 'Task 2'
  shared_options
  method_option :value, :type => :numeric
  def task2
  end

  desc 'task3', 'Task 3'
  method_option :colors, :type => :boolean, :aliases => '-c'
  def task3
  end
end

Cli.start(ARGV)
于 2013-04-19T22:02:57.390 に答える
2

私は同じ問題を抱えていて、NNが答えたものを使用しました。しかし、私はいくつかの問題を発見しました:

例のように複数のオプションを共有したい場合、うまく機能しません。:valuetask2 と task3 の間で共有したいとします。別のshared_optionsものを作成するか、共有オプションを使用して配列を作成し、shared_option 名でアクセスすることができます。

これは機能しますが、冗長で読みにくいです。オプションを共有できるように、小さなものを実装しました。

Cli < Thor  
  class << self
      def add_shared_option(name, options = {})
        @shared_options = {} if @shared_options.nil?
        @shared_options[name] =  options
      end

      def shared_options(*option_names)
        option_names.each do |option_name|
          opt =  @shared_options[option_name]
          raise "Tried to access shared option '#{option_name}' but it was not previously defined" if opt.nil?
          option option_name, opt
        end
      end
    end
    #...commands 
end

これにより、オプション名をキーとしてハッシュが作成され、「定義」(必須、デフォルトなど) が値 (ハッシュ) として作成されます。これは後で簡単にアクセスできます。

これにより、次のことができます。

require 'thor'

class Cli < Thor

  add_shared_option :type,  :type => :string, :required => true, :default => 'foo'
  add_shared_option :value, :type => :numeric

  desc 'task1', 'Task 1'
  shared_options :type
  def task1
  end

  desc 'task2', 'Task 2'
  shared_options :type, :value
  def task2
  end

  desc 'task3', 'Task 3'
  shared_options :value
  def task3
  end
end

Cli.start(ARGV)

私にとっては、より読みやすく見えます。コマンドの数が 3 つまたは 4 つよりも多い場合は、大幅に改善されます。

于 2014-07-18T16:20:56.613 に答える
0

常に「shared_options」と入力しないようにするには、次のようにすることもできます。

require 'thor'

class Cli < Thor
  class << self
    private
    def shared_options!
      # list your shared options here
      method_option :opt1, type: :boolean
      method_option :opt2, type: :numeric
      # etc
    end

    # alias original desc so we can call it from inside new desc
    alias_method :orig_desc, :desc

    # redefine desc, calling original desc, and then applying shared_options!
    def desc(*args)
      orig_desc(*args)
      shared_options!
    end
  end

  desc 'task1', 'Task 1'

  def task1
  end

  desc 'task2', 'Task 2'

  def task2
  end

  desc 'task3', 'Task 3'

  def task3
  end
end

または、メソッドのエイリアシングでアクロバットが必要ない場合は、独自のメソッド「my_desc」を定義して、「desc」の代わりにそれを呼び出すことができます。

于 2016-04-05T18:59:39.350 に答える