我是lua的新手,我正在尝试创建一个配置DSL,允许包含已经有默认值的部分。
因此,java表预定义了很多值
java = {
source = 1.6,
target = 1.6,
directories = {
sources = "src/main/java",
output = "build/clases",
},
}
我有一个实现__call的Config原型,因此当使用表构造函数作为函数调用时,它只会覆盖默认值。某事(比如):
Config.__call = function(t, props)
for k,v in pairs(props) do
t[k] = v
end
end
我们的想法是,您只能调用dsl来指定要覆盖的内容:
java {
source = 1.5,
directories {
sources = "customsrcdir",
}
}
有一个Config.new方法允许递归地将原型应用于表,以便所有都具有带有__call方法集的元表。
我的问题在于“目录”小节。它在全局上下文中进行评估,因此唯一可行的方法是:
java {
source = 1.5,
java.directories {
sources = "customsrcdir",
}
}
这是毫无意义的,因为这与做:
相同java {
source = 1.5
}
java.directories {
sources = "customsrcdir",
}
我尝试了不同的方法让所需的DSL工作。一个是使用_ENV设置自定义全局环境,但后来我意识到在__call之前对表进行了评估。
我想知道有更多lua经验的人是否使用更高级的表/ metatable / _ENV魔法实现了这样的DSL。
答案 0 :(得分:1)
查看premake是如何做到的......可能是比现在更好的解决方案。 http://en.wikipedia.org/wiki/Premake#Sample_Script
答案 1 :(得分:1)
可以通过电话按照您的方式进行,但解决方案如此复杂,以至于遗漏=
是不值得的。如果你仍然想要表合并/替换功能,那就不难了。
local function merge(t1, t2)
for k, v in pairs(t2) do
-- Merge tables with tables, unless the replacing table is an array,
-- in which case, the array table overwrites the destination.
if type(t1[k]) == 'table' and type(v) == 'table' and #v == 0 then
merge(t1[k], v)
else
t1[k] = v
end
end
end
local data = {
java = {
source = 1.6,
target = 1.6,
directories = {
sources = "src/main/java",
output = "build/classes",
},
}
}
local dsl = {}
load( [[
java = {
source = 1.5,
directories = {
sources = "customsrcdir",
},
}
]], 'dsl-config', 't', dsl)()
merge(data, dsl)
转储data
将导致:
java = {
directories = {
output = "build/classes",
sources = "customsrcdir"
}
source = 1.5,
target = 1.6
}