使用带有无效密钥的groovy map for DSL

使用带有无效密钥的groovy map for DSL,groovy,dsl,Groovy,Dsl,我目前正在构建一个小型DSL,它需要在key=value对中指定一组属性,但是这些键可能包含破折号“-”或句点“.”,我似乎无法让它工作 归结起来,我基本上尝试将一个映射作为一个闭包的委托来传递,但是语法一直吸引着我 作为一个例子,考虑如下: def map = [:] map.with { example1 = 123 //exam-ple2 = 123 //'exam-ple3' = 123 //(exam-ple4) = 123 exam.ple5

我目前正在构建一个小型DSL,它需要在key=value对中指定一组属性,但是这些键可能包含破折号“-”或句点“.”,我似乎无法让它工作

归结起来,我基本上尝试将一个映射作为一个闭包的委托来传递,但是语法一直吸引着我

作为一个例子,考虑如下:

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绘制一张房产地图

顺便说一句:我称DSL为java而非groovy,因此解析方面的技巧必须是java:)

更新1:在最初的评论和回答之后

因此,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,但是是的,Tim,我忘记了隐含的含义:)

现在,我已经将格式更改为字符串,因此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
}


尽管这是可行的,但闭包和多行字符串的混合是目前唯一的缺点。

在映射声明中,Groovy将
example1
example2
等标识符解析为映射的字符串键

[ example1: 1, example2: 2 ]
在{}上下文中,它可能使用了一种机制


但是您的案例中有表达式
exam.ple
exam-ple
。这些表达式具有优先级,因此Groovy将首先尝试解析它们(分别使用类似于
exam.getProperty('ple')
exam.减号(ple)

您有一些语法选择,但您必须向Groovy明确哪些应该是字符串键,哪些是其他表达式:

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

你能解释一下:‘解析端必须是java’吗?由于内部groovy DSL依赖于groovy语法解析器,比如这里的映射元素分配,您将如何用Java解析它???如果你调用groovy,这不是在groovy端完成的吗?
it.'exam-ple2'=123