在ruby中没有参数的DSL块

我正在用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 

我不记得如何做到这一点,我不确定缺点,但更清晰的语法是诱人的。 有没有人对这种转变有所了解?

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

更新:但是,这省略了书,但不允许你使用参数。 要透明地使用它,你必须以某种方式运输它。 我建议在本书上做:

 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 

看一下这篇文章http://www.dan-manges.com/blog/ruby-dsls-instance-eval-with-delegation – 该方法概述(具体说明其缺点和可能性)他们的解决方案),还有几个有用的链接供进一步阅读。

基本上,它是关于使用instance_eval在期望的上下文中执行块。

说到这种技术的缺点:

那有什么问题呢? 嗯,问题是块通常是闭包。 而且你希望它们实际上是全封闭的。 从你编写块的那一点来看,这个块可能不是一个完整的闭包并不明显。 当你使用instance_eval时会发生这种情况:你将该块的self重置为其他东西 – 这意味着该块仍然是块外所有局部变量的闭包,但不是方法调用。 我甚至不知道是否改变了常量查找。

使用instance_eval会以一种在读取块时不明显的方式更改语言规则。 你需要考虑一个额外的步骤来弄清楚为什么一个你可以在块周围看到的方法调用实际上不能从块内部调用。

看看温顺的gem。 它可以处理所有锋利的边缘,让您轻松自如。