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.