【问题标题】:how to send dynamic arguments to methods with default args如何将动态参数发送到具有默认参数的方法
【发布时间】:2017-01-26 00:09:18
【问题描述】:

我试图弄清楚是否有一种方法可以使用 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 的调用最终是 send(:perform, [], {}) ,这会导致 ArgumentError 导致 args 数量不匹配,或者至少发送一个不意味着发送的值 ([] 而不是默认“某事”)。

任何想法如何克服这个问题?

【问题讨论】:

  • 如果你从等式中删除 kwargs,这一切都是starts working
  • 感谢@SergioTulentsev,这确实有效,我很欣赏详细的答案。尝试是否有人会提出 kwargs 的想法。

标签: ruby-on-rails ruby


【解决方案1】:

问题

我找到的最好的解释是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

【讨论】:

    猜你喜欢
    • 2023-03-13
    • 2017-06-11
    • 1970-01-01
    • 2018-03-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-04-26
    相关资源
    最近更新 更多