如何使用默认args向方法发送动态参数

时间:2017-01-25 14:57:21

标签: ruby-on-rails ruby

我想知道是否有一种方法可以使用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

一旦将模块包含在Worker类中,我遇到了一个问题 模块的发送命令:

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

如果曾经想要调用#perform并使用默认参数,那么调用将完全没有任何参数:

Worker.new.perform()

但模块中的send命令会将* args和** kwargs转换为[]和{}。因此,对#perform的调用最终会发送(:perform,[],{}),这会导致argsmentError的args数量不匹配,或者至少发送一个值并不意味着发送([]而不是默认'某事')。

任何想法如何克服这个?

1 个答案:

答案 0 :(得分:2)

问题

我发现的最佳解释是here

**{}的解析方式与**kwargs相同,即使kwargs为空哈希值。

keyword_args.empty?

一个简单的解决方案是在调用kwargs之前检查skippable_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?
        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