2013-01-15 52 views
7

使用Thor可以使用method_option來設置特定任務的選項。要爲班級中的所有任務設置選項,可以使用class_option。但是,如果想要一個班級的一些任務而不是全部的任務來分享選項,那麼情況如何呢?如何使兩個thor任務共享選項?

在以下task1task2份額選項,但它們不共享所有選項,並且它們與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'兩個task1task2的問題是,它違反了the DRY principle。有沒有一種處理這種習慣的慣用方式?

回答

11

method_optionthor.rb定義,它根據文檔採用以下參數:

  • name<Symbol>::參數的名稱。
  • options<Hash>::介紹如下。

知道了這一點,你可以將參數存儲到一個數組method_optionexpand that array into separate parametersmethod_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原則。

+1

好主意,但我們可以進一步,也許定義shared_options類方法委託給method_option +合併公共散列? – inger

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) 
+0

你真的需要在這裏繼承嗎?爲什麼不在CLI類中定義shared_options? – inger

+3

我認爲有很多方法可以回答OP。我碰巧鄙視不止一次地使用我的解決方案編寫代碼,編寫基類,把它放在gem中,然後在編寫另一個Thor腳本時使用它。畢竟,-v for verbose是我將在單個實例之外再次使用的東西。但是可以肯定的是,無論你喜歡,你都可以做到。 – Midwire

2

我有同樣的問題,我用什麼N.N.回答。 但我發現了一些問題:

如果您想要共享多個選項(如示例中所示),則效果不佳。想象一下你想在task2和task3之間分享:value。您可以創建另一個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這是一個很大的改進。

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「而不是」desc「。