Groovy的DSL:创建从字符串动态关闭(Groovy DSL: creating dynamic

2019-09-19 11:42发布

但是也有一些相似,但明显不同,我需要提出这个作为一个新的问题,在这里的一些其他问题:

我已经创建了一个空类,让调用它测试。 它没有任何属性或方法。 然后,我通过图一键/值对的迭代,动态创建命名为关键属性和包含的价值......像这样:

def langMap = [:]
langMap.put("Zero",0)
langMap.put("One",1)
langMap.put("Two",2)
langMap.put("Three",3)
langMap.put("Four",4)
langMap.put("Five",5)
langMap.put("Six",6)
langMap.put("Seven",7)
langMap.put("Eight",8)
langMap.put("Nine",9)

langMap.each { key,val ->
    Test.metaClass."${key}" = val
}

现在,我可以这样创造了一个新的方法来访问这些:

Test.metaClass.twoPlusThree = { return Two + Three }
println test.twoPlusThree()

我想这样做虽然,被动态地从字符串加载一组指令,如“二+三”,动态创建的方法来评估的结果,然后反复重复这个过程包含表达式然而,许多字符串我正好有。

问题:a)首先,有一个简单的更好,更优雅的方式来做到这一点(基于我所提供的信息)? 二)假设这条路是可行的,什么是语法从一个字符串,其中字符串的引用变量名有效只能在这个类中的方法动态构建这个封闭?

谢谢!

Answer 1:

我认为正确的答案取决于你实际上要怎样做。 输入字符串可以是一个更复杂的表达式,如'(Two + Six) / Four'

如果你想允许更复杂的表达式,你可能想直接判断字符串作为一个Groovy表达式。 在groovyConsole中或Groovy脚本里面,你可以直接调用evaluate ,这将在脚本的上下文中计算表达式:

def numNames = 'Zero One Two Three Four Five Six Seven Eight Nine'.split()

// Add each numer name as a property to the script.
numNames.eachWithIndex { name, i ->
    this[name] = i
}

println evaluate('(Two + Six) / Four') // -> 2

如果你是不是在那些脚本友好的世界的一个,你可以使用GroovyShell类:

def numNames = 'Zero One Two Three Four Five Six Seven Eight Nine'.split()
def langMap = [:]
numNames.eachWithIndex { name, i -> langMap[name] = i }

def shell = new GroovyShell(langMap as Binding)
println shell.evaluate('(Two + Six) / Four') // -> 2

但是,请注意, 使用eval是非常危险的 。 如果产生用户输入的字符串,我不建议你去这样; 用户可以输入类似"rm -rf /".execute()并根据脚本的权限,删除一切从任何地方执行的脚本。 您可以先验证输入字符串为“安全”(也许检查它仅包含已知的运营商,空格,括号内数字的名称),但我不知道这是足够安全的。

另一种方法是定义你自己的迷你语言,这些表达式,然后使用类似分析他们ANTLR 。 但同样,这真的取决于你试图完成什么。



文章来源: Groovy DSL: creating dynamic closures from Strings