如何编写不与区块环境隔离的DSL?
我正在尝试编写一个小型 Ruby DSL,但偶然发现了一个不便之处。现在我的“DSL”代码是 https://gist.github.com/0379b07f516f4f322204 和我的实现代码(在 .html.erb 文件内)是:
html_table_for @users do |t, user|
t.field :username, link_to(user.username, :action => 'show', :id => user.id)
t.field :email
t.field :roles, user.roles.map(&:code).join(', ')
end
实现代码看起来不太像 DSL,因为t.field
而不是简单的field
。通过用 instance_exec(@block)
替换 DSL 代码(第 34 行)中的 @block.call
我几乎得到了我想要的东西,但随后我失去了所有 ActionView 的优点(即link_to
)。
有没有办法让我的小 DSL 类的实例方法在块中可用,同时保持 Rails 中包含的 ActionPack 辅助方法的可用性?
I am trying to write a small Ruby DSL and have stumbled upon an inconvenience. Right now my "DSL" code is https://gist.github.com/0379b07f516f4f322204 and my implementation code (inside an .html.erb file) is:
html_table_for @users do |t, user|
t.field :username, link_to(user.username, :action => 'show', :id => user.id)
t.field :email
t.field :roles, user.roles.map(&:code).join(', ')
end
The implementation code does not look much like a DSL because of the t.field
instead of simply field
. By replacing @block.call
in the DSL code (line 34) with instance_exec(@block)
I almost get what I want but then I lose all the ActionView goodness (namely link_to
).
Is there a way to make available in the block the instance methods of my little DSL class while at the same time keeping availability of the helper methods of ActionPack included in Rails?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
我发布了类似的 StackOverflow 问题的详细答案。
简短的回答:查看 Docile gem - 它使您变得非常容易。
I posted a detailed answer to a similar StackOverflow question.
Short answer: check out the Docile gem -- it makes this very easy for you.
可以通过 使用方法委托:
现在您可以像这样使用它:
但是使用此方法时要小心:您仍然无法使用调用对象中的实例变量:
It is possible (albeit hacky and confusing) to get both, by using method delegation:
Now you can use it like this:
Be careful when using this approach though: you still can't use instance variables from the calling object: