是否可以在非全局上下文中评估 Ruby DSL?
我正在使用 Blockenspiel 使用 Ruby 创建 DSL。它效果很好并且 解决了我的很多问题,但是我遇到了以下问题 这与 Blockenspiel 没有严格关系。
假设我有一个如下所示的 DSL:
dish do
name = 'Pizza'
ingredients = ...
nutrition_facts = ...
end
dish do
name = 'Doner'
ingredients = ...
nutrition_facts = ...
end
现在我有一个菜单编译器,它可以将菜肴编译成 一个菜单。编译器现在应该能够编译多个菜单文件, 所以它已经设置并清除了全局上下文。这应该最好 并行发生。
我发现 sinatra 使用类变量,但这有 结果是它只能进行顺序处理并且您 当你想编译一个新的类时必须清除类变量 菜单。另一种方法是使用全局变量。
我更愿意在以下范围内评估 DSL 方法: 对象,这样就没有全局上下文,我可以编译 并行菜单,但上次我尝试这个时,我遇到了一些 在菜单文件中声明(helper-)方法时出现问题。
哪些方法是可行的?推荐的方法是什么?
I'm using Blockenspiel to create a DSL with Ruby. It works great and
solves a lot of my problems, but I encountered the following problem
that is not strictly related to Blockenspiel.
Suppose I have a DSL that looks like this:
dish do
name = 'Pizza'
ingredients = ...
nutrition_facts = ...
end
dish do
name = 'Doner'
ingredients = ...
nutrition_facts = ...
end
Now I have a menu compiler which takes the dishes and compiles them into
a menu. The compiler should now be able to compile multiple menu files,
so it has setup and clear a global context. This should preferably
happen in parallel.
I found out that sinatra uses class variables, but this has the
consequence that it can only do sequential processing and that you
have to clear the class variables when you want to compile a new
menu. An alternative would be to use global variables.
I would prefer to evaluate the DSL methods within the scope of an
object, so that there's no global context and I could compile the
menus in parallel, but the last time I tried this, I encountered some
problems when declaring (helper-)methods in the menu file.
Which methods are possible? What is the recommended way to do this?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
我见过的许多库都是利用
instance_eval
来完成此类事情。只要性能不是一个大问题,您就可以执行以下操作:
Menu.new 'menus/pizza_joint'
menus/pizza_joint
实际上有一些 DSL 库可以添加诸如
#name< 之类的访问器/code> 和
#ingredients
因此您不必手动构建它们。例如 dslifyWhat a number of libraries I've seen do is take advantage of
instance_eval
for this sort of thing.As long as performance isn't a huge issue, you can do stuff like:
Menu.new 'menus/pizza_joint'
menus/pizza_joint
There are actually DSL libraries that add accessors like
#name
and#ingredients
so you don't have to build them by hand. eg dslify基本上有两种方法可以实现您想要的。
选项a:使用setter方法生成一个对象:
选项b:使用实例变量和instance_eval
在这两种情况下,dish方法将返回一个Dish实例,您可以在其上调用例如
name
来访问块中设置的名称(对菜的多次调用将返回独立的对象)。请注意,使用 instance_eval,用户还可以调用块中 Dish 类的私有方法,并且拼写错误的变量名称不会导致错误。There are basically two ways to archieve what you want.
Option a: You yield an object with setter-methods:
Option b: you use instance variables and instance_eval
In both cases the dish method will return an instance of Dish on which you can call e.g.
name
to access the name set in the block (and multiple calls to dish will return independent objects). Note that with instance_eval the user will also be able to call private methods of the Dish class in the block and that misspelling variable names will not cause an error.