在ruby中没有参数的DSL块

时间:2012-02-10 09:59:59

标签: ruby block dsl

我正在用红宝石写一个简单的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

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

3 个答案:

答案 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宝石。它可以处理所有锋利的边缘,使您非常轻松。