3

我正在尝试使用 Groovy 为我的应用程序创建交互式脚本/宏模式。该应用程序是 OSGi,脚本可能需要的大部分信息事先并不知道。我想我可以使用 GroovyShell 并在加载 OSGi 包时多次调用 eval() 不断附加到命名空间。GroovyShell 维护多个 eval 调用的变量状态,但不维护类定义或方法。

目标:在启动期间创建一个基类。在加载 OSGi 包时,根据需要创建派生类。

4

3 回答 3

2

我不确定您对 eval 之间不存在的声明类的含义是什么,以下两个脚本在一个接一个地评估时按预期工作:

class C {{println 'hi'}}
new C()

...

new C()

但是,方法会绑定到声明它们的类,并且 GroovyShell 会为每个实例创建一个新类。如果您不需要任何脚本的返回值并且它们是真正的脚本(不是具有主要方法的类),您可以将以下内容附加到每个评估脚本的末尾。

Class klass = this.getClass()
this.getMetaClass().getMethods().each {
  if (it.declaringClass.cachedClass == klass) {
    binding[it.name] = this.&"$it.name"
  }
}

如果您依赖于返回值,您可以手动管理评估并运行脚本作为解析的一部分(警告,下面是未经测试的代码,仅用于说明性用途)......

String scriptText = ...
Script script = shell.parse(scriptText)
def returnValue = script.run()
Class klass = script.getClass()
script.getMetaClass().getMethods().each {
  if (it.declaringClass.cachedClass == klass) {
    shell.context[it.name] = this.&"$it.name"
  }
}
// do whatever with returnValue...

我相信您知道最后一个警告。静态类型变量不会保留在 eval 之间,因为它们没有存储在绑定中。因此,在前面的脚本中,变量 'klass' 不会在脚本调用之间保留,并且会消失。为了纠正这一点,只需在第一次使用所有变量时删除类型声明,这意味着它们将被读取并写入绑定。

于 2008-09-15T15:42:13.430 回答
1

最终在每次脚本编译之前注入代码。最终目标是用户编写的脚本具有可用的域特定语言。

于 2009-09-04T17:08:35.407 回答
0

这可能是您正在寻找的东西?

来自Groovy in Action

def binding = new Binding(x: 6, y: 4)
def shell = new GroovyShell(binding)
def expression = '''f = x * y'''
shell.evaluate(expression)
assert binding.getVariable("f") == 24

一个适当的使用 Binding 会让你保持状态吗?

于 2008-09-05T15:55:37.663 回答