在块中调用所有方法并附加参数

3
我有以下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类的所有方法并将额外的key=>value添加到最后一个参数哈希表。
Sandwich.prepare_with中需要进行一些特殊的魔法来调用Sandwich(和其所有子类)的所有方法,如使用call而不是仅使用.fry!,例如.fry!({:ingredient=>special_ingredient})编辑:另外一个理想情况是我们需要过滤内部块代码的调用,例如以下代码为任何prepare_with代码引发异常,因为它没有过滤调用附加参数的方法:
=> Hamburger.prepare_with(bacon) do
=>   Hamburger.fry!
=>   h = Hash.new("Go fish") 
=>   Hamburger.add_mayo
=> end

修改了我的回答,请告诉我这是否是您要寻找的。 - Patrick Oscity
你的意思是 Hash.new 应该抛出一个错误吗? - Patrick Oscity
我不确定我是否真正理解了你的编辑,但我认为这是第二个问题,并且这个问题并不容易解决。如果你想在这里构建DSL,你应该使用外部DSL。你可以通过构建自己的解析器或使用treetop或racc来实现。然后,如果出现未知语句,你可以引发异常。 - Patrick Oscity
2个回答

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

它们不能是实例方法,因为问题定义。 - Sergey
好的,你必须在某个地方记住这个特殊的成分。在类变量中记住它们似乎很奇怪,但等一下,我会更新我的答案来反映这一点。 - Patrick Oscity
请查看我编辑后的注释。谢谢。 - Sergey

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

@padde 我必须开始等待更长时间,我的答案总是在底部。 - gmalette

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接