Groovy DSL:从Strings创建动态闭包 [英] Groovy DSL: creating dynamic closures from Strings

查看:125
本文介绍了Groovy DSL:从Strings创建动态闭包的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这里有一些其他类似的问题,但有很大的不同,我需要提出一个新的问题:

There are some other questions on here that are similar but sufficiently different that I need to pose this as a fresh question:

我创建了一个空类,让调用它Test。它没有任何属性或方法。然后迭代通过一个键/值对映射,动态创建属性命名为键,并包含值...如下:

I have created an empty class, lets call it Test. It doesn't have any properties or methods. I then iterate through a map of key/value pairs, dynamically creating properties named for the key and containing the value... like so:

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
}

现在我可以从这样创建的一个新方法访问这些:

Now I can access these from a new method created like this:

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

我想要做的是动态加载来自String的指令集,像Two + Three,创建一个方法来评估结果,然后迭代地重复这个过程,因为很多字符串包含我碰巧拥有的表达式。

What I would like to do though, is dynamically load a set of instructions from a String, like "Two + Three", create a method on the fly to evaluate the result, and then iteratively repeat this process for however many strings containing expressions that I happen to have.

问题:
a)首先,是否有一个更好,更优雅的方法来做到这一点(基于我给出的信息)?
b)假设这个路径是可行的,从一个字符串动态构造这个闭包的语法是什么,其中字符串引用的变量名只在这个类的方法中有效?

Questions: a) First off, is there simply a better and more elegant way to do this (Based on the info I have given) ? b) Assuming this path is viable, what is the syntax to dynamically construct this closure from a string, where the string references variable names valid only within a method on this class?

谢谢!

推荐答案

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

I think the correct answer depends on what you're actually trying to do. Can the input string be a more complicated expression, like '(Two + Six) / Four'?

您想要允许更复杂的表达式,您可能希望将该字符串直接评估为Groovy表达式。在GroovyConsole或Groovy脚本中,您可以直接调用 evaluate ,这将评估该脚本上下文中的表达式:

If you want to allow more complex expressions, you may want to directly evaluate the string as a Groovy expression. Inside the GroovyConsole or a Groovy script, you can directly call evaluate, which will evaluate an expression in the context of that script:

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 class:

If you are not in one of those script-friendly worlds, you can use the GroovyShell class:

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(),根据脚本的权限,从脚本执行的地方删除所有内容。你可以首先验证输入字符串是安全的(也许检查它只包含已知的运算符,空格,括号和数字名称),但我不知道这是否足够安全。

But, be aware that using eval is very risky. If the input string is user-generated, i would not recommend you going this way; the user could input something like "rm -rf /".execute(), and, depending on the privileges of the script, erase everything from wherever that script is executed. You may first validate that the input string is "safe" (maybe checking it only contains known operators, whitespaces, parentheses and number names) but i don't know if that's safe enough.

另一个选择是为这些表达式定义自己的迷你语言,然后使用类似 ANTLR 。但是,这又取决于你想要完成的工作。

Another alternative is defining your own mini-language for those expressions and then parsing them using something like ANTLR. But, again, this really depends on what you're trying to accomplish.

这篇关于Groovy DSL:从Strings创建动态闭包的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆