【问题标题】:Yielding a block to a proc (or creating a method that accepts a block from a proc that yields)向 proc 产生一个块(或创建一个从产生的 proc 接受块的方法)
【发布时间】:2015-05-02 03:45:59
【问题描述】:

我目前正在开发一个接口,该接口允许我使用 proc 链包装任意方法调用。无需过多详细说明,我目前有一个接受如下内容的接口:

class Spy
  def initialize
    @procs = []
  end

  def wrap(&block)
    @procs << block
  end

  def execute
    original_proc = Proc.new { call_original }
    @procs.reduce(original_proc) do |memo, p|
      Proc.new { p.call &memo }
    end.call
  end

  def call_original
    puts 'in the middle'
  end
end

spy = Spy.new
spy.wrap do |&block|
  puts 'hello'
  block.call
end
spy.wrap do |&block|
  block.call
  puts 'goodbye'
end
spy.execute

我想做的是从我的 API 中删除 |&amp;block|block.call 并改用 yield

spy.wrap do
  puts 'hello'
  yield
end

这不起作用并引发了LocalJumpError: no block given (yield) 错误。

我也尝试通过在 reduce 中传递 define_singleton_method 来创建方法,但我没有任何运气。

def execute
  original_proc = Proc.new { call_original }
  @procs.reduce(original_proc) do |memo, p|
    define_singleton_method :hello, &p
    Proc.new { singleton_method(:hello).call(&memo) }
  end.call
end

我可以使用其他方法吗?无论如何从 Proc 到 yield 或使用 Proc 来初始化可以屈服的东西?

【问题讨论】:

    标签: ruby


    【解决方案1】:

    在你的 wrap 块中使用 yield 没有多大意义,除非你将一个块传递给调用者本身:

    def foo
      spy.wrap do
        puts "executed in wrap from foo"
        yield
      end
    end
    

    如果您在没有块的情况下调用foo,它将引发异常,因为yield 找不到要执行的块。但是如果你将一个块传递给foo 方法,那么它将被调用:

    foo do
      puts "foo block"
    end
    

    会输出

    executed in wrap from foo
    foo block
    

    总之,我认为您误解了yield 的工作原理,我认为这不是您想要在这里实现的目标。

    【讨论】:

    • 我想我想要做的是将传递给wrap 的每个块用一个聚合块包装起来,该块包含对wrap 方法的所有其余调用。我想我可以 1) 将传递给 wrap 的块捕获到一个 proc,2) 存储那些以延迟执行,3) 执行并链接每个存储的 proc,每个都相互包装。我认为让这个与产量一起工作在语法上会更好。不会花太多时间在上面
    • 更简洁地说,我似乎无法使用 yield 获取一个块,将其传递给某个构建器方法,然后使用该块创建一个将 yield 的方法跨度>
    • 如果你想操作块,你不能绕过yield关键字
    猜你喜欢
    • 2010-12-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-06
    • 2014-06-05
    • 1970-01-01
    • 1970-01-01
    • 2014-04-09
    相关资源
    最近更新 更多