我正在用红宝石写一个简单的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
我不记得如何做到这一点,我不确定缺点,但更清晰的语法是诱人的。有没有人对这种转变有所了解?
答案 0 :(得分:9)
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
答案 1 :(得分:7)
看看这篇文章http://www.dan-manges.com/blog/ruby-dsls-instance-eval-with-delegation - 概述了该方法(在其缺点和可能的解决方案的背景下明确说明),还有几个有用的链接供进一步阅读。< / p>
基本上,它是关于使用instance_eval在理想的上下文中执行块。
谈到这种技术的缺点:
那有什么问题呢?好吧,问题是块是 一般关闭。而且你希望它们实际上是全封闭的。 从你编写块的那一点来看,这并不明显 该块可能不是完全关闭。这就是你发生的事情 使用instance_eval:你将该块的self重置为某个东西 else - 这意味着该块仍然是所有本地的闭包 块外的变量,但不适用于方法调用。我甚至没有 知道是否改变了常量查找。
使用instance_eval以这种方式更改语言规则 读块时不明显。你需要考虑一个额外的步骤 找出你可以词法上看到的方法调用的确切原因 实际上不能从块内部调用块周围。
答案 2 :(得分:0)
查看docile宝石。它可以处理所有锋利的边缘,使您非常轻松。