I’ve added a method to Closure‘s metaClass, but I don’t seem to be able to get a reference for the instance the method is being called on. In this example, delegate is set to the script instance, not the f closure i’m invoking fixedPoint on:
Closure.metaClass.fixedPoint = {
while (it != (it = delegate.call(it))) {}
it
}
def f = { Math.round(it / 2.0) }
println f.fixedPoint(9)
gives
Caught: groovy.lang.MissingMethodException: No signature of method: test.call() is applicable for argument types: (java.lang.Integer) values: [9]
What a I doing wrong here?
Explanation:
If you do
Closure.metaClass.fixedPoint = ...then the class Closure will get a new MetaClass, which is ExpandoMetaClass. And in a next step the method is added. Now the default meta class for a Closure is ClosureMetaClass, which neither allows you to add methods, nor does it care about other meta classes much. When you dodef f = { Math.round(it / 2.0) }then you actually create a new class (and instance of it). It extends Closure, but is not Closure itself. And this class will have by default ClosureMetaClass as meta class, totally ignoring what you did with the meta class of Closure.Solution:
You have to force the usage of ExpandoMetaClass, thus the first line of your code (before f is assigned) should be
ExpandoMetaClass.enableGlobally():At least for me this code runs without exception…
Side Note:
The Closure stored in the meta class to form the method is usually a clone of what you gave in. The meta class will then set the delegate on the copy. Inspecting the delegate of f by for example
println f.@delegatewon’t show you the result then.