다른 그루비에 그루비 스크립트 포함
다른 groovy 스크립트에서 groovy 파일을 가져 오는 방법을 읽었습니다.
하나의 그루비 파일에 공통 함수를 정의하고 다른 그루비 파일에서 해당 함수를 호출하고 싶습니다.
나는 이것이 스크립팅 언어처럼 Groovy를 사용한다는 것을 이해합니다. 즉, 클래스 / 객체가 필요하지 않습니다. 나는 그루비에서 할 수있는 dsl과 같은 것을 시도하고 있습니다. 모든 변수는 Java에서 어설 션되며 쉘에서 그루비 스크립트를 실행하고 싶습니다.
이것이 가능합니까? 누군가가 몇 가지 예를 제공 할 수 있습니까?
evaluate(new File("../tools/Tools.groovy"))
그것을 스크립트 맨 위에 놓으십시오. 그러면 그루비 파일의 내용이 표시됩니다 (큰 따옴표 사이의 파일 이름을 그루비 스크립트로 바꾸면됩니다).
놀랍게도 "Tools.groovy"라는 클래스로이 작업을 수행합니다.
Groovy 2.2부터는 새로운 @BaseScriptAST 변환 주석을 사용하여 기본 스크립트 클래스를 선언 할 수 있습니다 .
예:
MainScript.groovy 파일 :
abstract class MainScript extends Script {
def meaningOfLife = 42
}
test.groovy 파일 :
import groovy.transform.BaseScript
@BaseScript MainScript mainScript
println "$meaningOfLife" //works as expected
이를 수행하는 또 다른 방법은 그루비 클래스에서 함수를 정의하고 런타임에 파일을 구문 분석하고 클래스 경로에 추가하는 것입니다.
File sourceFile = new File("path_to_file.groovy");
Class groovyClass = new GroovyClassLoader(getClass().getClassLoader()).parseClass(sourceFile);
GroovyObject myObject = (GroovyObject) groovyClass.newInstance();
최선의 선택은 그루비 클래스의 형태로 유틸리티를 구성하고, 클래스 경로에 추가하고, 메인 스크립트가 import 키워드를 통해 참조하도록하는 것입니다.
예:
scripts / DbUtils.groovy
class DbUtils{
def save(something){...}
}
scripts / script1.groovy :
import DbUtils
def dbUtils = new DbUtils()
def something = 'foobar'
dbUtils.save(something)
실행 스크립트 :
cd scripts
groovy -cp . script1.groovy
이 작업을 수행하는 방법은 GroovyShell.
GroovyShell shell = new GroovyShell()
def Util = shell.parse(new File('Util.groovy'))
def data = Util.fetchData()
Groovy doesn't have an import keyword like typical scripting languages that will do a literal include of another file's contents (alluded to here: Does groovy provide an include mechanism?).
Because of its object/class oriented nature, you have to "play games" to make things like this work. One possibility is to make all your utility functions static (since you said they don't use objects) and then perform a static import in the context of your executing shell. Then you can call these methods like "global functions".
Another possibility would be using a Binding object (http://groovy.codehaus.org/api/groovy/lang/Binding.html) while creating your Shell and binding all the functions you want to the methods (the downside here would be having to enumerate all methods in the binding but you could perhaps use reflection). Yet another solution would be to override methodMissing(...) in the delegate object assigned to your shell which allows you to basically do dynamic dispatch using a map or whatever method you'd like.
Several of these methods are demonstrated here: http://www.nextinstruction.com/blog/2012/01/08/creating-dsls-with-groovy/. Let me know if you want to see an example of a particular technique.
Here's a complete example of including one script within another.
Just run the Testmain.groovy file
Explanatory comments included because I'm nice like that ;]
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")
How about treat the external script as a Java class? Based on this article: https://www.jmdawson.net/blog/2014/08/18/using-functions-from-one-groovy-script-in-another/
getThing.groovy The external script
def getThingList() {
return ["thing","thin2","thing3"]
}
printThing.groovy The main script
thing = new getThing() // new the class which represents the external script
println thing.getThingList()
Result
$ groovy printThing.groovy
[thing, thin2, thing3]
For late-comers, it appears that groovy now support the :load file-path command which simply redirects input from the given file, so it is now trivial to include library scripts.
It works as input to the groovysh & as a line in a loaded file:
groovy:000> :load file1.groovy
file1.groovy can contain:
:load path/to/another/file invoke_fn_from_file();
A combination of @grahamparks and @snowindy answers with a couple of modifications is what worked for my Groovy scripts running on 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!
Groovy can import other groovy classes exactly like Java does. Just be sure the extension of the library file is .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
After some investigation I have come to the conclusion that the following approach seems the best.
some/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'])
In order to run the example.groovy script, add it to your system path and type from any directory:
example.groovy
The script prints:
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]
The above example was tested in the following environment: Groovy Version: 2.4.13 JVM: 1.8.0_151 Vendor: Oracle Corporation OS: Linux
The example demonstrates the following:
- How to use a
Utilclass inside a groovy script. - A
Utilclass calling theGuavathird party library by including it as aGrapedependency (@Grab('com.google.guava:guava:23.0')). - The
Utilclass can reside in a subdirectory. - Passing arguments to a method within the
Utilclass.
Additional comments/suggestions:
- Always use a groovy class instead of groovy script for reusable functionality within your groovy scripts. The above example uses the Util class defined in the Util.groovy file. Using groovy scripts for reusable functionality is problematic. For example, if using a groovy script then the Util class would have to be instantiated at the bottom of the script with
new Util(), but most importantly it would have to be placed in a file named anything but Util.groovy. Refer to Scripts versus classes for more details about the differences between groovy scripts and groovy classes. - In the above example I use the path
"${new File(getClass().protectionDomain.codeSource.location.path).parent}/some/subpackage/Util.groovy"instead of"some/subpackage/Util.groovy". This will guarantee that theUtil.groovyfile will always be found in relation to the groovy script's location (example.groovy) and not the current working directory. For example, using"some/subpackage/Util.groovy"would result in searching atWORK_DIR/some/subpackage/Util.groovy. - Follow the Java class naming convention to name your groovy scripts. I personally prefer a small deviation where the scripts start with a lower letter instead of a capital one. For example,
myScript.groovyis a script name, andMyClass.groovyis a class name. Namingmy-script.groovywill result in runtime errors in certain scenarios because the resulting class will not have a valid Java class name. - In the JVM world in general the relevant functionality is named JSR 223: Scripting for the Java. In groovy in particular the functionality is named Groovy integration mechanisms. In fact, the same approach can be used in order to call any JVM language from within Groovy or Java. Some notable examples of such JVM languages are Groovy, Java, Scala, JRuby, and JavaScript (Rhino).
참고URL : https://stackoverflow.com/questions/9136328/including-a-groovy-script-in-another-groovy
'developer tip' 카테고리의 다른 글
| Android Studio에 ZXing 통합 (0) | 2020.09.11 |
|---|---|
| 약한 연결-클래스가 있는지 확인하고 해당 클래스를 사용합니다. (0) | 2020.09.11 |
| 디버그에서 애플리케이션 인사이트 비활성화 (0) | 2020.09.11 |
| 가져 오기 쉬운 Git 커밋 통계 (0) | 2020.09.11 |
| 서버 127.0.0.1 shell / mongo.js에 연결할 수 없습니다. (0) | 2020.09.11 |