我想在对象上动态创建method_missing,同时仍然允许它接受块。同时,我需要在动态创建的method_missing中使用闭包。这是问题所在:
define_singleton_method
创建method_missing
,并传递一个块来创建闭包。method_missing
不能接受块。简单演示,仅供澄清(即,我关心解决一般情况,而非此特定问题):
close_over_me = "99"
o = Object.new
o.define_singleton_method(:method_missing) do |*all_args|
meth, *args = all_args
"The args passed to #{meth}: #{args}. Special code: #{close_over_me}"
end
p o.hi(42) #=> "The args passed to hi: [42]. Special code: 99"
现在让我说我想传入一个块,它以某种方式改变了特殊代码,例如,通过加倍它。也就是说,我想写:
p o.hi(42) {|x| 2*x}
请记住,我希望实现以下所有目标:
method_missing
必须在动态定义时创建一个闭包。因此无法做def o.method_missing...
是否有任何元编程魔法可以同时实现所有这些?
答案 0 :(得分:2)
使用define_method
系列方法,传递给define_method
的块的参数列表将成为define_method
定义的方法的参数列表,因此您需要做的就是块参数是将块参数添加到块的参数列表中:
close_over_me = "99"
o = Object.new
o.define_singleton_method(:method_missing) do |meth, *args, &blk|
blk ||= -> x { x }
"The args passed to #{meth}: #{args}. Special code: #{blk.(close_over_me)}"
end
p o.hi(42) {|x| x*2 } #=> "The args passed to hi: [42]. Special code: 9999"
答案 1 :(得分:0)
以下是修改过的代码 - 您可以期待block
和all_args
。
在发出呼叫之前,必须验证阻止状态。
另请注意,由于close_over_me
是一个字符串,因此将其加倍乘以2会导致"9999"
。
close_over_me = "99"
o = Object.new
o.define_singleton_method(:method_missing) do |*all_args, &block|
meth, *args = all_args
"The args passed to #{meth}: #{args}. Special code: #{block ? block.call(close_over_me) : close_over_me}"
end
p o.hi(42) {|x| x * 2}
#=> "The args passed to hi: [42]. Special code: 9999"
p o.hi(42)
#=> "The args passed to hi: [42]. Special code: 99"
答案 2 :(得分:0)
虽然绝对有可能:
close_over_me = "99"
o = Object.new
o.define_singleton_method(:method_missing) do |*all_args, &cb|
meth, *args = all_args
yielded = cb.call(13) if cb
"Args #{meth}: #{args}. Code: #{close_over_me}. Yielded: #{yielded}."
end
p o.hi(42)
#=> "The args passed to hi: [42]. Special code: 99. Block yielded:."
p o.hi(42) { |x| 2 * x }
#=> "The args passed to hi: [42]. Special code: 99, Block yielded: 26."
我无法如何工作任何数量的参数,因为在单身内部我们应该明确地调用它。
在我看来,你是在设计错误。