Search code examples
javagroovygroovyshell

Import a Groovy script into another Groovy Script at Runtime


I have a Groovy file that looks like this (currently).

main.groovy

import org.packages.mystuff.JavaClassIAmUsing;
public class MyObject {

    def rate(item){
        def o = evaluate(new File (new File(getClass().protectionDomain.codeSource.location.path).parent),"CommonFunctions.groovy");
        println o.whoami();

    }
}

i have another groovy file called

CommonFunctions.groovy

def whoami() {return 'no body';}

I'm trying to include the CommonFunctions script in to main script, BUT the location of the script are not known at build time (i.e. i can not hardcode a absolute file path in the script or absoulte path of the java process in relation to where the scripts will be stored).

All i know is that the scripts will be together or at a location relative to the calling script (say sub directory).

I've attempted to try and location the calling script location, but i get the error

  No signature of method: MyObject.evaluate()

How can i referance this script, considering the main script is accessed at runtime using a GroovyClassLoader.parseClass(File) method.


Solution

  • I'm not really sure why you want to do it this way, I think it would be much simpler to make a class of CommonsFunctions that you could instantiate normally and use everywhere.

    However, it is possible to achieve what you want; with Groovy, there are not that many limitations...

    There are two problems with your suggested solution:

    1. getClass() inside your MyObject class naturally refers to ... the MyObject class, so your attempt to find the location of the script will fail. You're on the right track, but you need to resolve the script location using the surrounding Script class.
    2. evaluate doesn't really work the way you think it does. The result of the evaluate method is the result of the script, not an instance of the Script class. One way to remedy this, is to rewrite the methods in CommonFunction as closure properties. These properties will be available in the shell Binding object when evaluating the script.

    So, with these rewrites, you end up with something like this:

    main.groovy

    class MyObject {
        def scriptDir
    
        def rate(item) {
            def commonFunctionsScriptFile = new File(scriptDir, "CommonFunctions.groovy")
            def binding = new Binding()
            new GroovyShell(binding).evaluate(commonFunctionsScriptFile)
            println binding.variables.whoami()
        }
    }
    
    scriptFile = new File(getClass().protectionDomain.codeSource.location.path)
    new MyObject(scriptDir: scriptFile.parentFile).rate(null)
    

    Here, the script file location is resolved in the script, not in the inner class.

    CommonFunctions.groovy

    whoami = { 'no body' }
    

    Here, whoami is no longer a method, but a closure property which will be added to the binding. Make sure that you don't prefix this property with def, since then it will be a local variable instead of a property added to the binding object.

    Output after these rewrites is the expected: no body.