別のGroovyにGroovyスクリプトを含める


97

別のGroovyスクリプトにGroovyファイルを単純にインポートする方法を読みました

1つのgroovyファイルで共通の関数を定義し、それらの関数を他のgroovyファイルから呼び出したいと思います。

これはスクリプト言語のようにGroovyを使用することになることを理解しています。つまり、クラスやオブジェクトは必要ありません。私はグルーヴィーで行うことができるdslのようなものにしようとしています。すべての変数はJavaからアサートされ、シェルでgroovyスクリプトを実行したいと思います。

これはまったく可能ですか?誰かがいくつかの例を提供できますか?


回答:


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

それをスクリプトの一番上に置きます。これにより、groovyファイルの内容が取り込まれます(二重引用符で囲まれたファイル名をgroovyスクリプトに置き換えてください)。

意外と「Tools.groovy」と呼ばれるクラスでこれを行います。


7
これが機能するには、ファイル名がJavaのクラス命名規則に準拠している必要があります。
willkil 2013

2
質問-この構文を使用して評価しているスクリプトに引数を渡すにはどうすればよいですか?
スティーブは

3
@steveできませんが、そのスクリプトで引数を指定して呼び出す関数を定義できます
Nilzor

11
動作しません...スクリプトは十分に評価されていますが、呼び出し元のスコープ(def、クラスなど)には宣言がありません
LoganMzz

3
呼び出し1からオブジェクトを返し、評価結果を変数に割り当てる必要があります。
LoganMzz 16

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

これを行う別の方法は、groovyクラスで関数を定義し、実行時にファイルを解析してクラスパスに追加することです。

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

2
このソリューションは実際に私にとって最も効果的でした。承認された回答を使用しようとすると、メインのgroovyスクリプトが評価済みスクリプトで定義されたクラスを解決できないというエラーが表示されました。価値のあるものは...
cBlaine 2014年

1
私はSOに投稿されたいくつかの異なるアプローチを試しましたが、これだけが機能しました。他のクラスは、クラスまたはメソッドを解決できないというエラーをスローしました。これは私が使用しているバージョンですGroovyバージョン:2.2.2 JVM:1.8.0ベンダー:Oracle Corporation OS:Windows 7
Kuberchaun

これはうまくいきました。必ずGroovyObject明示的に使用してください。これは、独自のクラス名のプレースホルダーではありません。
2015年

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 libsrcdirectory などのディレクトリ構造がある場合、これはどのように機能するのでしょうか
Gi0rgi0s

9

これを行う方法はGroovyShellです。

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

6

Groovyには、別のファイルの内容のリテラルインクルードを行う典型的なスクリプト言語のようなインポートキーワードがありません(ここで言及されています:groovyはインクルードメカニズムを提供していますか?)。
オブジェクト/クラス指向の性質のため、このようなものを機能させるには「ゲームをする」必要があります。1つの可能性は、すべてのユーティリティ関数を静的にして(オブジェクトを使用しないと言ったため)、実行中のシェルのコンテキストで静的インポートを実行することです。次に、「グローバル関数」のようにこれらのメソッドを呼び出すことができます。
別の可能性は、Bindingオブジェクト(http://groovy.codehaus.org/api/groovy/lang/Binding.html)を使用することです。)シェルを作成し、メソッドに必要なすべての関数をバインドしている間(ここでの欠点は、バインド内のすべてのメソッドを列挙する必要がありますが、リフレクションを使用できます)。さらに別の解決策はmethodMissing(...)、シェルに割り当てられたデリゲートオブジェクトをオーバーライドすることです。これにより、基本的にマップまたは任意のメソッドを使用して動的ディスパッチを実行できます。

これらの方法のいくつかをここで示します:http : //www.nextinstruction.com/blog/2012/01/08/creating-dsls-with-groovy/。特定のテクニックの例をご覧になりたい場合はお知らせください。


7
このリンクは現在死んでいます
Nicolas Mommaerts 2014

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
ChristofferHammarström2017年

まあ、それはgroovyshへの入力として、およびロードされたファイルの行として機能します。<br/> groovy:000> :load file1.groovy file1.groovyには以下を含めることができます:<br/>:load path/to/another/file
Jack Punt

1
ドキュメントにロードが見つかりました。私が正しく理解すれば、それはgroovysh でのみ機能しますか?
ChristofferHammarström2017年

ただし、これは変数内で定義されたパスでは機能しません。
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は、Javaとまったく同じように他の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

この例は、次のことを示しています。

  • UtilGroovyスクリプト内でクラスを使用する方法。
  • Util呼び出すクラスGuavaとしてそれを含めることによって、サードパーティのライブラリをGrape依存(@Grab('com.google.guava:guava:23.0'))。
  • Utilクラスは、サブディレクトリに置くことができます。
  • Utilクラス内のメソッドに引数を渡す。

追加のコメント/提案:

  • groovyスクリプト内で再利用可能な機能を使用するには、常にgroovyスクリプトではなくgroovyクラスを使用してください。上記の例では、Util.groovyファイルで定義されているUtilクラスを使用しています。再利用可能な機能にgroovyスクリプトを使用すると問題が発生します。たとえば、groovyスクリプトを使用する場合、Utilクラスはを使用してスクリプトの下部でインスタンス化する必要がありますnew Util()が、最も重要なのは、Util.groovy以外の名前のファイルに配置する必要があることです。groovyスクリプトとgroovyクラスの違いの詳細については、スクリプトとクラスを参照してください。
  • 上記の例では、の"${new File(getClass().protectionDomain.codeSource.location.path).parent}/some/subpackage/Util.groovy"代わりにパスを使用しています"some/subpackage/Util.groovy"。これにより、Util.groovyファイルが常にexample.groovy現在の作業ディレクトリではなくgroovyスクリプトの場所()に関連して検出されることが保証されます。たとえば、を使用"some/subpackage/Util.groovy"すると、で検索されWORK_DIR/some/subpackage/Util.groovyます。
  • Javaクラスの命名規則に従って、groovyスクリプトに名前を付けます。私は個人的に、スクリプトが大文字の小文字ではなく小文字で始まる小さな逸脱を好みます。たとえば、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.