如何在同一方法中发送块

时间:2014-09-03 05:16:38

标签: ruby metaprogramming

使用此方法可以动态地将args发送到对象:

module DSL
  def update object, *args, &block
    updated_object = object.send *args
    # then, some stuff with the updated object and the block
  end
end

可以使用以下代码,例如:

include DSL

# equivalent to: Array.new 3, :foo
update Array, :new, 3, :foo do
  # updated object => [:foo, :foo, :foo]
  # some stuff
end

或者如:

# equivalent to: [:foo, :foo, :foo].size
update [:foo, :foo, :foo], :size do
  # updated object => 3
  # some stuff
end

但是我们如何才能更新此update方法的内容以处理块,例如:

[:foo, :bar].select {|a| a == :foo }

我考虑将块转换为proc,例如:

update [:foo, :bar], :select, &:foo.method(:==) do
  # ...
end

但是,因为同一个方法不能处理多个块,所以引发了这个异常:

  

SyntaxError:既包含块arg又包含实际块

有没有一种优雅的方法来解决这个问题?

1 个答案:

答案 0 :(得分:1)

我认为你已经超越了这个,但无论如何,这是一个想法:

你可以将常规proc传递给你的update方法,然后对最后一个参数进行特殊处理,这是一个proc。

module DSL
  def update object, *args, &block
    updated_object = if args.last.is_a? Proc
      proc = args.pop
      object.send *args, &proc
    else
      object.send *args
    end
    yield updated_object
  end
end

extend DSL

update [:foo, :bar], :select, ->(a) { a == :foo } do |obj|
  puts "selected object: #{obj}"
end

# >> selected object: [:foo]