[groovy-user] Groovy scripts. Reusing declared methods in other scripts. How? Include?

1,266 views
Skip to first unread message

Mohamed Seifeddine

unread,
May 11, 2012, 7:45:28 AM5/11/12
to us...@groovy.codehaus.org
If I have a method methodOne declared method in a groovy script One.groovy, 
how can I in my other groovy script Two.groovy call methodOne ?

Is there an include functionality?

Thanks, Mo

Mohamed Seifeddine

unread,
May 11, 2012, 10:14:05 AM5/11/12
to us...@groovy.codehaus.org
A no will do ...

// Mo

Mohamed Seifeddine

unread,
May 11, 2012, 10:41:12 AM5/11/12
to us...@groovy.codehaus.org
I found this old thread ( from 2006! ) 


Jochen suggesting back then that this could easily be added, with something similar to :

import inlined "Test0.groovy"

Test0.methodOne()

What happened with this suggestion Jochen?

Sincerely, Mo

Cédric Champeau

unread,
May 11, 2012, 2:44:58 PM5/11/12
to us...@groovy.codehaus.org
Hi,

Scripts are converted to classes, so methods defined in One.groovy correspond to class One. If you want to use methods from file One.groovy, then you must either instantiate object One from script Two, or make the method from One static. For example:

One.groovy

static void m1() {
   println 'One'
}


Two.groovy

One.m1()

Cheers,
-- 
Cédric Champeau
SpringSource - A Division Of VMware
http://www.springsource.com/
http://twitter.com/CedricChampeau

Jochen Theodorou

unread,
May 11, 2012, 6:43:10 PM5/11/12
to us...@groovy.codehaus.org
Am 11.05.2012 16:41, schrieb Mohamed Seifeddine:
> I found this old thread ( from 2006! )
>
> http://groovy.329449.n5.nabble.com/Scripting-philosophy-was-calling-functions-in-other-groovy-scripts-td331530.html
>
>
> Jochen suggesting back then that this could easily be added, with
> something similar to :
>
> import inlined "Test0.groovy"
>
> Test0.methodOne()
>
> What happened with this suggestion Jochen?

Someone who needed that implemented it for his scripts, but without
making it public and it never found its way into the compiler. Many use
now mixin instead I guess

bye blackdrag

---------------------------------------------------------------------
To unsubscribe from this list, please visit:

http://xircles.codehaus.org/manage_email


Mohamed Seifeddine

unread,
May 14, 2012, 3:40:48 AM5/14/12
to us...@groovy.codehaus.org
On Sat, May 12, 2012 at 12:43 AM, Jochen Theodorou <blac...@gmx.org> wrote:
Am 11.05.2012 16:41, schrieb Mohamed Seifeddine:

I found this old thread ( from 2006! )

http://groovy.329449.n5.nabble.com/Scripting-philosophy-was-calling-functions-in-other-groovy-scripts-td331530.html


Jochen suggesting back then that this could easily be added, with
something similar to :

import inlined "Test0.groovy"

Test0.methodOne()

What happened with this suggestion Jochen?

Someone who needed that implemented it for his scripts, but without making it public and it never found its way into the compiler. Many use now mixin instead I guess



=========================================================================================================

By mixins you mean ? 


I am aware of that you can use static, but I find it would much more useful if you weren't forced to update exisiting code, in order to benefit from it. 
It also appears as if static cannot be used on classes in a script, The class "ABC" has an incorrect modifier static

Cedric suggestion is good and works on methods but it isn't consistent

Test0.groovy:

println "Loading Test0"

void methodOne() {

   println "methodOne";
}

public class ABC {            // not possible to declare this class as static

    public static void methodTwo() {
        println "methodTwo"
    }
    
    public methodThree() {
        println "methodThree"
    }

}


Test1.groovy :

def test0 = new Test0()
//test0.run()             // Will run "Loading trest0"

test0.methodOne()         // Will print 

def b0 = new Test0.ABC()  // Won't work

def b1 = new test0.ABC()  // Won't work

def b2 = new ABC()        // Will work  ... 


As you can see this isn't consistent. I can call methodOne using an instance of the script class, but I can't access the class in the same way... there should be a consistent way for access.
I would prefer that if you "include" another script, its methods and classes should be treated as if they were in in the same script that included them, that is, the same way that the class ABC is now treated but not properties and methods.

//  Moe 

========================================================================================================

Mohamed Seifeddine

unread,
May 14, 2012, 3:59:46 AM5/14/12
to us...@groovy.codehaus.org
I should also add to the last comment, static won't work for methods and properties that are not encapsulated with a class in the script to be included. 
As seen above, methods without static can be called with an instance, however a property or a closure can not be called, resulting in : "No signature of method ... "

Clearly, things could be improved in this area :)

// Moe

Paul Holt

unread,
May 14, 2012, 9:18:20 PM5/14/12
to us...@groovy.codehaus.org
I've had problems with this too. No there doesn't seem to be an easy way to call one script from another without compiling the second script from the first and calling it.

I ended up having a 'main' script with most of the business logic, delegating the real work to a groovy compiled library.

--
Paul Holt

Mohamed Seifeddine

unread,
May 15, 2012, 8:53:41 AM5/15/12
to us...@groovy.codehaus.org
Should I create a JIRA to support achieving the requested above ?

Paul Holt

unread,
May 15, 2012, 10:10:11 PM5/15/12
to us...@groovy.codehaus.org
I... don't think it's really a bug. Scripts are just a handy way of building a quick executable class. The real work should be done by compiled libraries that you distribute alongside the script.

I don't think this is an insurmountable problem for anyone. If you can distribute a script you can distribute a class and put it on your script's class path.
--
Paul Holt

Mohamed Seifeddine

unread,
May 16, 2012, 3:43:58 AM5/16/12
to us...@groovy.codehaus.org
I don't think it is a bug, but a feature request. Obviously, if I intend to build scripts, I should be forced to have the majority of it in a class way fashion. This is really a downer like others have mentioned before me.

// Mo

Mohamed Seifeddine

unread,
May 16, 2012, 7:37:33 AM5/16/12
to us...@groovy.codehaus.org
Ok, 

So for now I have to accept this limitation... but how do I include/use a script/class that doesn't reside immediatly  under the current location of the running script? 

folder0 : A.groovy  

folder0 -> folder1 -> B.groovy, contents : 

abc() { println "abc" }


Contents of A.groovy that I have tried: 

evaluate(new File("folder1/A.groovy") ) 

abc() // Doesn't work

Also tried: 

new folder1.A().run()  // Doesn't work

also

import folder1.A        // Compilation error

also tried 

a = new folder1.A()  // Compilation error


Ok, so I just ran into : 


it claims that if your script is another directory you need to specify a package name that matches the directory name, but then it is no longer a script but a class. 

If you declare one class within this script, then that will be the name to reach it by, if not, then the filename. So while you can have a class in a library script that resides in the same directory, you cannot have that in a script that resides in a subdirectory due to the enforcing of package name. 

Seriously ...  but here are some serious inconsistency when it comes to usage. Ofcourse you should be able to include another script, like the php include.
You shouldn't have to rewrite your code. What if you create a method in a new script that you realize that you can reuse... so you place it in your lib, but then you need to customize and change the way you are calling that method, which in  this case might require some work due to possible breaking which you might not have the  time to figure out so you just ignore doing it. 

It would be comforting to just know that moving the method, and using include will result in the exact same behaviour.  

I've already spent way to much time trying to figure out how to build my libraries... for Groovy to be easy and quick to program in, no one should have to go through this maze again. 
I would rate this is as an important feature 
  
// Moe







Mohamed Seifeddine

unread,
May 16, 2012, 9:30:11 AM5/16/12
to us...@groovy.codehaus.org
Starting to feel as a monologue, but I also suspect that my messages is being recieved hours later than when I actually post them ... 
==================
Please help me because this is ridiculous. New example:

Two groovy files in the same folder: 

.../scripts/reusables/Lib0.groovy : 

package reusables
public class Lib0 {
   
    public static def printSomething() { println "printSomething" }


and 

.../scripts/reusables/GroovyFileUsingLib0.groovy :

reusables.Lib0.printSomething() // Doesn't work! 

Caught: groovy.lang.MissingPropertyException: No such property: reusables for class: GroovyFileUsingLib0
groovy.lang.MissingPropertyException: No such property: reusables for class: GroovyFileUsingLib0
        at  GroovyFileUsingLib0.run( GroovyFileUsingLib0 .groovy:2)

Lib0.printSomething() // Doesn't work
Compilation incomplete: expected to find the class Lib0 in /....../Scripts/Groovy/reusables/Lib0.groovy, but the file contains the classes: reusables.Lib0


Note that if I move the script file GroovyFileUsingLib0.groovy one directory back, to scripts, then the first way will work, ie: reusables.Lib0.printSomething()  ... 

It appears for me as if there is no way to use the class Lib0 if it resides in the same directory as the script file, but that seems odd, I bet I have missed something here ... right ? 

However, if I remove the package declaration from Lib0 ( reusables ) ... then I can call it using the second way. Lib0.printSomething() .... but then we are back at step one again where Groovy scripts not residing in the same directory as the class Lib0 won't be able to call it, that is why the package declaration was necessary as mentioned in my previous post... .this is twisted... 

but please enlighten me !

Thanks, Moe



Levi Hoogenberg

unread,
May 16, 2012, 9:34:57 AM5/16/12
to us...@groovy.codehaus.org

Does your second script contain a package declaration? It should.

Op 16 mei 2012 15:31 schreef "Mohamed Seifeddine" <msei...@gmail.com> het volgende:

Tim Yates

unread,
May 16, 2012, 9:49:24 AM5/16/12
to us...@groovy.codehaus.org
Right, I've got this directory setup:

 Test.groovy
 Run.groovy
 pkg/Test2.groovy

Where

Test.groovy:

def testFunction() {
  println "Hi from ${this.class.name}"
}

Run.groovy

new Test().testFunction()
new pkg.Test2().testFunction()

pkg/Test2.groovy:

package pkg

def testFunction() {
  println "Hi from ${this.class.name}"
}

Then, if I run:

$ groovy -cp . Run.groovy 
Hi from Test
Hi from pkg.Test2

Is this not right?  Or am I looking at the wrong thing?

Tim

Cédric Champeau

unread,
May 16, 2012, 9:51:19 AM5/16/12
to us...@groovy.codehaus.org
Obviously, Groovy is object-oriented so writing "scripts" has slightly different semantics than what you can do with PHP, for example, where basically, including is inlining code. This makes writing scripts less straightforward for people coming from that kind of languages.

However, here is a quick hack that may do what you want. Here is the idea: basically, in Groovy, scripts make use of a special variable called "binding" which is some kind of "global map". It contains, for example, every "undeclared" variable, that is to say variables in scripts you don't declare using a type or "def". This binding can be used to store "functions" too, so the idea is to parse the scripts you want to include, then export every method from the script as a closure in the binding map. This has the effect of making the method available to the current script. Here is an example of usage:

foo.groovy
----------------
include 'bar.groovy'

methodFromBar('hello') // this works because methodFromBar('hello') is equivalent to binding['methodFromBar'].call('hello')

bar.groovy
----------------
void methodFromBar(arg) { println arg }

Then, this is the definition of the "include" function:

void include(filename) {
  def scriptClass = new GroovyShell().parse(new File('bar.groovy')).class
  def obj = scriptClass.newInstance()
  scriptClass.methods.findAll { !it.isSynthetic() }.each {
     binding[it.name] = new org.codehaus.groovy.runtime.MethodClosure(obj, it.name)
  }
}


This must be added at the beginning of the foo.groovy script. Of course, this is not a definitive solution, because you must include this function in each file where you want to include another file, but this is a proof of concept. Eventually, the include function could be transparently added using a smart global AST transformation on classpath when groovy is started.

Hope this helps!

Mohamed Seifeddine

unread,
May 16, 2012, 10:45:01 AM5/16/12
to us...@groovy.codehaus.org
@Levi 
That doesn't help. 

Create two Groovy files in the same directory, where One is: 

One.groovy

package myDir
class One {
     static def printSomething () { println "something" }
}

Two.groovy

package myDir

One.printSomething() ;     // Doesn't work
myDir.One.printSomething() // Doesn't work, with or without the package declaration in the two


@Tim 
Yes, that will work. I also demonstrated that. However, try moving your Run.groovy into the pkg directory and call the method in Test2

pkg/Run.groovy

new pkg.Test2().testFunction()

There is no easy way I see on how you can call the method in test2 ( I haven't evaluated Cedrics suggestion yet ). Run.groovy cannot find the class pkg.Test2.groovy

Now, some of you might suggest that I need to remove the package declaration in Test2.groovy for this to work ... but then Test.groovy with 

new pkg.Test2().testFunction()

in the top directory will no longer work! I should be able to have libraries built on libraries in my library directory, ( in this case it would be Run.groovy ) right!? I haven't figured out a way of calling the method ( static or instance ) in Test2.groovy 

Tim, did you understand what I mean?

@Cedric 

Yes, I tried your hack and it looks promising to build on, however, as I am sure you know yourself, its still incomplete, for example take this: 

One.groovy 

def abc = "aaaaaaaaa"
 
def printSomething() {
println abc
}













Mohamed Seifeddine

unread,
May 16, 2012, 10:47:14 AM5/16/12
to us...@groovy.codehaus.org
Was sent to early... but the last thing above won't work... 
Caught: groovy.lang.MissingPropertyException: No such property: abc for class: One
groovy.lang.MissingPropertyException: No such property: abc for class: One
        at One.printSomething(One.groovy:4)
        at Two.run(Two.groovy:13)

Altgouhg, it will work if your method prints the string itself ... ie println "aaaaaaaaaaaa"...


// Moe

Levi Hoogenberg

unread,
May 16, 2012, 10:48:32 AM5/16/12
to us...@groovy.codehaus.org

And you run your script from the top-level directory, right?

Op 16 mei 2012 16:45 schreef "Mohamed Seifeddine" <msei...@gmail.com> het volgende:

Matthias Hryniszak

unread,
May 16, 2012, 10:48:39 AM5/16/12
to us...@groovy.codehaus.org
Maybe this will help?


Best regards,
Maciej

2012/5/16 Mohamed Seifeddine <msei...@gmail.com>

Dinko Srkoc

unread,
May 16, 2012, 10:56:01 AM5/16/12
to us...@groovy.codehaus.org
$ cat foo/One.groovy
package foo
def testMe() { println "foo.One.testMe" }

$cat foo/Run.groovy
package foo
new foo.One().testMe()

$groovy -cp . foo/Run.groovy
foo.One.testMe

Cheers,
Dinko

Mohamed Seifeddine

unread,
May 16, 2012, 11:07:54 AM5/16/12
to us...@groovy.codehaus.org
On Wed, May 16, 2012 at 4:56 PM, Dinko Srkoc <dinko...@gmail.com> wrote:
$ cat foo/One.groovy
package foo
def testMe() { println "foo.One.testMe" }

$cat foo/Run.groovy
package foo
new foo.One().testMe()

$groovy -cp . foo/Run.groovy
foo.One.testMe


 

Yes, you got me ... I see that this works... but this is a workaround and would you agree it is a bit ugly ( and not intuitive ) to be forced to stand one directory back in order for it to work ? 

 $groovy foo/Run.groovy

try running that script from the directory where the script is located or from ANY other location on the disk, like two directories back 
but you did manage to get it working, congrats!  :)

// Moe

Dinko Srkoc

unread,
May 16, 2012, 11:33:21 AM5/16/12
to us...@groovy.codehaus.org
On 16 May 2012 17:07, Mohamed Seifeddine <msei...@gmail.com> wrote:
>
>
> On Wed, May 16, 2012 at 4:56 PM, Dinko Srkoc <dinko...@gmail.com> wrote:
>>
>> $ cat foo/One.groovy
>> package foo
>> def testMe() { println "foo.One.testMe" }
>>
>> $cat foo/Run.groovy
>> package foo
>> new foo.One().testMe()
>>
>> $groovy -cp . foo/Run.groovy
>> foo.One.testMe
>>
>
>
>
> Yes, you got me ... I see that this works... but this is a workaround and
> would you agree it is a bit ugly ( and not intuitive ) to be forced to stand
> one directory back in order for it to work ?
>
>  $groovy foo/Run.groovy
>
> try running that script from the directory where the script is located or
> from ANY other location on the disk, like two directories back
> but you did manage to get it working, congrats!  :)

$ cd foo
$ groovy -cp .. Run.groovy
foo.One.testMe

;-)
Dinko

Dinko Srkoc

unread,
May 16, 2012, 11:47:44 AM5/16/12
to us...@groovy.codehaus.org
On 16 May 2012 17:07, Mohamed Seifeddine <msei...@gmail.com> wrote:
>
>
> On Wed, May 16, 2012 at 4:56 PM, Dinko Srkoc <dinko...@gmail.com> wrote:
>>
>> $ cat foo/One.groovy
>> package foo
>> def testMe() { println "foo.One.testMe" }
>>
>> $cat foo/Run.groovy
>> package foo
>> new foo.One().testMe()
>>
>> $groovy -cp . foo/Run.groovy
>> foo.One.testMe
>>
>
>
>
> Yes, you got me ... I see that this works... but this is a workaround and
> would you agree it is a bit ugly ( and not intuitive ) to be forced to stand
> one directory back in order for it to work ?

Every Groovy script is, at the same time, a class. You should consider
your scripts collection as a Java or Groovy project with the directory
structure being your source dir tree/package tree. That means every
script, apart from the top level scripts, should have a `package`
declaration. Running the scripts should then include a classpath
pointing to the source dir.

Is it unintuitive? No, it's a Java/Groovy/Scala/other JVM language
way. Is it ugly? Well, that's in the eye of the beholder.

Cheers,
Dinko
Reply all
Reply to author
Forward
0 new messages