可以在非全局上下文中评估Ruby DSL吗?
我正在使用Ruby创建一个DSL。它工作得很好,而且 解决了我的很多问题,但我遇到了以下问题 这与Blockenspiel没有严格的关系 假设我有一个DSL,看起来像这样:可以在非全局上下文中评估Ruby DSL吗?,ruby,metaprogramming,dsl,Ruby,Metaprogramming,Dsl,我正在使用Ruby创建一个DSL。它工作得很好,而且 解决了我的很多问题,但我遇到了以下问题 这与Blockenspiel没有严格的关系 假设我有一个DSL,看起来像这样: dish do name = 'Pizza' ingredients = ... nutrition_facts = ... end dish do name = 'Doner' ingredients = ... nutrition_facts = ... end 现在,我有了一个菜单编译器,它
dish do
name = 'Pizza'
ingredients = ...
nutrition_facts = ...
end
dish do
name = 'Doner'
ingredients = ...
nutrition_facts = ...
end
现在,我有了一个菜单编译器,它可以将菜肴编译成
菜单。编译器现在应该能够编译多个菜单文件,
因此,它设置并清除了一个全局上下文。这应该是最好的
同时发生
我发现sinatra使用类变量,但这有
结果是它只能进行顺序处理,而您
当你想编译一个新的类时,必须清除类变量
菜单。另一种方法是使用全局变量
我更愿意在
对象,这样就没有全局上下文,我可以编译
菜单是并行的,但上次我尝试这个,我遇到了一些问题
在菜单文件中声明(helper-)方法时出现问题
哪些方法是可行的?推荐的方法是什么?基本上有两种方法来归档您想要的内容 选项a:使用setter方法生成对象:
Dish = Struct.new(:name, :ingredients, :nutrition_facts)
def dish
d = Dish.new
yield d
d
end
dish do |d|
d.name = 'Pizza'
d.ingredients = ...
d.nutrition_facts = ...
end
选项b:使用实例变量和实例求值
class Dish
attr_accessor :name, :ingredients, :nutrition_facts
end
def dish(&blk)
d = Dish.new
d.instance_eval(&blk)
d
end
dish do
@name = 'Doner'
@ingredients = ...
@nutrition_facts = ...
end
在这两种情况下,dish方法都将返回dish实例,您可以在其上调用,例如
name
,以访问块中设置的名称(对dish的多次调用将返回独立对象)。请注意,使用instance_eval,用户还可以调用块中Dish类的私有方法,拼写错误的变量名不会导致错误。我所看到的许多库所做的就是利用instance_eval
实现这类功能
只要性能不是一个大问题,您就可以执行以下操作:
class Menu
def initialize file
instance_eval File.read(file),file,1
end
def dish &block
Dish.new &block
end
#....
end
class Dish
def name(n=nil)
@name = n if n
@name
end
def ingredients(igrd=nil)
@ingredients= igrd if igrd
@ingredients
end
end
#....
菜单。新的“菜单/比萨店”
菜单/比萨店
dish do
name 'Cheese Pizza'
ingredients ['Cheese','Dough','Sauce']
end
实际上,有些DSL库添加了诸如
#name
和#components
之类的访问器,因此您不必手动构建它们。例如如果你用self.foo=
替换@foo=
,你就不必担心拼写错误。但我仍然需要一个全局菜单,这是我想要避免的。你可以创建一个菜单(name='default')do。。。将
组件结束到DSL。dish
方法只能在菜单中使用。菜单文件中的helper方法到底有什么问题?我希望菜单名取自我编译的菜单文件。我想在没有全局状态或上下文的情况下并行编译所有菜单。上下文只能是菜单文件的本地上下文。我还可以声明新函数并在计算菜单时在菜单中使用它们吗?可以instance_eval
,就像一个块一样,允许您在其中定义类、模块和方法。