Y compris un script groovy dans un autre groovy

J’ai lu comment importer simplement un fichier groovy dans un autre script groovy

Je veux définir des fonctions communes dans un fichier groovy et appeler ces fonctions à partir d’autres fichiers groovy.

Je comprends que cela utiliserait Groovy comme un langage de script, c’est-à-dire que je n’ai pas besoin de classes / d’objects. J’essaye de faire quelque chose comme dsl qui peut être fait dans groovy. Toutes les variables seront validées à partir de Java et je veux exécuter un script groovy dans un shell.

Est-ce possible ? Quelqu’un peut-il donner un exemple.

evaluate(new File("../tools/Tools.groovy")) 

Mettez cela en haut de votre script. Cela apportera le contenu d’un fichier groovy (remplacez simplement le nom du fichier entre les guillemets avec votre script groovy).

Je le fais avec une classe appelée étonnamment “Tools.groovy”.

À partir de Groovy 2.2, il est possible de déclarer une classe de script de base avec la nouvelle annotation de transformation AST @BaseScript .

Exemple:

fichier MainScript.groovy :

 abstract class MainScript extends Script { def meaningOfLife = 42 } 

fichier test.groovy :

 import groovy.transform.BaseScript @BaseScript MainScript mainScript println "$meaningOfLife" //works as expected 

Une autre façon de faire est de définir les fonctions dans une classe groovy et d’parsingr et d’append le fichier au classpath au moment de l’exécution:

 File sourceFile = new File("path_to_file.groovy"); Class groovyClass = new GroovyClassLoader(getClass().getClassLoader()).parseClass(sourceFile); GroovyObject myObject = (GroovyObject) groovyClass.newInstance(); 

Je pense que le meilleur choix est d’organiser les utilitaires sous forme de classes groovy, de les append à classpath et de laisser le script principal s’y référer via le mot-clé import.

Exemple:

scripts / DbUtils.groovy

 class DbUtils{ def save(something){...} } 

scripts / script1.groovy:

 import DbUtils def dbUtils = new DbUtils() def something = 'foobar' dbUtils.save(something) 

script en cours d’exécution:

 cd scripts groovy -cp . script1.groovy 

Groovy n’a pas de mot-clé d’importation comme les langages de script typiques qui feront un littéral inclus du contenu d’un autre fichier (mentionné ici: groovy fournit-il un mécanisme d’inclusion? ).
En raison de sa nature orientée object / classe, vous devez “jouer à des jeux” pour faire des choses comme ce travail. Une possibilité est de rendre toutes les fonctions de votre utilitaire statiques (puisque vous avez dit qu’elles n’utilisent pas d’objects), puis d’effectuer une importation statique dans le contexte de votre shell d’exécution. Ensuite, vous pouvez appeler ces méthodes comme “fonctions globales”.
Une autre possibilité consisterait à utiliser un object Binding ( http://groovy.codehaus.org/api/groovy/lang/Binding.html ) lors de la création de votre Shell et de la liaison de toutes les fonctions souhaitées aux méthodes (l’inconvénient ici serait d’avoir énumérer toutes les méthodes de la liaison, mais vous pourriez peut-être utiliser la reflection). Une autre solution serait de remplacer methodMissing(...) dans l’object delegate assigné à votre shell, ce qui vous permet de faire une dissortingbution dynamic en utilisant une carte ou la méthode de votre choix.

Plusieurs de ces méthodes sont présentées ici: http://www.nextinstruction.com/blog/2012/01/08/creating-dsls-with-groovy/ . Faites-moi savoir si vous voulez voir un exemple d’une technique particulière.

La façon dont je fais cela est avec GroovyShell .

 GroovyShell shell = new GroovyShell() def Util = shell.parse(new File('Util.groovy')) def data = Util.fetchData() 

Voici un exemple complet d’inclusion d’un script dans un autre.
Il suffit de lancer le fichier Testmain.groovy
Commentaires explicatifs inclus parce que je suis gentil comme ça;]

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(Ssortingng 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") 

Que diriez-vous de traiter le script externe comme une classe Java? Basé sur cet article: https://www.jmdawson.net/blog/2014/08/18/using-functions-from-one-groovy-script-in-another/

getThing.groovy Le script externe

 def getThingList() { return ["thing","thin2","thing3"] } 

printThing.groovy Le script principal

 thing = new getThing() // new the class which represents the external script println thing.getThingList() 

Résultat

 $ groovy printThing.groovy [thing, thin2, thing3] 

Pour les plus récents, il semble que groovy supporte maintenant la commande :load file-path qui redirige simplement les entrées du fichier donné, il est donc désormais facile d’inclure des scripts de bibliothèque.

Il fonctionne comme une entrée dans le groovysh & comme une ligne dans un fichier chargé:
groovy:000> :load file1.groovy

file1.groovy peut contenir:
:load path/to/another/file invoke_fn_from_file();

Une combinaison de réponses @grahamparks et @snowindy avec quelques modifications est ce qui a fonctionné pour mes scripts Groovy exécutés sur 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 comstack time errors!! foo.doSth(); // Actually works! 

Après quelques investigations, je suis arrivé à la conclusion que l’approche suivante semble la meilleure.

certains / sous-paquet / 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.Ssortingngs class Util { void msg(int a, Ssortingng b, Map c) { println 'Message printed by msg method inside Util.groovy' println "Print 5 asterisks using the Guava dependency ${Ssortingngs.repeat("*", 5)}" println "Arguments are a=$a, b=$b, c=$c" } } 

example.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']) 

Pour exécuter le script example.groovy , ajoutez-le à votre chemin système et tapez depuis n’importe quel répertoire:

 example.groovy 

Le 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] 

L’exemple ci-dessus a été testé dans l’environnement suivant: Groovy Version: 2.4.13 JVM: 1.8.0_151 Vendor: Oracle Corporation OS: Linux

L’exemple montre ce qui suit:

  • Comment utiliser une classe Util dans un script groovy.
  • Une classe Util qui appelle la bibliothèque tierce Guava en l’incluant comme une dépendance Grape ( @Grab('com.google.guava:guava:23.0') ).
  • La classe Util peut résider dans un sous-répertoire.
  • Passer des arguments à une méthode dans la classe Util .

Commentaires / suggestions supplémentaires:

  • Utilisez toujours une classe groovy au lieu d’un script groovy pour des fonctionnalités réutilisables dans vos scripts groovy. L’exemple ci-dessus utilise la classe Util définie dans le fichier Util.groovy. L’utilisation de scripts groovy pour des fonctionnalités réutilisables est problématique. Par exemple, si vous utilisez un script groovy, alors la classe Util devrait être instanciée au bas du script avec new Util() , mais surtout, elle devrait être placée dans un fichier nommé à part Util.groovy. Reportez-vous à Scripts et classes pour plus de détails sur les différences entre les scripts groovy et les classes groovy.
  • Dans l’exemple ci-dessus, j’utilise le chemin "${new File(getClass().protectionDomain.codeSource.location.path).parent}/some/subpackage/Util.groovy" au lieu de "some/subpackage/Util.groovy" . Cela garantira que le fichier Util.groovy sera toujours trouvé par rapport à l’emplacement du script groovy ( example.groovy ) et non au répertoire de travail actuel. Par exemple, utiliser "some/subpackage/Util.groovy" entraînerait une recherche dans WORK_DIR/some/subpackage/Util.groovy .
  • Suivez la convention de dénomination de la classe Java pour nommer vos scripts groovy. Personnellement, je préfère une petite déviation où les scripts commencent par une lettre inférieure plutôt que par une lettre majuscule. Par exemple, myScript.groovy est un nom de script et MyClass.groovy est un nom de classe. Nommer my-script.groovy entraînera des erreurs d’exécution dans certains scénarios car la classe résultante n’aura pas de nom de classe Java valide.
  • Dans le monde de la JVM en général, les fonctionnalités pertinentes sont nommées JSR 223: Scripting for the Java . Dans groovy en particulier, la fonctionnalité est appelée mécanismes d’intégration Groovy . En fait, la même approche peut être utilisée pour appeler n’importe quel langage JVM depuis Groovy ou Java. Groovy, Java, Scala, JRuby et JavaScript (Rhino) en sont des exemples notables.