2017-01-25 75 views
1

我想了解是否有一種使用send方法調用具有動態參數(* args,** kwrags)的方法,而該方法只有默認參數。如何向具有默認參數的方法發送動態參數

考慮下面的類:

class Worker 
    def perform(foo='something') 
    # do something 
    end 
end 

我有需要檢查一些條件的模塊。 如果條件不滿足,則#perform方法應該運行:

module SkippableWorker 
    def self.included(base) 
    base.class_eval do 
     alias_method :skippable_perform, :perform 
     define_method :perform do |*args, **keyword_args| 
     return if skip? 
     self.send(:skippable_perform, *args, **keyword_args) 
     end 

     define_method :skip? do 
     # checks whether to skip or not 
     end 
    end 
    end 
end 

一旦包括在工類的模塊,我遇到一個問題 模塊的發送命令:

self.send(:skippable_perform, *args, **keyword_args) 

如果一旦想要調用#perform並使用默認參數,則調用將根本沒有任何參數:

Worker.new.perform() 

但是,發送命令i n模塊將* args和** kwargs轉換爲[]和{}。因此,對#perform的調用結束爲send(:perform,[],{}),這會導致ArgumentError參數量不匹配,或者至少發送一個值並不意味着發送([]而不是默認'某事')。

任何想法如何克服這一點?

+2

如果您從等式中刪除kwargs,它將全部[開始工作](http://pastebin.com/qt84MvnR)。 –

+0

謝謝@SergioTulentsev,這確實有效,我讚賞詳細的答案。 嘗試是否有人會想出一個kwargs的想法。 –

回答

2

問題

我發現,最好的解釋是here

**{}未被解析的方式與**kwargs相同,即使kwargs是空的哈希。

keyword_args.empty?

一個簡單的解決方案是在致電skippable_perform之前檢查kwargs是否爲空。

完整的代碼變成:

module SkippableWorker 
    def self.included(base) 
    base.class_eval do 
     alias_method :skippable_perform, :perform 
     define_method :perform do |*args, **keyword_args| 
     return if skip? 
     if keyword_args.empty? 
      self.send(:skippable_perform, *args) 
     else 
      self.send(:skippable_perform, *args, **keyword_args) 
     end 
     end 

     define_method :skip? do 
     puts self.class 
     if rand > 0.5 
      puts " Skipping" 
      true 
     end 
     end 
    end 
    end 
end 

class Worker 
    def perform(foo='standard arg') 
    puts " #{foo}" 
    end 
    include SkippableWorker 
end 

class AnotherWorker 
    def perform(bar:'standard kwarg') 
    puts " #{bar}" 
    end 
    include SkippableWorker 
end 

Worker.new.perform 
Worker.new.perform 
Worker.new.perform('another arg') 
Worker.new.perform('another arg') 
AnotherWorker.new.perform 
AnotherWorker.new.perform 
AnotherWorker.new.perform(bar: 'another kwarg') 
AnotherWorker.new.perform(bar: 'another kwarg') 

根據rand,它可以輸出:

Worker 
    standard arg 
Worker 
    Skipping 
Worker 
    Skipping 
Worker 
    another arg 
AnotherWorker 
    standard kwarg 
AnotherWorker 
    standard kwarg 
AnotherWorker 
    Skipping 
AnotherWorker 
    another kwarg 

#方法參數

另一種方法是檢查由skippable_perform預計其參數:

method(:skippable_perform).parameters.any?{|type,name| type == :key} 

並根據結果改編define_method

+0

謝謝,好主意! –