动态创建“method_missing”,其中包含一个闭包并支持传递的块

时间:2015-12-31 08:27:07

标签: ruby

我想在对象上动态创建method_missing,同时仍然允许它接受块。同时,我需要在动态创建的method_missing中使用闭包。这是问题所在:

  1. 要创建闭包,我需要使用define_singleton_method创建method_missing,并传递一个块来创建闭包。
  2. 块本身不能接受块,因此新创建的method_missing不能接受块。
  3. 简单演示,仅供澄清(即,我关心解决一般情况,而非此特定问题):

    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}
    

    请记住,我希望实现以下所有目标:

    1. 它适用于任何方法名称。
    2. method_missing必须在动态定义时创建一个闭包。因此无法做def o.method_missing...
    3. 它必须适用于任意数量的参数,我们事先并不知道参数的数量。参数可以是任何类型。
    4. 是否有任何元编程魔法可以同时实现所有这些?

3 个答案:

答案 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)

以下是修改过的代码 - 您可以期待blockall_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."

我无法如何工作任何数量的参数,因为在单身内部我们应该明确地调用它。

在我看来,你是在设计错误。