Add method to metaclass

Leikingo picture Leikingo · Dec 10, 2010 · Viewed 11.4k times · Source

I'm just playing with the metaclass programming in Groovy. But suddenly I was facing a little problem which I just could not get working...

Here is the simple script:

// define simple closure
def printValueClosure = {
 println "The value is: '$delegate'"
}

String.metaClass.printValueClosure = printValueClosure

// works fine
'variable A'.printValueClosure()



// define as method
def printValueMethod(String s){
 println "The value is: '$s'"
}

// how to do this!?
String.metaClass.printValueMethod = this.&printValueMethod(delegate)

'variable B'.printValueMethod()

Is it possible to use the method but set the first parameter to the calling object? using delegate seems not to work... The assignment of methods which do not reference the caller is no problem. Does currying work here?

Thanks, Ingo

Answer

ataylor picture ataylor · Dec 10, 2010

The simplest way to accomplish this is to wrap the method in a closure, like so:

def printValueMethod(String s){
    println "The value is: '$s'"
}

String.metaClass.printValueMethod = { -> printValueMethod(delegate) }

assert 'variable B'.printValueMethod() == "The value is: 'variable B'"

The idomatic way to add a method without using closures would be to create a category class and mix it in like so:

class PrintValueMethodCategory {
    static def printValueMethod(String s) {
        println "The value is: '$s'"
    }
}

String.metaClass.mixin(PrintValueMethodCategory)

assert 'variable B'.printValueMethod() == "The value is: 'variable B'"

I don't think currying can help in this particular case, since you don't know the value of the delegate at the time of assignment to the metaclass.