在另一个groovy中包含groovy脚本

在另一个groovy中包含groovy脚本,groovy,Groovy,我读过 我想在一个groovy文件中定义公共函数,并从其他groovy文件中调用这些函数 我知道这将像使用脚本语言一样使用Groovy,也就是说,我不需要类/对象。我正在尝试在groovy中实现类似dsl的功能。所有变量都将从Java断言,我希望在shell中执行groovy脚本 这可能吗?有人能举个例子吗。Groovy没有像典型的脚本语言那样的导入关键字,这些语言会对另一个文件的内容进行文本包含(这里提到:)由于其面向对象/面向类的特性,您必须“玩游戏”才能使类似的工作正常进行。一种可能是使所

我读过

我想在一个groovy文件中定义公共函数,并从其他groovy文件中调用这些函数

我知道这将像使用脚本语言一样使用Groovy,也就是说,我不需要类/对象。我正在尝试在groovy中实现类似dsl的功能。所有变量都将从Java断言,我希望在shell中执行groovy脚本


这可能吗?有人能举个例子吗。

Groovy没有像典型的脚本语言那样的导入关键字,这些语言会对另一个文件的内容进行文本包含(这里提到:)
由于其面向对象/面向类的特性,您必须“玩游戏”才能使类似的工作正常进行。一种可能是使所有实用程序函数都是静态的(因为您说过它们不使用对象),然后在执行shell的上下文中执行静态导入。然后你可以像“全局函数”一样调用这些方法
另一种可能是在创建Shell时使用Binding对象(),并将所有想要的函数绑定到方法(这里的缺点是必须枚举绑定中的所有方法,但可能使用反射)。另一个解决方案是覆盖分配给shell的委托对象中的
methodMissing(…)
,这允许您基本上使用map或任何您想要的方法进行动态分派

此处演示了其中的几种方法:。如果你想看一个特定技术的例子,请告诉我

evaluate(new File("../tools/Tools.groovy"))
把它放在脚本的顶部。这将引入groovy文件的内容(只需用groovy脚本替换双引号之间的文件名)


我使用一个名为“Tools.groovy”的类来实现这一点。另一种方法是在groovy类中定义函数,并在运行时解析文件并将其添加到类路径:

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

从Groovy 2.2开始,可以使用新的
@BaseScript
AST转换注释声明一个基本脚本类

例如:

文件MainScript.groovy

abstract class MainScript extends Script {
    def meaningOfLife = 42
}
import groovy.transform.BaseScript
@BaseScript MainScript mainScript

println "$meaningOfLife" //works as expected
文件测试.groovy

abstract class MainScript extends Script {
    def meaningOfLife = 42
}
import groovy.transform.BaseScript
@BaseScript MainScript mainScript

println "$meaningOfLife" //works as expected

我认为最好的选择是以groovy类的形式组织实用程序,将它们添加到类路径中,并让主脚本通过import关键字引用它们

例如:

scripts/DbUtils.groovy

class DbUtils{
    def save(something){...}
}
class Utils {
    def doSth() {...}
}
scripts/script1.groovy:

import DbUtils
def dbUtils = new DbUtils()
def something = 'foobar'
dbUtils.save(something)
运行脚本:

cd scripts
groovy -cp . script1.groovy

对于后来的人来说,groovy现在似乎支持
:load file path
命令,该命令只是重定向来自给定文件的输入,因此现在包含库脚本是很简单的

它作为groovysh的输入&作为加载文件中的一行:
groovy:000>:加载文件1.groovy

file1.groovy可以包含:
:加载路径/到/另一个/文件

从_文件()调用_fn_

我这样做的方式是使用
GroovyShell

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

@grahamparks和@snowindy answers的组合,加上一些修改,是我在Tomcat上运行的Groovy脚本的工作原理:

Utils.groovy

class DbUtils{
    def save(something){...}
}
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!

经过一些调查,我得出结论,以下方法似乎是最好的

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"
    }
}
#!/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'])
// 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}"
}
// 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")
示例.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"
    }
}
#!/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'])
// 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}"
}
// 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")
要运行
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版本:2.4.13 JVM:1.8.0\u 151供应商:Oracle公司操作系统:Linux

该示例演示了以下内容:

  • 如何在groovy脚本中使用
    Util
  • 一个
    Util
    类调用
    Guava
    第三方库,方法是将其作为
    Grape
    依赖项(
    @Grab(
  • Util
    类可以驻留在子目录中
  • 将参数传递给
    Util
    类中的方法
其他意见/建议:

  • 对于groovy脚本中的可重用功能,请始终使用groovy类而不是groovy脚本。上面的示例使用Util.groovy文件中定义的Util类。使用groovy脚本实现可重用功能是有问题的。例如,如果使用groovy脚本,则必须使用
    new Util()
    在脚本底部实例化Util类,但最重要的是,它必须放在名为Util.groovy以外的任何文件中。有关groovy脚本和groovy类之间差异的更多详细信息,请参阅
  • 在上面的示例中,我使用路径
    “${new File(getClass().protectionDomain.codeSource.location.path).parent}/some/subpackage/Util.groovy”
    而不是
    “some/subpackage/Util.groovy”
    。这将保证
    Util.groovy
    文件始终与groovy脚本的位置(
    example.groovy
    )相关,而不是与当前工作目录相关。例如,使用
    “some/subpackage/Util.groovy”
    将导致在
    WORK\u DIR/some/subpackage/Util.groovy
    进行搜索
  • 按照Java类命名约定命名groovy脚本。我个人更喜欢一个小偏差,脚本以小写字母开头,而不是大写字母。例如,
    myScript.groovy
    是脚本名,
    MyClass.groovy
    是类名。命名
    my script.groovy
    将在某些场景中导致运行时错误,因为生成的类将没有有效的Java类名
  • 通常,在JVM世界中,相关功能被命名为。特别是在groovy中,该功能被命名为。事实上,可以使用相同的方法从Groovy或Java中调用任意函数。这类JVM语言的一些显著例子是Groovy、Java、Scala、,