Включая 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).