Włączenie groovy script do innego groovy


97

Przeczytałem, jak po prostu zaimportować groovy plik do innego groovy skryptu

Chcę zdefiniować wspólne funkcje w jednym pliku groovy i wywołać te funkcje z innych plików groovy.

Rozumiem, że byłoby to używanie Groovy jako języka skryptowego, tj. Nie potrzebuję klas / obiektów. Próbuję czegoś takiego jak dsl, które można zrobić w groovy. Wszystkie zmienne zostaną potwierdzone z Javy i chcę wykonać groovy skrypt w powłoce.

Czy to w ogóle możliwe? Czy ktoś może podać jakiś przykład.


Odpowiedzi:


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

Umieść to na początku swojego skryptu. Spowoduje to wyświetlenie zawartości groovy pliku (po prostu zastąp nazwę pliku między podwójnymi cudzysłowami swoim groovym skryptem).

Robię to z klasą o zadziwiającej nazwie „Tools.groovy”.


7
Aby to zadziałało, nazwa pliku musi być zgodna z regułami nazewnictwa klas Javy.
— willkil

2
Pytanie - Jak mogę przekazać argumenty do skryptu, który oceniam, używając tej składni?
— Steve

3
@steve Nie możesz, ale możesz zdefiniować w tym skrypcie funkcję, którą wywołujesz z argumentami
— Nilzor,

11
To nie działa ... skrypt jest dobrze oceniany, ale nie ma deklaracji w zakresie wywołującego (def, class itp.)
— LoganMzz

3
Musisz zwrócić obiekt z wywołania pierwszego, a następnie przypisać wynik oceny do zmiennej.
— LoganMzz

45

Począwszy od Groovy 2.2 możliwe jest zadeklarowanie podstawowej klasy skryptu z nową @BaseScriptadnotacją transformacji AST.

Przykład:

plik MainScript.groovy :

abstract class MainScript extends Script {
    def meaningOfLife = 42
}

plik test.groovy :

import groovy.transform.BaseScript
@BaseScript MainScript mainScript

println "$meaningOfLife" //works as expected

1
Podczas korzystania z tej metody wciąż pojawia się komunikat „nie można rozwiązać klasy”. Co byś polecił mi zrobić? Czy istnieje sposób na zaimportowanie niestandardowych klas do innego świetnego skryptu?
— droidnoob

38

Innym sposobem na to jest zdefiniowanie funkcji w groovy klasy i przeanalizowanie i dodanie pliku do ścieżki klas w czasie wykonywania:

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

3
To rozwiązanie faktycznie działało najlepiej dla mnie. Kiedy próbowałem użyć zaakceptowanej odpowiedzi, pojawił się błąd informujący, że mój główny skrypt groovy nie był w stanie rozwiązać klasy zdefiniowanej w ocenianym skrypcie. Na co warto ...
— cBlaine

1
Wypróbowałem kilka różnych podejść, które zostały opublikowane w SO i tylko to zadziałało. Inni zgłaszali błędy dotyczące niemożności rozwiązania klasy lub metod. To jest wersja, której używam Wersja Groovy Wersja: 2.2.2 JVM: 1.8.0 Dostawca: Oracle Corporation System operacyjny: Windows 7.
— Kuberchaun

1
To działało świetnie. Pamiętaj, aby użyć GroovyObjectjawnie, to nie jest symbol zastępczy dla własnej nazwy klasy.
— sprawdziłem

1
Nadal dostaję: java.lang.NoClassDefFoundError: groovy.lang.GroovyObject
— dokaspar

Oszczędza życie. Dzięki, stary!!
— Anjana Silva

30

Myślę, że najlepszym wyborem jest zorganizowanie rzeczy użytkowych w formie groovy, dodanie ich do ścieżki klas i pozwolenie głównemu skryptowi odwoływać się do nich poprzez słowo kluczowe import.

Przykład:

scripts / DbUtils.groovy

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

scripts / script1.groovy:

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

uruchomiony skrypt:

cd scripts
groovy -cp . script1.groovy

Zastanawiam się, jak by to działało, gdybyś miał strukturę katalogów, taką jak libi srckatalogi
— Gi0rgi0s

9

Sposób, w jaki to robię, jest GroovyShell.

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

7

Groovy nie ma słowa kluczowego importu, takiego jak typowe języki skryptowe, które będą dosłownie włączać zawartość innego pliku (nawiązanie do tego: Czy groovy zapewnia mechanizm włączania? ).
Ze względu na jego obiektową / klasową naturę, musisz „grać w gry”, aby takie rzeczy działały. Jedną z możliwości jest uczynienie wszystkich funkcji narzędziowych statycznymi (ponieważ powiedziałeś, że nie używają one obiektów), a następnie wykonanie statycznego importu w kontekście wykonywanej powłoki. Następnie możesz nazwać te metody „funkcjami globalnymi”.
Inną możliwością byłoby użycie obiektu Binding ( http://groovy.codehaus.org/api/groovy/lang/Binding.html) podczas tworzenia powłoki i wiązania wszystkich funkcji, które chcesz, z metodami (minusem byłoby tutaj wyliczenie wszystkich metod w powiązaniu, ale być może możesz użyć odbicia). Jeszcze innym rozwiązaniem byłoby nadpisaniemethodMissing(...) w obiekcie delegata przypisanym do twojej powłoki, który pozwala w zasadzie na dynamiczne wysyłanie przy użyciu mapy lub dowolnej metody.

Kilka z tych metod przedstawiono tutaj: http://www.nextinstruction.com/blog/2012/01/08/creating-dsls-with-groovy/ . Daj mi znać, jeśli chcesz zobaczyć przykład konkretnej techniki.


7
ten link jest teraz martwy
— Nicolas Mommaerts


6

Oto kompletny przykład włączenia jednego skryptu do drugiego.
Po prostu uruchom plik Testmain.groovy Dołączone
komentarze wyjaśniające, ponieważ jestem taki miły;]

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

Dla spóźnionych wygląda na to, że groovy teraz obsługują :load file-pathpolecenie, które po prostu przekierowuje dane wejściowe z danego pliku, więc teraz trywialne jest dołączanie skryptów bibliotecznych.

Działa jako wejście do groovysh & jako linia w załadowanym pliku:
groovy:000> :load file1.groovy

plik1.groovy może zawierać:
:load path/to/another/file invoke_fn_from_file();


Czy możesz to rozwinąć, proszę? Gdzie to jest w dokumentacji? Gdzie mam umieścić :load file-path?
— Christoffer Hammarström

Cóż, działa jako wejście do groovysh & jako linia w załadowanym pliku: <br/> groovy:000> :load file1.groovy plik1.groovy może zawierać: <br/>:load path/to/another/file
— Jack Punt.

1
Znalazłem ładunek w dokumentach . Jeśli dobrze rozumiem, działa tylko z groovyshem?
— Christoffer Hammarström

Nie zadziała to jednak ze ścieżką zdefiniowaną w zmiennej, prawda?
— user2173353

0

Połączenie odpowiedzi @grahamparks i @snowindy z kilkoma modyfikacjami sprawdziło się w przypadku moich skryptów Groovy działających na 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!

Otrzymuję: java.lang.NoClassDefFoundError: groovy.lang.GroovyObject
— dokaspar

0

Groovy może importować inne groovy klasy, dokładnie tak, jak robi to Java. Upewnij się tylko, że rozszerzenie pliku biblioteki to .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

Po pewnym dochodzeniu doszedłem do wniosku, że następujące podejście wydaje się najlepsze.

jakiś / 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'])

Aby uruchomić example.groovyskrypt, dodaj go do ścieżki systemowej i wpisz z dowolnego katalogu:

example.groovy

Skrypt drukuje:

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]

Powyższy przykład został przetestowany w następującym środowisku: Groovy Version: 2.4.13 JVM: 1.8.0_151 Vendor: Oracle Corporation OS: Linux

Przykład pokazuje, co następuje:

  • Jak korzystać z Util klasy w świetnym skrypcie.
  • UtilKlasa wywołanie Guavabiblioteki strony trzeciej, włączając go jako Grapezależność ( @Grab('com.google.guava:guava:23.0')).
  • UtilKlasy mogą znajdować się w podkatalogu.
  • Przekazywanie argumentów do metody w Utilklasie.

Dodatkowe uwagi / sugestie:

  • Zawsze używaj groovy class zamiast groovy script do wielokrotnego użytku w swoich groovy scripts. W powyższym przykładzie użyto klasy Util zdefiniowanej w pliku Util.groovy. Używanie groovy skryptów do wielokrotnego użytku jest problematyczne. Na przykład, jeśli używasz groovy script, to klasa Util musiałaby zostać utworzona na dole skryptu z new Util(), ale co najważniejsze, musiałaby zostać umieszczona w pliku o nazwie cokolwiek innego niż Util.groovy. Zobacz Skrypty a klasy , aby uzyskać więcej informacji na temat różnic między porywające skryptów i klas porywające.
  • W powyższym przykładzie używam ścieżki "${new File(getClass().protectionDomain.codeSource.location.path).parent}/some/subpackage/Util.groovy"zamiast "some/subpackage/Util.groovy". Gwarantuje to, że Util.groovyplik będzie zawsze znajdowany w odniesieniu do lokalizacji skryptu groovy ( example.groovy), a nie do bieżącego katalogu roboczego. Na przykład użycie "some/subpackage/Util.groovy"spowoduje wyszukanie w WORK_DIR/some/subpackage/Util.groovy.
  • Postępuj zgodnie z konwencją nazewnictwa klas Java, aby nazywać swoje świetne skrypty. Osobiście wolę małe odchylenie, w którym skrypty zaczynają się od małej litery zamiast dużej. Na przykład myScript.groovyto nazwa skryptu, a MyClass.groovyto nazwa klasy. Nazewnictwo my-script.groovyspowoduje błędy w czasie wykonywania w niektórych scenariuszach, ponieważ wynikowa klasa nie będzie miała prawidłowej nazwy klasy Java.
  • W świecie JVM ogólnie odpowiednia funkcjonalność nosi nazwę JSR 223: Scripting for the Java . Szczególnie groovy funkcjonalność nazywa się mechanizmami integracji Groovy . W rzeczywistości to samo podejście można zastosować w celu wywołania dowolnego języka JVM z poziomu Groovy lub Java. Niektóre godne uwagi przykłady takich języków JVM to Groovy, Java, Scala, JRuby i JavaScript (Rhino).
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.