¿Cómo puedo convencer a GroovyShell para que mantenga el estado sobre las llamadas eval()?

StackOverflow https://stackoverflow.com/questions/45582

Pregunta

Estoy intentando utilizar Groovy para crear un modo macro/scripting interactivo para mi aplicación.La aplicación es OSGi y gran parte de la información que los scripts pueden necesitar no se conoce de antemano.Pensé que podría usar GroovyShell y llamar a eval() varias veces y agregarlo continuamente al espacio de nombres a medida que se cargan los paquetes OSGi.GroovyShell mantiene un estado variable en múltiples llamadas de evaluación, pero no en definiciones de clases ni en métodos.

meta:Cree una clase base durante el inicio.A medida que se cargan los paquetes OSGi, cree clases derivadas según sea necesario.

¿Fue útil?

Solución 2

Terminé inyectando código antes de cada compilación de script.El objetivo final es que el script escrito por el usuario tenga un idioma específico del dominio disponible para su uso.

Otros consejos

No estoy seguro de lo que quiere decir con clases declaradas que no existen entre evaluaciones, los siguientes dos scripts funcionan como se esperaba cuando se evalúan uno tras otro:

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

...

new C()

Sin embargo, los métodos quedan vinculados a la clase que los declaró y GroovyShell crea una nueva clase para cada instancia.Si no necesita el valor de retorno de ninguno de los scripts y son realmente scripts (no clases con métodos principales), puede adjuntar lo siguiente al final de cada script evaluado.

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

Si depende del valor de retorno, puede administrar manualmente la evaluación y ejecutar el script como parte de su análisis (advertencia, a continuación aparece código no probado, solo para usos ilustrativos)...

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...

Hay una última advertencia que estoy seguro que conoce.Las variables escritas estáticamente no se mantienen entre evaluaciones ya que no se almacenan en el enlace.Entonces, en el script anterior, la variable 'klass' no se mantendrá entre invocaciones del script y desaparecerá.Para rectificar eso, simplemente elimine las declaraciones de tipo en el primer uso de todas las variables, eso significa que se leerán y escribirán en el enlace.

¿Esto podría ser lo que estás buscando?

De Groovy en acción

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

¿Un uso adecuado de Binding le permitirá mantener el estado?

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top