Включая groovy script в другой groovy

Я прочитал как просто импортировать файл groovy в другой groovy script

Я хочу определить общие функции в одном файле groovy и вызывать эти функции из других файлов groovy.

Я понимаю, что это будет использовать groovy как язык сценариев. i.e, мне не нужны классы/объекты. Я пытаюсь что-то вроде dsl, которое можно сделать в groovy. Все переменные будут утверждаться с Java, и я хочу выполнить groovy script в оболочке.

Возможно ли это вообще? Может ли кто-нибудь привести пример.

Ответ 1

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

Поместите это вверху вашего script. Это приведет к содержимому файла groovy (просто замените имя файла между двойными кавычками на groovy script).

Я делаю это с классом, на удивление называемым "Tools.groovy".

Ответ 2

Как и в случае с Groovy 2.2, можно объявить базовый класс script с новой аннотацией трансформации @BaseScript AST.

Пример:

файл MainScript.groovy:

abstract class MainScript extends Script {
    def meaningOfLife = 42
}

файл test.groovy:

import groovy.transform.BaseScript
@BaseScript MainScript mainScript

println "$meaningOfLife" //works as expected

Ответ 3

Другой способ сделать это - определить функции класса groovy и проанализировать и добавить файл в путь к классам во время выполнения:

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

Ответ 4

Я думаю, что лучший выбор - организовать полезные вещи в виде классов groovy, добавить их в путь к классам и позволить main script ссылаться на них через ключевое слово import.

Пример:

Сценарии/DbUtils.groovy

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

скрипты/script1.groovy:

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

работает script:

cd scripts
groovy -cp . script1.groovy

Ответ 5

Groovy не имеет ключевого слова импорта, например, типичные языки сценариев, которые будут делать литерал, включающий другое содержимое файла (здесь указано: Предоставляет ли groovy механизм включения?).
Из-за своей природы, ориентированной на объект/класс, вы должны "играть в игры", чтобы сделать такие вещи, как эта работа. Одна из возможностей - сделать все ваши служебные функции статическими (поскольку вы сказали, что они не используют объекты), а затем выполнить статический импорт в контексте вашей исполняемой оболочки. Затем вы можете назвать эти методы "глобальными функциями".
Еще одна возможность - использовать объект Binding (http://groovy.codehaus.org/api/groovy/lang/Binding.html) при создании вашей оболочки и привязывать все функции, которые вы хотите к методам (недостатком здесь было бы перечислить все методы привязки, но вы могли бы использовать отражение). Еще одним решением было бы переопределить methodMissing(...) в объекте делегирования, назначенного вашей оболочке, что позволит вам в основном выполнять динамическую отправку с использованием карты или любого другого метода, который вам нужен.

Несколько из этих методов показаны здесь: http://www.nextinstruction.com/blog/2012/01/08/creating-dsls-with-groovy/. Дайте мне знать, если вы хотите увидеть пример конкретной техники.

Ответ 6

Для поздних пользователей, кажется, что groovy теперь поддерживает команду :load file-path, которая просто перенаправляет ввод из данного файла, поэтому теперь тривиально включать скрипты библиотеки.

Он работает как вход для groovysh и как строка в загруженном файле:
groovy:000> :load file1.groovy

file1.groovy может содержать:
:load path/to/another/file invoke_fn_from_file();

Ответ 7

Способ, которым я это делаю, - GroovyShell.

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

Ответ 8

Комбинация @grahamparks и @snowindy ответов с несколькими модификациями - это то, что сработало для моих сценариев Groovy, работающих на 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!

Ответ 9

После некоторого исследования я пришел к выводу, что следующий подход кажется лучшим.

некоторые/подпакет/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'])

Чтобы запустить example.groovy script, добавьте его в свой системный путь и введите из любого каталога:

example.groovy

script печатает:

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]

Приведенный выше пример был протестирован в следующей среде: Groovy Version: 2.4.13 JVM: 1.8.0_151 Vendor: Oracle Corporation OS: Linux

Пример демонстрирует следующее:

  • Как использовать класс Util внутри groovy script.
  • Класс Util, вызывающий библиотеку сторонних разработчиков Guava, включив его как зависимость Grape (@Grab('com.google.guava:guava:23.0')).
  • Класс Util может находиться в подкаталоге.
  • Передача аргументов методу в классе Util.

Дополнительные комментарии/предложения:

  • Всегда используйте класс groovy вместо groovy script для повторного использования в ваших сценариях groovy. В приведенном выше примере используется класс Util, определенный в файле Util.groovy. Использование groovy скриптов для многоразовой функциональности проблематично. Например, если использовать groovy script, тогда класс Util должен быть создан в нижней части script с помощью new Util(), но, самое главное, его нужно будет поместить в файл с именем ничего, кроме Util.groovy. Обратитесь к Сценарии и классы для получения более подробной информации о различиях между groovy скриптами и groovy классами.
  • В приведенном выше примере я использую путь "${new File(getClass().protectionDomain.codeSource.location.path).parent}/some/subpackage/Util.groovy" вместо "some/subpackage/Util.groovy". Это гарантирует, что файл Util.groovy всегда будет найден в отношении местоположения groovy script (example.groovy), а не текущего рабочего каталога. Например, использование "some/subpackage/Util.groovy" приведет к поиску в WORK_DIR/some/subpackage/Util.groovy.
  • Следуйте правилам именования классов Java, чтобы назвать ваши сценарии groovy. Я лично предпочитаю небольшое отклонение, когда сценарии начинаются с более низкой буквы вместо столичной. Например, myScript.groovy - это имя script, а MyClass.groovy - имя класса. Именование my-script.groovy приведет к ошибкам во время выполнения в определенных сценариях, потому что результирующий класс не будет иметь допустимого имени класса Java.
  • В мире JVM в целом соответствующая функциональность называется JSR 223: сценарии для Java. В groovy в частности функциональность называется Groovy механизмы интеграции. Фактически, тот же подход можно использовать для вызова любого JVM-языка из groovy или Java. Некоторыми заметными примерами таких языков JVM являются Groovy, Java, Scala, JRuby и JavaScript (Rhino).