Skip to content

Instantly share code, notes, and snippets.

@sit
Created September 23, 2011 16:08
Show Gist options
  • Save sit/1237768 to your computer and use it in GitHub Desktop.
Save sit/1237768 to your computer and use it in GitHub Desktop.
A puzzle about why Groovy behaves a certain way with respect to propertyMissing
/*
* A minimal script to demonstrate the problem discussed at
* http://stackoverflow.com/questions/7524340/how-do-groovy-scripts-interact-with-propertymissing
*/
class Thing {
}
class FooSyntax {
def myKeyword(Thing t) { println "Hello Foo " + t.toString(); }
/*
* With this method uncommented, neither foo in the script works.
* With this method commented, the first foo (with bar) works,
* the second foo (with baz) does not (as expected).
*
* Why is this?
*/
// def propertyMissing(String name) {
// println "no foo for ${name}"
// }
}
class ScriptSyntax {
def foo(Closure cl) {
def f = new FooSyntax();
f.with cl
}
def thing() {
new Thing()
}
def dispatchKeyword(String methodName, Object args) {
// Sanity check methodName
invokeMethod(methodName, args)
}
}
def runner(String text) {
def source = new GroovyCodeSource(text, "inlineScript", "inline.groovy")
def script = new GroovyClassLoader().parseClass(source).newInstance(binding) as Script
def dsl = new ScriptSyntax()
script.metaClass.methodMissing = { name, args -> dsl.dispatchKeyword(name, args) }
script.run()
}
runner("""bar = thing()
foo { myKeyword bar }
foo { myKeyword baz }""")
@pledbrook
Copy link

This is a problem with your use of .with() on line 27. The code you want to use for executing the closure is:

def f = new FooSyntax()
cl = cl.clone
cl.delegate = f
cl.call()

Your example will then work as you want it to. The problem is that the with() method modifies the closure in a similar way, but changes the default resolution strategy.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment