在Ruby中,DSL块没有参数

8
我正在用Ruby写一个简单的DSL。几周前,我偶然发现了一篇博客文章,展示了如何转换类似以下代码的方法:
some_method argument do |book|
  book.some_method_on_book
  book.some_other_method_on_book :with => argument
end

翻译:转化为更清晰的代码。
some_method argument do
   some_method_on_book
   some_other_method_on_book :with => argument
end

我记不清如何做这个,也不确定有什么缺点,但更简洁的语法很诱人。有人知道这个转换吗?

感谢您更改标题!我在措辞方面遇到了一些问题。 - dhuCerbin
3个回答

9
def some_method argument, &blk
  #...
  book.instance_eval &blk
  #...
end

更新:然而,那个漏洞会忽略book,但不允许使用参数。为了透明地使用它,您必须以某种方式传输它。我建议在书本上这样做:

class Book
  attr_accessor :argument
end

def some_method argument, &blk
  #...
  book.argument = argument
  book.instance_eval &blk
  #...
end

some_method 'argument' do
   some_method_on_book
   some_other_method_on_book argument
end

谢谢更新。我需要对处理参数进行更多的自定义,但这种方法得到了漂亮的语法。 - dhuCerbin

7
请查看这篇文章http://www.dan-manges.com/blog/ruby-dsls-instance-eval-with-delegation——它概述了该方法(明确说明了其缺点及可能的解决方案),并提供了几个有用的链接以供进一步阅读。
基本上,它是关于使用instance_eval在所需的上下文中执行块。
谈论这种技术的缺点:
引用如下:
那么问题在哪里呢? 好吧,问题在于块通常是闭包。 你期望它们实际上是完整的闭包。 而且从编写块的地方来看,看不出那个块可能不是完整的闭包。 当您使用instance_eval时就会发生这种情况:您将该块的self重置为其他内容 - 这意味着该块仍然是闭包,但对于方法调用则不是。我甚至不知道常量查找是否更改或未更改。
使用instance_eval以一种不明显的方式改变了语言规则。 当阅读块时,您需要思考一个额外的步骤,以确定您可以在块内部实际上无法从块内部调用的方法调用的确切原因。

谢谢,我需要更深入地了解缺点。 - dhuCerbin

0

看看docile gem。它会处理所有尖锐的边缘,让这对你来说非常容易。


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