在另一个Groovy脚本中包含一个Groovy脚本

119

我已阅读如何在另一个Groovy脚本中简单导入Groovy文件的内容

我想将常用函数定义在一个Groovy文件中,并从其他Groovy文件中调用这些函数。

我知道这将使用Groovy作为脚本语言,即我不需要类/对象。我正在尝试像Groovy中可以完成的dsl一样做。所有变量都将由Java进行断言,我希望在Shell中执行Groovy脚本。

这有可能吗?有人能提供一些示例吗?


2
可能是从Groovy脚本加载脚本的重复问题。 - tim_yates
13个回答

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

将此内容放在脚本顶部。这将引入一个Groovy文件的内容(只需在双引号之间替换文件名为您的Groovy脚本即可)。

我使用一个非常惊奇地被称为"Tools.groovy"的类来完成这个操作。


9
为了使其正常工作,文件名需符合Java的类命名规则。 - willkil
2
问题 - 我如何使用这个语法将参数传递给我正在评估的脚本? - Steve
3
@steve,你不能这样做,但是你可以在该脚本中定义一个函数,并用参数调用该函数。 - Nilzor
12
无法运行...脚本评估良好,但调用者作用域中不存在声明(def、class等)。 - LoganMzz
4
你需要在第一次调用时返回一个对象,然后将计算结果分配给一个变量。 - LoganMzz
显示剩余3条评论

46

另一种方法是在Groovy类中定义函数,并在运行时解析并将文件添加到类路径中:

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

3
这个解决方案对我来说确实是最好的。当我尝试使用被接受的答案时,出现了一个错误,说我的主要groovy脚本无法解析在评估脚本中定义的类。就这样吧。 - cBlaine
1
我尝试了 SO 上发布的几种不同方法,只有这个有效。其他方法会抛出无法解析类或方法的错误。这是我正在使用的版本 Groovy Version: 2.2.2 JVM: 1.8.0 Vendor: Oracle Corporation OS: Windows 7。 - Kuberchaun
1
这个很好用。请确保显式地使用GroovyObject,而不是您自己的类名作为占位符。 - haventchecked
1
仍然出现以下错误:java.lang.NoClassDefFoundError: groovy.lang.GroovyObject - dokaspar
救了我的一命。谢谢伙计! - Anjana Silva

46

从Groovy 2.2版本开始,可以使用新的@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

2
当我使用这个方法时,我一直收到“无法解析类”的错误。你有什么建议?是否有任何方法可以将自定义类导入到另一个Groovy脚本中? - droidnoob
我不知道它怎么能工作。你在哪里提供MainScript.groovy的路径? - QkiZ

32

我认为最好的选择是将实用工具以 Groovy 类的形式组织起来,将它们添加到 classpath 中,并且让主脚本通过 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

我想知道如果你有像libsrc目录这样的目录结构,这个会怎么工作。 - Gi0rgi0s

11

如果您在源代码库之外运行脚本,则无法正常工作。 - Eugen
1
如果getThing.groovy在另一个文件夹中怎么办? - red888

10

我使用 GroovyShell 来完成这个任务。

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

如果有多个脚本使用相同的第三方库,则会出现错误。 例如,如果超过1个脚本具有以下代码:@Grab('com.opencsv:opencsv:4.5') import com.opencsv.CSVWriter为解决此问题,我必须将Object用作类型,而不是实际类型,并且需要从其他脚本中删除@Grab语句(这些脚本在主脚本中被引用)。 - ankur_rajput

8
这是一个在另一个脚本中包含一个脚本的完整示例。只需运行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")

7
Groovy没有import关键字,像典型的脚本语言那样直接包含另一个文件的内容(在这里提到:Groovy是否提供包含机制?)。因为它是面向对象/类的,所以你需要"玩一些游戏"才能让诸如此类的东西工作。一种可能性是将所有实用函数设为静态(因为你说它们不使用对象),然后在执行shell的上下文中执行静态导入。然后你可以像调用"全局函数"一样调用这些方法。
另一种可能是在创建Shell时使用Binding对象(http://groovy.codehaus.org/api/groovy/lang/Binding.html)并将所有要绑定的函数绑定到方法中(缺点是必须枚举绑定中的所有方法,但也许可以使用反射)。另一种解决方案是在分配给你的shell 的委托对象中覆盖methodMissing(...) ,这使你基本上可以使用映射或任何你想用的方法进行动态分派。

这里演示了几种方法:http://www.nextinstruction.com/blog/2012/01/08/creating-dsls-with-groovy/。如果你想看某种技术的例子,请告诉我。


7
此链接已失效。 - Nicolas Mommaerts

3
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

结合@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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接