Inclusa una sceneggiatura fantastica in un'altra fantastica


97

Ho letto come importare semplicemente un file groovy in un altro script groovy

Voglio definire funzioni comuni in un file groovy e chiamare quelle funzioni da altri file groovy.

Capisco che questo userebbe Groovy come un linguaggio di scripting, cioè non ho bisogno di classi / oggetti. Sto cercando di fare qualcosa come dsl che può essere fatto in groovy. Tutte le variabili verranno affermate da Java e voglio eseguire script groovy in una shell.

Ciò è effettivamente possibile ? Qualcuno può fornire qualche esempio.


2
possibile duplicato di Load script from groovy script
tim_yates

Risposte:


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

Mettilo all'inizio del copione. Ciò porterà il contenuto di un file groovy (basta sostituire il nome del file tra virgolette doppie con il tuo script groovy).

Lo faccio con una classe sorprendentemente chiamata "Tools.groovy".


7
Il nome del file deve essere conforme alle regole di denominazione delle classi di Java affinché funzioni.
willkil

2
Domanda: come posso passare argomenti allo script che sto valutando utilizzando questa sintassi?
Steve

3
@steve Non puoi, ma puoi definire una funzione in quello script che chiami con argomenti
Nilzor

11
Non funziona ... lo script è ben valutato ma non esiste alcuna dichiarazione nell'ambito del chiamante (def, class, ecc.)
LoganMzz

3
È necessario restituire un oggetto dalla chiamata uno, quindi assegnare il risultato di valutazione a una variabile.
LoganMzz

45

A partire da Groovy 2.2 è possibile dichiarare una classe di script di base con la nuova @BaseScriptannotazione di trasformazione AST.

Esempio:

file MainScript.groovy :

abstract class MainScript extends Script {
    def meaningOfLife = 42
}

file test.groovy :

import groovy.transform.BaseScript
@BaseScript MainScript mainScript

println "$meaningOfLife" //works as expected

1
Continuo a essere "incapace di risolvere la classe" quando utilizzo questo metodo. Cosa mi consiglieresti di fare? C'è un modo per importare classi personalizzate in un altro script fantastico?
droidnoob

38

Un altro modo per farlo è definire le funzioni in una classe groovy e analizzare e aggiungere il file al classpath in fase di runtime:

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

2
Questa soluzione in realtà ha funzionato meglio per me. Quando ho provato a utilizzare la risposta accettata, ho ricevuto un errore che diceva che il mio script groovy principale non era in grado di risolvere la classe definita nello script valutato. Per quello che vale ...
cBlaine

1
Ho provato diversi approcci diversi che sono stati pubblicati su SO e solo questo ha funzionato. Gli altri hanno lanciato errori di non essere in grado di risolvere la classe oi metodi. Questa è la versione che sto utilizzando Versione Groovy: 2.2.2 JVM: 1.8.0 Fornitore: Oracle Corporation OS: Windows 7.
Kuberchaun

Funzionava benissimo. Assicurati di usare GroovyObjectesplicitamente, non è un segnaposto per il nome della tua classe.
controllato il

1
Ancora ottengo: java.lang.NoClassDefFoundError: groovy.lang.GroovyObject
dokaspar

Salvavita. Grazie amico!!
Anjana Silva

30

Penso che la scelta migliore sia organizzare le cose di utilità in forma di classi groovy, aggiungerle a classpath e lasciare che lo script principale vi faccia riferimento tramite la parola chiave import.

Esempio:

scripts / DbUtils.groovy

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

scripts / script1.groovy:

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

script in esecuzione:

cd scripts
groovy -cp . script1.groovy

Mi chiedo come funzionerebbe se avessi una struttura di directory come con libe srcdirectory
Gi0rgi0s

9

Il modo in cui lo faccio è con GroovyShell.

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

6

Groovy non ha una parola chiave di importazione come i tipici linguaggi di scripting che faranno un'inclusione letterale del contenuto di un altro file (alluso qui: groovy fornisce un meccanismo di inclusione? ).
A causa della sua natura orientata agli oggetti / alle classi, devi "giocare" per far funzionare cose come questa. Una possibilità è rendere statiche tutte le funzioni di utilità (poiché hai detto che non usano oggetti) e quindi eseguire un'importazione statica nel contesto della shell in esecuzione. Quindi puoi chiamare questi metodi come "funzioni globali".
Un'altra possibilità sarebbe usare un oggetto Binding ( http://groovy.codehaus.org/api/groovy/lang/Binding.html) mentre crei la tua Shell e associ tutte le funzioni che desideri ai metodi (lo svantaggio qui sarebbe dover enumerare tutti i metodi nel binding, ma potresti forse usare la reflection). Un'altra soluzione potrebbe essere quella di sovrascrivere methodMissing(...)l'oggetto delegato assegnato alla tua shell che ti consente di eseguire fondamentalmente l'invio dinamico utilizzando una mappa o qualsiasi metodo desideri.

Molti di questi metodi sono dimostrati qui: http://www.nextinstruction.com/blog/2012/01/08/creating-dsls-with-groovy/ . Fammi sapere se vuoi vedere un esempio di una tecnica particolare.


7
questo collegamento è ora morto
Nicolas Mommaerts


5

Ecco un esempio completo dell'inclusione di uno script all'interno di un altro.
Basta eseguire il file Testmain.groovy
Commenti esplicativi inclusi perché sono simpatico così;]

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

0

Per i ritardatari, sembra che groovy ora supporti il :load file-pathcomando che reindirizza semplicemente l'input dal file dato, quindi ora è banale includere gli script di libreria.

Funziona come input per groovysh e come riga in un file caricato:
groovy:000> :load file1.groovy

file1.groovy può contenere:
:load path/to/another/file invoke_fn_from_file();


Puoi approfondire questo argomento per favore? Dov'è questo nei documenti? Dove lo metto :load file-path?
Christoffer Hammarström

Bene, funziona come input per groovysh e come riga in un file caricato: <br/> groovy:000> :load file1.groovy file1.groovy può contenere: <br/>:load path/to/another/file
Jack Punt

1
Ho trovato carico nei documenti . Se ho capito bene, funziona solo con groovysh?
Christoffer Hammarström

Tuttavia, questo non funzionerà con il percorso definito all'interno di una variabile, no?
user2173353

0

Una combinazione di risposte @grahamparks e @snowindy con un paio di modifiche è ciò che ha funzionato per i miei script Groovy in esecuzione su 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!

Ottengo: java.lang.NoClassDefFoundError: groovy.lang.GroovyObject
dokaspar

0

Groovy può importare altre classi groovy esattamente come fa Java. Assicurati solo che l'estensione del file della libreria sia .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

-1

Dopo alcune indagini sono giunto alla conclusione che il seguente approccio sembra il migliore.

alcuni / 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"
    }
}

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

Per eseguire lo example.groovyscript, aggiungilo al percorso di sistema e digita da qualsiasi directory:

example.groovy

Lo script stampa:

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'esempio precedente è stato testato nel seguente ambiente: Groovy Version: 2.4.13 JVM: 1.8.0_151 Vendor: Oracle Corporation OS: Linux

L'esempio mostra quanto segue:

  • Come utilizzare un file Util classe all'interno di uno script groovy.
  • Una Utilclasse che chiama la Guavalibreria di terze parti includendola come Grapedipendenza ( @Grab('com.google.guava:guava:23.0')).
  • La Utilclasse può risiedere in una sottodirectory.
  • Passaggio di argomenti a un metodo all'interno della Utilclasse.

Commenti / suggerimenti aggiuntivi:

  • Usa sempre una classe groovy invece di script groovy per funzionalità riutilizzabili all'interno dei tuoi script groovy. L'esempio precedente utilizza la classe Util definita nel file Util.groovy. L'utilizzo di script groovy per funzionalità riutilizzabili è problematico. Ad esempio, se si utilizza uno script groovy, la classe Util dovrebbe essere istanziata nella parte inferiore dello script con new Util(), ma soprattutto dovrebbe essere collocata in un file denominato in modo diverso da Util.groovy. Fare riferimento a Script e classi per maggiori dettagli sulle differenze tra script groovy e classi groovy.
  • Nell'esempio sopra, utilizzo il percorso "${new File(getClass().protectionDomain.codeSource.location.path).parent}/some/subpackage/Util.groovy"invece di "some/subpackage/Util.groovy". Ciò garantirà che il Util.groovyfile verrà sempre trovato in relazione alla posizione dello script groovy ( example.groovy) e non alla directory di lavoro corrente. Ad esempio, l'utilizzo "some/subpackage/Util.groovy"comporterebbe la ricerca in WORK_DIR/some/subpackage/Util.groovy.
  • Segui la convenzione di denominazione delle classi Java per assegnare un nome ai tuoi fantastici script. Personalmente preferisco una piccola deviazione in cui gli script iniziano con una lettera minuscola invece di una maiuscola. Ad esempio, myScript.groovyè un nome di script ed MyClass.groovyè un nome di classe. La denominazione my-script.groovycomporterà errori di runtime in determinati scenari poiché la classe risultante non avrà un nome di classe Java valido.
  • Nel mondo JVM in generale la funzionalità rilevante è denominata JSR 223: Scripting for the Java . In groovy in particolare la funzionalità è chiamata meccanismi di integrazione Groovy . In effetti, lo stesso approccio può essere utilizzato per chiamare qualsiasi linguaggio JVM da Groovy o Java. Alcuni esempi notevoli di tali linguaggi JVM sono Groovy, Java, Scala, JRuby e JavaScript (Rhino).
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.