다른 그루비에 그루비 스크립트 포함


97

다른 groovy 스크립트에서 groovy 파일을 가져 오는 방법을 읽었습니다.

하나의 그루비 파일에 공통 함수를 정의하고 다른 그루비 파일에서 해당 함수를 호출하고 싶습니다.

나는 이것이 스크립팅 언어처럼 Groovy를 사용한다는 것을 이해합니다. 즉, 클래스 / 객체가 필요하지 않습니다. 나는 그루비에서 할 수있는 dsl과 같은 것을 시도하고 있습니다. 모든 변수는 Java에서 어설 션되며 쉘에서 그루비 스크립트를 실행하고 싶습니다.

이것이 가능합니까? 누군가가 몇 가지 예를 제공 할 수 있습니까?


답변:


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

그것을 스크립트 맨 위에 놓으십시오. 그러면 그루비 파일의 내용이 표시됩니다 (큰 따옴표 사이의 파일 이름을 그루비 스크립트로 바꾸면됩니다).

놀랍게도 "Tools.groovy"라는 클래스로이 작업을 수행합니다.


7
이 작업을 수행하려면 파일 이름이 Java의 클래스 이름 지정 규칙을 준수해야합니다.
willkil 2013

2
질문-이 구문을 사용하여 평가중인 스크립트에 인수를 어떻게 전달할 수 있습니까?
Steve

3
당신은 할 수 없습니다 @ 스티브,하지만 당신은 당신이 인수를 호출하는 스크립트에서 함수 정의 할 수 있습니다
Nilzor

11
이 스크립트가 잘 평가 ... 작동하지 않습니다하지만 선언 (데프, 클래스 등) 발신자 범위에 존재하지 않는
LoganMzz

3
호출 1에서 객체를 반환 한 다음 평가 결과를 변수에 할당해야합니다.
LoganMzz

45

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

1
이 방법을 사용할 때 "클래스를 해결할 수 없습니다"라는 메시지가 계속 표시됩니다. 나에게 무엇을 추천 하시겠습니까? 사용자 정의 클래스를 다른 멋진 스크립트로 가져 오는 방법이 있습니까?
droidnoob

38

이를 수행하는 또 다른 방법은 그루비 클래스에서 함수를 정의하고 런타임에 파일을 구문 분석하고 클래스 경로에 추가하는 것입니다.

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

2
이 솔루션은 실제로 저에게 가장 효과적이었습니다. 허용 된 답변을 사용하려고 시도했을 때 주요 그루비 스크립트가 평가 된 스크립트에 정의 된 클래스를 해결할 수 없다는 오류가 발생했습니다. 무엇의 가치에 대한 ...
cBlaine

1
나는 SO에 게시 된 여러 가지 접근 방식을 시도했지만 이것이 효과가있었습니다. 다른 사람들은 클래스 나 메서드를 해결할 수 없다는 오류를 던졌습니다. 현재 사용중인 버전입니다. Groovy 버전 : 2.2.2 JVM : 1.8.0 공급 업체 : Oracle Corporation OS : Windows 7
Kuberchaun 2014 년

이것은 훌륭하게 작동했습니다. GroovyObject자신의 클래스 이름에 대한 자리 표시자가 아닌 명시 적 으로 사용해야 합니다.
haventchecked

1
여전히 나는 얻는다 : java.lang.NoClassDefFoundError : groovy.lang.GroovyObject
dokaspar

생명의 은인. 고마워 친구!!
Anjana Silva

30

최선의 선택은 그루비 클래스의 형태로 유틸리티를 구성하고, 클래스 경로에 추가하고, 메인 스크립트가 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

with libsrc디렉토리 와 같은 디렉토리 구조가 있다면 이것이 어떻게 작동하는지 궁금합니다
Gi0rgi0s

9

이 작업을 수행하는 방법은 GroovyShell.

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

6

Groovy에는 다른 파일의 내용을 문자 그대로 포함하는 일반적인 스크립팅 언어와 같은 가져 오기 키워드가 없습니다 (여기에 언급 됨 : Groovy가 포함 메커니즘을 제공합니까? ).
객체 / 클래스 지향적 특성 때문에 이러한 작업을 수행하려면 "게임"을해야합니다. 한 가지 가능성은 모든 유틸리티 함수를 정적으로 만든 다음 (객체를 사용하지 않는다고 말 했으므로) 실행중인 셸 컨텍스트에서 정적 가져 오기를 수행하는 것입니다. 그런 다음 "전역 함수"와 같은 메서드를 호출 할 수 있습니다. ) 셸을 만들고 원하는 모든 함수를 메서드에 바인딩하는 동안 (여기서 단점은 바인딩의 모든 메서드를 열거해야하지만 리플렉션을 사용할 수 있다는 것입니다). 또 다른 해결책은
또 다른 가능성은 Binding 개체 ( http://groovy.codehaus.org/api/groovy/lang/Binding.htmlmethodMissing(...) 셸에 할당 된 델리게이트 객체 입니다. 이렇게하면 기본적으로 맵이나 원하는 방법을 사용하여 동적 디스패치를 ​​수행 할 수 있습니다.

이러한 방법 중 일부는 http://www.nextinstruction.com/blog/2012/01/08/creating-dsls-with-groovy/에서 설명 합니다. 특정 기술의 예를보고 싶다면 알려주세요.


7
이 링크는 지금 죽었
니콜라스 Mommaerts

6

외부 스크립트를 Java 클래스로 취급하는 것은 어떻습니까? 이 기사를 기반으로 : https://www.jmdawson.net/blog/2014/08/18/using-functions-from-one-groovy-script-in-another/

getThing.groovy 외부 스크립트

def getThingList() {
    return ["thing","thin2","thing3"]
}

printThing.groovy 메인 스크립트

thing = new getThing()  // new the class which represents the external script
println thing.getThingList()

결과

$ groovy printThing.groovy
[thing, thin2, thing3]

5

다음은 하나의 스크립트를 다른 스크립트에 포함하는 완전한 예입니다.
Testmain.groovy 파일을 실행하십시오.
설명 주석이 포함되어 있습니다.

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

후발 사용자의 경우 groovy :load file-path가 주어진 파일에서 입력을 단순히 리디렉션 하는 명령을 지원하는 것으로 보이 므로 이제 라이브러리 스크립트를 포함하는 것이 간단합니다.

groovysh에 대한 입력 및로드 된 파일의 한 줄로 작동합니다.
groovy:000> :load file1.groovy

file1.groovy는 다음을 포함 할 수 있습니다.
:load path/to/another/file invoke_fn_from_file();


이것을 확장 해 주시겠습니까? 문서에서 이것은 어디에 있습니까? 어디에 넣을 :load file-path까요?
Christoffer Hammarström

글쎄, 그것은 groovysh에 대한 입력 및로드 된 파일의 한 줄로 작동합니다. <br/> groovy:000> :load file1.groovy file1.groovy는 다음을 포함 할 수 있습니다. <br/>:load path/to/another/file
Jack Punt

1
문서 에서 부하를 찾았습니다 . 올바르게 이해하면 groovysh 에서만 작동합니까?
Christoffer Hammarström

그래도 변수 내부에 정의 된 경로에서는 작동하지 않습니다.
user2173353

0

@grahamparks 및 @snowindy 답변과 몇 가지 수정 사항의 조합은 Tomcat에서 실행되는 Groovy 스크립트에서 작동하는 것입니다.

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!

나는 얻는다 : java.lang.NoClassDefFoundError : groovy.lang.GroovyObject
dokaspar

0

Groovy는 자바처럼 다른 멋진 클래스를 가져올 수 있습니다. 라이브러리 파일의 확장자가 .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

몇 가지 조사 끝에 다음 접근 방식이 가장 좋다는 결론에 도달했습니다.

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'])

example.groovy스크립트 를 실행하려면 시스템 경로에 스크립트를 추가하고 임의의 디렉토리에서 입력하십시오.

example.groovy

스크립트는 다음을 인쇄합니다.

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그루비 스크립트 내 클래스 .
  • 타사 라이브러리를 종속성 ( ) 으로 포함하여 Util호출 하는 클래스 입니다.GuavaGrape@Grab('com.google.guava:guava:23.0')
  • Util클래스는 하위 디렉토리에 상주 할 수 있습니다.
  • Util클래스 내의 메서드에 인수 전달 .

추가 의견 / 제안 :

  • groovy 스크립트 내에서 재사용 가능한 기능을 위해 항상 groovy 스크립트 대신 groovy 클래스를 사용하십시오. 위의 예는 Util.groovy 파일에 정의 된 Util 클래스를 사용합니다. 재사용 가능한 기능을 위해 groovy 스크립트를 사용하는 것은 문제가 있습니다. 예를 들어, 그루비 스크립트를 사용하는 경우 Util 클래스 new Util()는를 사용 하여 스크립트의 맨 아래에 인스턴스화되어야 하지만 가장 중요한 것은 Util.groovy가 아닌 이름의 파일에 배치되어야한다는 것입니다. 참조 클래스에 비해 스크립트 그루비 스크립트와 그루비 클래스의 차이점에 대한 자세한 내용은.
  • 위의 예에서는 "${new File(getClass().protectionDomain.codeSource.location.path).parent}/some/subpackage/Util.groovy"대신 경로 를 사용합니다 "some/subpackage/Util.groovy". 이렇게하면 Util.groovy파일이 항상 example.groovy현재 작업 디렉토리가 아니라 그루비 스크립트의 위치 ( )와 관련하여 찾을 수 있습니다 . 예를 들어를 사용 "some/subpackage/Util.groovy"하면에서 검색됩니다 WORK_DIR/some/subpackage/Util.groovy.
  • 멋진 스크립트의 이름을 지정하려면 Java 클래스 이름 지정 규칙을 따르십시오. 개인적으로 스크립트가 대문자 대신 소문자로 시작하는 작은 편차를 선호합니다. 예를 들어 myScript.groovy는 스크립트 이름이고은 MyClass.groovy클래스 이름입니다. 이름을 지정 my-script.groovy하면 결과 클래스에 유효한 Java 클래스 이름이 없기 때문에 특정 시나리오에서 런타임 오류가 발생합니다.
  • 일반적으로 JVM 세계에서 관련 기능은 JSR 223 : Scripting for the Java 입니다. 특히 Groovy에서는 기능을 Groovy 통합 메커니즘이라고 합니다. 사실, 동일한 접근 방식을 사용하여 Groovy 또는 Java 내에서 JVM 언어 를 호출 할 수 있습니다 . 이러한 JVM 언어의 몇 가지 주목할만한 예는 Groovy, Java, Scala, JRuby 및 JavaScript (Rhino)입니다.
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.