对带有无效密钥的DSL使用groovy映射

问题描述:

我目前正在构建一个小的DSL,它需要指定key = value对中的一组属性,但是这些密钥可能包含破折号' - '或句点''。我似乎无法让它工作。对带有无效密钥的DSL使用groovy映射

煮沸我本质上尝试传递一个Map作为委托给一个闭包,但是这个语法一直让我着迷。

作为一个例子,考虑这样的:

def map = [:] 

map.with { 
    example1 = 123 
    //exam-ple2 = 123 
    //'exam-ple3' = 123 
    //(exam-ple4) = 123 
    exam.ple5 = 123 
    //'exam.ple6' = 123 
} 

实施例1是精细,关键字等于值和容易读取。例2和例4是编译器根据二进制表达式编译的。例3和例6是常量表达式,不会被编译。例5将编译,但在运行时生成一个NPE。

我可以使用变通方法,例如将Map作为参数传递给闭包,这给了我例3和例6,但是它的冗长让我很烦恼。

有没有人有任何想法如何整齐地DSL属性映射?

BTW:我从Java调用不是常规的DSL,所以在分析方面的技巧必须是java :)

更新1:在inital意见和答案后..

所以脚本由GroovyShell评估为DelegatingScript,其中代表是Java对象。封闭包含来自.properties文件的属性,需要在不同的上下文中进行定义,例如,

env { 
    server-name=someHost1 
    database.name=someHost2 
    clientName=someHost3 
} 

委派(Java)的对象将读取该块,作为

public void env(Closure closure) { 
    Map map = new HashMap(); 
    closure.setDelegate(map); 
    closure.setResolveStrategy(Closure.DELEGATE_ONLY); 
    closure.call(); 
    ... do something with map... 

}

现在的用户(即不是我)可能会从原来的属性文件复制到脚本更改名称,因此我宁愿他们可以做到这一点,而不必编辑太多,因为它肯定会导致错别字。

正如我所说我也有例3和6海湾红色为好,但肯定的,蒂姆,我忘了隐含的吧:)

现在我已经改变了格式的字符串,因此DSL使用多写像

env ''' 
    server-name=someHost1 
    database.name=someHost2 
    clientName=someHost3 
''' 

也就是说,直插式字符串而不是关闭,然后读取字符串,并使用标准的java.util.Properties:

public void env(String envString) { 
    Properties properties = new Properties; 
    properties.load(new StringReader(envString)) 
    ....etc 

}

虽然这个工程,具有封闭和M的组合最后一行字符串是目前唯一的缺点。

+0

你可以这样解释:“解析方必须是java'? 由于内部groovy DSL依赖groovy语法分析器 像地图元素分配这里,你将如何解析它与Java? 如果你打电话groovy,无论如何不会在groovy方面做到这一点? – ARA

+0

'it.'exam-ple2'= 123' –

在地图声明,Groovy中解析标识符,比如example1example2字符串键到地图:

[ example1: 1, example2: 2 ] 

.with{}情况下,它可能使用setProperty(property, value)机制。


但你的案件的特点表现exam.pleexam-ple。这些表达式有优先权,因此,Groovy会尝试先解决它们(可能分别类似于exam.getProperty('ple')exam.minus(ple))。

你有一些语法的替代品,但你必须要清楚,以常规什么都应该是字符串键,什么是其他表达式:

def map = [ 
    'exam.ple4' : 4, // direct map declaration 
    example5 : 5 // unambiguous key declaration: no quotes needed 
] 

map.with { 
    example1 = 1 
    put 'exam.ple2', 2 // ambiguous, needs quotes 
    it.'exam-ple3' = 3 // as per @TimYates suggestion 
} 

assert map['exam-ple3'] == 3 
assert map.'exam.ple2' == 2 
assert map['exam.ple4'] == 4 
assert map.example5 == 5 // again, no quotes needed for key