views:

84

answers:

3

I have a method with an incoming variable, which represents a script.

e.g.

hello.groovy

Foo.init(this)

Foo.groovy

class Foo {
    static init(app) {

    }
}

What is the best way to add a ton of new functionality to the app variable in the init method? Basically, I would like to add all the functionality of another object to the app object.

For instance, if I had another class:

class Bar {
    def a() { }

    def b() {

    }
}

I would like the app object to basically be a new Bar(). In JavaScript, this is easy by using the prototype object, but I cannot seem to get it working in groovy. What is the best way to accomplish this? Or should I be doing something differently?

A: 

There are several ways to do this and each has advantages and disadvantages. On the Groovy Documentation page, the section on Dynamic Groovy illustrates several of these. If I understand you correctly, the simplest way is to just use the metaClass of an instance to add new functionality, a la:

class Foo {
  static void init (a) {
    a.metaClass.a = { println "a()"; }
    a.metaClass.b = { println "b()"; } 
  }
}

def myObject = new Object();
Foo.init (myObject);

myObject.a();
myObject.b();
RTBarnard
I want to automatically add all the methods of another object (let's say new Bar()) to the object a. You're way would definitely work, but I don't want to manually define all the new methods in the init method.
Holden
Wow, sorry, you're -> your.
Holden
A: 

The easiest way to do this would be with a mixin. Basically you can call mixin on app's class and pass it another class to incorporate that functionality into it.

I've modified your example to show this mixing in the Bar class.

class Foo {
    static init(app) {
        app.class.mixin Bar
    }
}

class Bar {
    def a() { println "a called" }

    def b() {
        println "b called"
    }
}

def app = new Object()
Foo.init(app)
app.a()
app.b()

The output of this would be:

a called b called

In this case I added Bar to the Object class but you could add it to any class in your application.

Chris Dail
I like your solution and I see how it definitely could work, but it doesn't work if the app object is an incoming script. i.e. from an external script I want to say Foo.init(this).
Holden
Do you happen to know why it won't work when the current object is a script? What is special about the script object?
Holden
I think it has something to do with how a Script class is run. The stacktrace refers to that it cannot find ScriptClass.a() which implies it is trying to invoke a static method. Methods in a script may be considered as static on the class but I don't know. I don't have that deep of a knowledge of how scripts work internal to groovy.
Chris Dail
+1  A: 

YourClass.metaClass.static.yourMethod is the most similar to JS prototype I've seen in Groovy. Check this link out:

http://stackoverflow.com/questions/1462946/groovy-meta-programming-adding-static-methods-to-object-metaclass

Cheers.

mrrtnn