peliculas - groovy traduccion
Incluyendo una secuencia de comandos groovy en otro groovy (11)
He leído cómo simplemente importar un archivo groovy en otra secuencia de comandos groovy
Quiero definir funciones comunes en un archivo groovy y llamar esas funciones desde otros archivos groovy.
Entiendo que esto sería usar Groovy como un lenguaje de scripting, es decir, no necesito clases / objetos. Estoy tratando de algo como DSL que se puede hacer en Groovy. Todas las variables se afirmarán desde Java y quiero ejecutar script groovy en un shell.
¿Es esto posible? ¿Alguien puede dar algún ejemplo?
¿Qué tal tratar el script externo como una clase de Java? Basado en este artículo: https://www.jmdawson.net/blog/2014/08/18/using-functions-from-one-groovy-script-in-another/
getThing.groovy El script externo
def getThingList() {
return ["thing","thin2","thing3"]
}
printThing.groovy El guión principal
thing = new getThing() // new the class which represents the external script
println thing.getThingList()
Resultado
$ groovy printThing.groovy
[thing, thin2, thing3]
A partir de Groovy 2.2, es posible declarar una clase de script base con la nueva anotación de transformación @BaseScript
AST.
Ejemplo:
archivo MainScript.groovy :
abstract class MainScript extends Script {
def meaningOfLife = 42
}
archivo test.groovy :
import groovy.transform.BaseScript
@BaseScript MainScript mainScript
println "$meaningOfLife" //works as expected
Aquí hay un ejemplo completo de incluir un script dentro de otro.
Simplemente ejecute el archivo Testmain.groovy
Comentarios explicativos incluidos porque soy agradable así;]
Testutils.groovy
// This is the ''include file''
// Testmain.groovy will load it as an implicit class
// Each method in here will become a method on the implicit class
def myUtilityMethod(String msg) {
println "myUtilityMethod running with: ${msg}"
}
Testmain.groovy
// Run this file
// evaluate implicitly creates a class based on the filename specified
evaluate(new File("./Testutils.groovy"))
// Safer to use ''def'' here as Groovy seems fussy about whether the filename (and therefore implicit class name) has a capital first letter
def tu = new Testutils()
tu.myUtilityMethod("hello world")
Creo que la mejor opción es organizar cosas de utilidad en forma de clases groovy, agregarlas a classpath y permitir que el script principal se refiera a ellas a través de la palabra clave import.
Ejemplo:
scripts / DbUtils.groovy
class DbUtils{
def save(something){...}
}
scripts / script1.groovy:
import DbUtils
def dbUtils = new DbUtils()
def something = ''foobar''
dbUtils.save(something)
secuencia de comandos en ejecución:
cd scripts
groovy -cp . script1.groovy
Después de algunas investigaciones, llegué a la conclusión de que el siguiente enfoque parece ser el mejor.
algunos / subpaquetes / Util.groovy
@GrabResolver(name = ''nexus'', root = ''https://local-nexus-server:8443/repository/maven-public'', m2Compatible = true)
@Grab(''com.google.errorprone:error_prone_annotations:2.1.3'')
@Grab(''com.google.guava:guava:23.0'')
@GrabExclude(''com.google.errorprone:error_prone_annotations'')
import com.google.common.base.Strings
class Util {
void msg(int a, String b, Map c) {
println ''Message printed by msg method inside Util.groovy''
println "Print 5 asterisks using the Guava dependency ${Strings.repeat("*", 5)}"
println "Arguments are a=$a, b=$b, c=$c"
}
}
ejemplo.groovy
#!/usr/bin/env groovy
Class clazz = new GroovyClassLoader().parseClass("${new File(getClass().protectionDomain.codeSource.location.path).parent}/some/subpackage/Util.groovy" as File)
GroovyObject u = clazz.newInstance()
u.msg(1, ''b'', [a: ''b'', c: ''d''])
Para ejecutar el script example.groovy
, agréguelo a la ruta del sistema y escriba desde cualquier directorio:
example.groovy
El script imprime:
Message printed by msg method inside Util.groovy
Print 5 asterisks using the Guava dependency *****
Arguments are a=1, b=b, c=[a:b, c:d]
El ejemplo anterior se probó en el siguiente entorno: Groovy Version: 2.4.13 JVM: 1.8.0_151 Vendor: Oracle Corporation OS: Linux
El ejemplo demuestra lo siguiente:
- Cómo usar una clase
Util
dentro de una secuencia de comandos groovy. - Una clase
Util
llama a la biblioteca de terceros deGuava
incluyéndola como una dependencia deGrape
(@Grab(''com.google.guava:guava:23.0'')
). - La clase
Util
puede residir en un subdirectorio. - Pasar argumentos a un método dentro de la clase
Util
.
Comentarios / sugerencias adicionales:
- Utilice siempre una clase groovy en lugar de groovy script para la funcionalidad reutilizable dentro de sus secuencias de comandos groovy. El ejemplo anterior usa la clase Util definida en el archivo Util.groovy. Usar scripts maravillosos para la funcionalidad reutilizable es problemático. Por ejemplo, si se usa una secuencia de comandos groovy, la clase Util debería crearse una instancia en la parte inferior de la secuencia de comandos con la
new Util()
, pero lo más importante es colocarla en un archivo llamado cualquier cosa que no sea Util.groovy. Consulte Scripts versus clases para obtener más detalles sobre las diferencias entre las secuencias de comandos groovy y groovy. - En el ejemplo anterior, utilizo la ruta
"${new File(getClass().protectionDomain.codeSource.location.path).parent}/some/subpackage/Util.groovy"
lugar de"some/subpackage/Util.groovy"
. Esto garantizará que el archivoUtil.groovy
siempre se encuentre en relación con la ubicación del script de Groovy (example.groovy
) y no con el directorio de trabajo actual. Por ejemplo, usar"some/subpackage/Util.groovy"
daría como resultado la búsqueda enWORK_DIR/some/subpackage/Util.groovy
. - Siga la convención de nomenclatura de la clase Java para nombrar sus guiones maravillosos. Personalmente, prefiero una pequeña desviación donde los guiones comienzan con una letra más baja en lugar de una mayúscula. Por ejemplo,
myScript.groovy
es un nombre de script yMyClass.groovy
es un nombre de clase. Almy-script.groovy
nombre amy-script.groovy
se producirán errores de tiempo de ejecución en ciertos escenarios, ya que la clase resultante no tendrá un nombre de clase de Java válido. - En el mundo de JVM en general, la funcionalidad relevante se llama JSR 223: Scripting para Java . En groovy en particular, la funcionalidad se denomina mecanismos de integración Groovy . De hecho, se puede usar el mismo enfoque para llamar a cualquier lenguaje JVM desde Groovy o Java. Algunos ejemplos notables de tales lenguajes JVM son Groovy, Java, Scala, JRuby y JavaScript (Rhino).
Groovy no tiene una palabra clave import como los lenguajes de scripts típicos que incluirán literalmente el contenido de otro archivo (al que se alude aquí: Groovy proporciona un mecanismo de inclusión ).
Debido a su naturaleza orientada a objetos / clases, debes "jugar juegos" para hacer que cosas como esta funcionen. Una posibilidad es hacer todas sus funciones de utilidad estáticas (ya que dijo que no usan objetos) y luego realizar una importación estática en el contexto de su caparazón de ejecución. Entonces puede llamar a estos métodos como "funciones globales".
Otra posibilidad sería utilizar un objeto de enlace ( http://groovy.codehaus.org/api/groovy/lang/Binding.html ) al crear su Shell y enlazar todas las funciones que desee con los métodos (la desventaja aquí sería tener enumerar todos los métodos en el enlace, pero quizás puedas usar la reflexión). Otra solución más sería anular methodMissing(...)
en el objeto delegado asignado a su caparazón que le permite básicamente hacer un despacho dinámico usando un mapa o el método que desee.
Varios de estos métodos se demuestran aquí: http://www.nextinstruction.com/blog/2012/01/08/creating-dsls-with-groovy/ . Avísame si quieres ver un ejemplo de una técnica en particular.
La forma en que hago esto es con GroovyShell
.
GroovyShell shell = new GroovyShell()
def Util = shell.parse(new File(''Util.groovy''))
def data = Util.fetchData()
Otra forma de hacerlo es definir las funciones en una clase groovy y analizar y agregar el archivo a la ruta de clase en tiempo de ejecución:
File sourceFile = new File("path_to_file.groovy");
Class groovyClass = new GroovyClassLoader(getClass().getClassLoader()).parseClass(sourceFile);
GroovyObject myObject = (GroovyObject) groovyClass.newInstance();
Para los que llegan tarde, parece que groovy ahora admite el comando :load file-path
que simplemente redirige la entrada del archivo dado, por lo que ahora es trivial incluir scripts de biblioteca.
Funciona como entrada para groovysh y como una línea en un archivo cargado:
groovy:000> :load file1.groovy
file1.groovy puede contener:
:load path/to/another/file invoke_fn_from_file();
Una combinación de respuestas @grahamparks y @snowindy con un par de modificaciones es lo que funcionó para mis scripts Groovy que se ejecutan en Tomcat:
Utils.groovy
class Utils {
def doSth() {...}
}
MyScript.groovy:
/* import Utils --> This import does not work. The class is not even defined at this time */
Class groovyClass = new GroovyClassLoader(getClass().getClassLoader()).parseClass(new File("full_path_to/Utils.groovy")); // Otherwise it assumes current dir is $CATALINA_HOME
def foo = groovyClass.newInstance(); // ''def'' solves compile time errors!!
foo.doSth(); // Actually works!
evaluate(new File("../tools/Tools.groovy"))
Pon eso en la parte superior de tu script. Eso traerá el contenido de un archivo groovy (simplemente reemplace el nombre del archivo entre las comillas dobles con su guión maravilloso).
Hago esto con una clase sorprendentemente llamada "Tools.groovy".