【问题标题】:Using yield inside define_method in Ruby在 Ruby 的 define_method 中使用 yield
【发布时间】:2011-01-19 09:18:56
【问题描述】:

是否可以使 yield 关键字在给定给 define_method 的块内工作?简单例子:

class Test
  define_method :test do |&b|
    puts b    # => #<Proc:...>
    yield
  end
end

Test.new.test {
  puts "Hi!"
}

此代码在 Ruby 1.8.7 和 1.9.0 中都产生以下错误:

test.rb:4:in `test': 没有给出块 (LocalJumpError) 来自 test.rb:8

奇怪的是 b 块变量 != nilblock_given? 返回 false。 Ruby 是否故意不通过 Proc 对象识别块?

编辑:关于 Beerlington 的回答:b.call() 不是我想要的。块变量仅用于指示实际给定的块,在define_method中未检测到。

为什么我需要使用yield 而不是block.call

我愿意为如何在 Ruby 中定义新类的方式编写一些扩展,因此当我使用我的扩展时,应该接受您可以用纯 Ruby 编写的任何代码。

因此不能考虑相似的语义,因为这会迫使我的库的用户只使用一种正确的方式来传递块。这违反了 TIMTOWDI 规则,并且不会使我的库透明。

现实生活中的例子

下面的代码可以简化为上面的代码,因为my_def 使用define_method

require 'my_library'

class Test
  # client can write 'my_def' instead of 'def' since
  # my_library extends Class class
  my_def :test, "some parameter" do
    yield        # oh no, error :(
  end
end

Test.new.test {
  puts "Hi!"
}

【问题讨论】:

标签: ruby metaprogramming


【解决方案1】:

我想这就是你要找的东西:

class Test
  define_method :test do |&b|
    b.call
  end
end

Test.new.test {
  puts "Hi!"
}

更多信息请访问http://coderrr.wordpress.com/2008/10/29/using-define_method-with-blocks-in-ruby-18/

【讨论】:

  • 不幸的是,这不是我想要的。我知道我可以通过这种方式调用 block,但我需要使用 yield。 b 变量仅用于指示实际给出的块。
  • @Dejw,这您正在寻找的机器人。将 &block 作为参数并对其调用 block.call 与调用“yield”具有相同的语义。 Beerlington 的代码适用于 1.8.7 和 1.9。
  • @Wayne:您可能认为这是解决方案,但事实并非如此。我没有写出使用yield 代替block.call 的目的,以及为什么 现在在我的问题中。
  • @Dejw,感谢您的补充说明。我不得不承认我仍然感到困惑:block.call 不仅具有与 yield 相同的语义,它对调用者具有完全相同的语法(参见 Beerlington 的代码:他没有将块作为参数传递)。调用者无法判断该方法使用的是哪一个。我错过了什么?
  • 问题是调用者可能写yield而不是block.call。我给出的代码可能是调用者的代码。我的库中的扩展方法定义可以简化为我上面的代码。客户端提供传递给define_method(方法体)的块,所以他/她可以在那里写任何东西。特别是yield。我可以在文档中写 yield 根本不起作用,但我试图避免这种情况,并使我的库与 Ruby 100% 兼容(允许使用任何语言语法,而不仅仅是一个子集)。
【解决方案2】:

您不能在 define_method 块内使用 yield。这是因为块被闭包捕获,请注意:

def hello
  define_singleton_method(:bye) { yield }
end

hello { puts "hello!" }

bye {  puts "bye!" } #=> "hello!"

我认为您的用户不会介意不能按照您所说的方式使用 'yield' ---- 语法 nothing 像普通的 Ruby 方法定义语法,因此不太可能有任何困惑。

有关为什么不能将块隐式传递给此处找到的方法的更多信息:http://banisterfiend.wordpress.com/2010/11/06/behavior-of-yield-in-define_method/

【讨论】:

  • 哇,感谢您的解释,我想知道为什么它不起作用。这应该是公认的答案
猜你喜欢
  • 1970-01-01
  • 2012-11-07
  • 1970-01-01
  • 1970-01-01
  • 2014-03-11
  • 2011-03-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多