Inclure un script groovy dans un autre groovy

97

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 / objets. J'essaye quelque chose comme le DSL qui peut être fait dans groovy. Toutes les variables seront affirmé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.

Kannan Ekanath
la source
2
duplication possible du script
tim_yates

Réponses:

107
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 doubles par votre script groovy).

Je fais cela avec une classe appelée étonnamment "Tools.groovy".

jmq
la source
7
Le nom de fichier doit être conforme aux règles de dénomination de classe de Java pour que cela fonctionne.
willkil
2
Question - Comment puis-je transmettre des arguments au script que j'évalue à l'aide de cette syntaxe?
Steve
3
@steve Vous ne pouvez pas, mais vous pouvez définir une fonction dans ce script que vous appelez avec des arguments
Nilzor
11
Cela ne fonctionne pas ... le script est bien évalué mais aucune déclaration n'existe dans la portée de l'appelant (def, classe, etc.)
LoganMzz
3
Vous devez renvoyer un objet à partir de l'appel un, puis affecter le résultat de l'évaluation à une variable.
LoganMzz
45

Depuis Groovy 2.2, il est possible de déclarer une classe de script de base avec la nouvelle @BaseScriptannotation de transformation AST.

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
emesx
la source
1
J'obtiens toujours "incapable de résoudre la classe" lorsque j'utilise cette méthode. Que recommanderiez-vous que je fasse? Existe-t-il un moyen d'importer des classes personnalisées dans un autre script groovy?
droidnoob
38

Une autre façon de faire est de définir les fonctions dans une classe groovy et d'analyser et d'ajouter le fichier au chemin de classe 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();
Grahamparks
la source
3
Cette solution fonctionnait le mieux pour moi. Lorsque j'ai essayé d'utiliser la réponse acceptée, j'ai eu une erreur disant que mon script groovy principal était incapable de résoudre la classe définie dans le script évalué. Pour ce que ça vaut ...
cBlaine
1
J'ai essayé plusieurs approches différentes publiées sur SO et seule cela a fonctionné. Les autres ont émis des erreurs sur l'impossibilité de résoudre la classe ou les méthodes. Ceci est la version que j'utilise version Groovy Version: 2.2.2 JVM: 1.8.0 Fournisseur: Oracle Corporation OS: Windows 7.
Kuberchaun
1
Cela a très bien fonctionné. Veillez à utiliser GroovyObjectexplicitement, ce n'est pas un espace réservé pour votre propre nom de classe.
vérifié
1
Je reçois toujours: java.lang.NoClassDefFoundError: groovy.lang.GroovyObject
dokaspar
Sauveur de vie. Merci mon pote!!
Anjana Silva
30

Je pense que le meilleur choix est d'organiser les choses utilitaires sous forme de classes groovy, de les ajouter au classpath et de laisser le script principal s'y référer via un mot-clé d'importation.

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
enneigé
la source
Je me demande comment cela fonctionnerait si vous aviez une structure de répertoires comme avec libet les srcrépertoires
Gi0rgi0s
9

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()
Mikedave
la source
7

Groovy n'a pas de mot-clé d'importation comme les langages de script typiques qui feront une inclusion littérale du contenu d'un autre fichier (auquel il est fait allusion ici: Groovy fournit-il un mécanisme d'inclusion? ).
En raison de sa nature orientée objet / classe, vous devez «jouer à des jeux» pour faire fonctionner des choses comme celles-ci. Une possibilité est de rendre toutes vos fonctions utilitaires statiques (puisque vous avez dit qu'elles n'utilisent pas d'objets) et ensuite d'effectuer une importation statique dans le contexte de votre shell en cours d'exécution. Ensuite, vous pouvez appeler ces méthodes comme "fonctions globales".
Une autre possibilité serait d'utiliser un objet 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 que vous souhaitez aux méthodes (l'inconvénient ici serait de devoir énumérer toutes les méthodes de la liaison, mais vous pourriez peut-être utiliser la réflexion). Une autre solution serait de remplacer methodMissing(...)l'objet délégué attribué à votre shell, ce qui vous permet essentiellement de faire une répartition dynamique à l'aide d'une carte ou de 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 souhaitez voir un exemple d'une technique particulière.

omnisis
la source
7
ce lien est maintenant mort
Nicolas Mommaerts
6

Voici un exemple complet d'inclusion d'un script dans un autre.
Il suffit de lancer le fichier Testmain.groovy.
Commentaires explicatifs inclus car 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(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")
Davidfrancis
la source
0

Pour les retardataires, il semble que groovy supporte désormais la :load file-pathcommande qui redirige simplement l'entrée du fichier donné, il est donc désormais trivial d'inclure des scripts de bibliothèque.

Cela fonctionne comme une entrée dans le groovysh et 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();

Jack Punt
la source
Pouvez-vous développer cela s'il vous plaît? Où est-ce dans la documentation? Où dois-je mettre :load file-path?
Christoffer Hammarström
Eh bien, cela fonctionne comme une entrée dans le groovysh et comme une ligne dans un fichier chargé: <br/> groovy:000> :load file1.groovy file1.groovy peut contenir: <br/>:load path/to/another/file
Jack Punt
1
J'ai trouvé la charge dans les documents . Si je comprends bien, cela ne fonctionne qu'avec groovysh?
Christoffer Hammarström
Cela ne fonctionnera pas avec le chemin défini dans une variable, n'est-ce pas?
user2173353
0

Une combinaison de réponses @grahamparks et @snowindy avec quelques modifications est ce qui a fonctionné pour mes scripts Groovy fonctionnant 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 compile time errors!!
foo.doSth(); // Actually works!
Sergio Muriel
la source
J'obtiens: java.lang.NoClassDefFoundError: groovy.lang.GroovyObject
dokaspar
0

Groovy peut importer d'autres classes groovy exactement comme le fait Java. Assurez-vous simplement que l'extension du fichier de bibliothèque est .groovy.

    $ cat lib/Lib.groovy
    package lib
    class Lib {
       static saySomething() { println 'something' }
       def sum(a,b) { a+b }
    }

    $ cat app.gvy
    import lib.Lib
    Lib.saySomething();
    println new Lib().sum(37,5)

    $ groovy app
    something
    42
miles zarathoustra
la source
-1

Après quelques recherches, je suis arrivé à la conclusion que l'approche suivante me semble la meilleure.

certains / subpackage / 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"
    }
}

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

Afin d'exécuter le example.groovyscript, ajoutez-le à votre chemin système et tapez à partir de 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 Utilclasse dans un script groovy.
  • Une Utilclasse appelant la Guavabibliothèque tierce en l'incluant en tant que Grapedépendance ( @Grab('com.google.guava:guava:23.0')).
  • La Utilclasse peut résider dans un sous-répertoire.
  • Passer des arguments à une méthode dans la Utilclasse.

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, la classe Util devra être instanciée au bas du script avec new Util(), mais surtout, elle devra être placée dans un fichier nommé autre chose que Util.groovy. Reportez-vous à Scripts versus 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 Util.groovyfichier 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 sur WORK_DIR/some/subpackage/Util.groovy.
  • Suivez la convention de dénomination des classes Java pour nommer vos scripts groovy. Personnellement, je préfère une petite déviation où les scripts commencent par une lettre inférieure au lieu d'une majuscule. Par exemple, myScript.groovyest un nom de script et MyClass.groovyest un nom de classe. La dénomination my-script.groovyentraî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 JVM en général, la fonctionnalité pertinente est appelée 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. Quelques exemples notables de ces langages JVM sont Groovy, Java, Scala, JRuby et JavaScript (Rhino).
Georgios F.
la source