在ruby中没有参数的DSL块

dhu*_*bin 8 ruby dsl block

我正在用红宝石写一个简单的dsl.几周前,我偶然发现了一些博文,其中展示了如何转换代码:

some_method argument do |book|
  book.some_method_on_book
  book.some_other_method_on_book :with => argument
end
Run Code Online (Sandbox Code Playgroud)

更清洁的代码:

some_method argument do
   some_method_on_book
   some_other_method_on_book :with => argument
end
Run Code Online (Sandbox Code Playgroud)

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

Son*_*tos 9

def some_method argument, &blk
  #...
  book.instance_eval &blk
  #...
end
Run Code Online (Sandbox Code Playgroud)

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

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
Run Code Online (Sandbox Code Playgroud)


Ale*_*xis 7

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

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

说到这种技术的缺点:

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

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