我想知道是否有一种方法可以使用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数量不匹配,或者至少发送一个值并不意味着发送([]而不是默认'某事')。
任何想法如何克服这个?
答案 0 :(得分:2)
我发现的最佳解释是here。
**{}
的解析方式与**kwargs
相同,即使kwargs
为空哈希值。
一个简单的解决方案是在调用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
。