使用附加参数调用块中的所有方法

时间:2012-04-24 11:40:48

标签: ruby lambda metaprogramming

我有以下Ruby类:

class Sandwich
  class << self
    def prepare_with(special_ingredient, &block)
      # Some very very special magic is done here to
      # call instead just .fry! as .fry!({:ingredient=>special_ingredient})
      # and for any other method the same
    end

    def fry!(opts= {})
    end

    def add_mayo(opts = {})
    end
  end
end

class Hamburger < Sandwich
end

=> Hamburger.prepare_with(bacon) do
=>   Hamburger.fry!
=>   Hamburger.add_mayo
=> end

我想修改调用Hamburger类的所有方法,并在最后一个参数Hash中添加额外的key=>value

应该在Sandwich.prepare_with中完成一些特殊的魔法来调用三明治的所有方法(及其所有后代),例如call而不是.fry!作为.fry!({:ingredient=>special_ingredient})

已编辑:理想情况下,我们需要过滤内部块代码的调用,例如以下代码会引发任何prepare_with代码的异常,这不会过滤使用其他参数调用的方法:

=> Hamburger.prepare_with(bacon) do
=>   Hamburger.fry!
=>   h = Hash.new("Go fish") 
=>   Hamburger.add_mayo
=> end

2 个答案:

答案 0 :(得分:3)

为什么fry!add_mayo不是实例方法?

编辑:正如请求的问题海报,没有实例方法:

class Sandwich
  class << self
    def prepare_with(special_ingredient, &block)
      @@default_opts = {:special_ingredient => special_ingredient}
      block.call
    end

    def fry!(opts={})
      opts = opts.merge(@@default_opts)
      puts "fried with #{opts[:special_ingredient]}"
    end

    def add_mayo(opts = {})
      puts "added mayo"
    end
  end
end

class Hamburger < Sandwich
end

Hamburger.prepare_with(:bacon) do 
  Hamburger.fry!
  Hamburger.add_mayo
end

Hamburger.prepare_with(:tofu) do 
  Hamburger.fry!
end

输出:

fried with bacon
added mayo
fried with tofu

答案 1 :(得分:0)

简短回答

block.call :ingredient => special_ingredient

长答案

我认为你应该处理对象。 add_mayo和fry应该是实例方法而不是类方法。

我会看到像

这样的东西
class Sandwich
  class << self
    def prepare &block
      sandwich = self.new
      block.call sandwich
      sandwich
    end
  end

  def fry(opts = {})
    #stuff
  end

  def add_mayo(opts = {})
  end
end

class Hamburger < Sandwich; end

hamburger = Hamburger.prepare do |h|
  h.fry :ingredient => :bacon
  h.add_mayo
end