views:

69

answers:

2

I dont know how to use binding with closures in grooy.I wrote a test code and while running it, it said, missing method setBinding on the closure passed as parameter.

void testMeasurement() {
    prepareData(someClosure)
}
def someClosure = {
  assertEquals("apple", a)
}


  void prepareData(testCase) {
    def binding = new Binding()
    binding.setVariable("a", "apple")
    testCase.setBinding(binding)
    testCase.call()

  }
+1  A: 

This works for me with Groovy 1.7.3:

someClosure = {
  assert "apple" == a
}
void testMeasurement() {
  prepareData(someClosure)
}
void prepareData(testCase) {
  def binding = new Binding()
  binding.setVariable("a", "apple")
  testCase.setBinding(binding)
  testCase.call()
}
testMeasurement()

In this script example, the setBinding call is setting a in the scripts binding (as you can see from the Closure documentation, there is no setBinding call). So after the setBinding call, you can call

println a

and it will print out "apple"

So to do this in the class, you can set the delegate for the closure (the closure will revert back to this delegate when a property cannot be found locally) like so:

class TestClass {
  void testMeasurement() {
    prepareData(someClosure)
  }

  def someClosure = { ->
    assert "apple" == a
  }

  void prepareData( testCase ) {
    def binding = new Binding()
    binding.setVariable("a", "apple")
    testCase.delegate = binding
    testCase.call()
  }
}

And it should grab the value fro a from the delegate class (in this case, a binding)

This page here goes through the usage of delegate and the scope of variables in Closures

Indeed, instead of using a Binding object, you should be able to use a simple Map like so:

  void prepareData( testCase ) {
    testCase.delegate = [ a:'apple' ]
    testCase.call()
  }

Hope it helps!

tim_yates
Added to my answer
tim_yates
A: 

This is really strange behaviour: removing the "def" in front of someClosure declaration makes the script work in JDK1.6 Groovy:1.7.3

Update: This was posted in the answer above. My mistake to repeat it. Update: Why it works? Without a def first line is taken as a property assignment which calls setProperty and makes the variable available in binding, which is resolved later. a def should have worked as well as per (http://docs.codehaus.org/display/GROOVY/Groovy+Beans)

someClosure = {
    assert "apple", a
    print "Done"
}

void testMeasurement() {
    prepareData(someClosure)
}

void prepareData(testCase) {
    def binding = new Binding()
    binding.setVariable("a", "apple")
    testCase.setBinding(binding)
    testCase.call()
}
testMeasurement()

I could reproduce the problem you mention by following code. But i am not sure if this is the correct way to use Binding. GroovyDocs says they are to be used with scripts. Could you point me to documentation which suggests such usage of Binding with Closures.

class TestBinding extends GroovyTestCase {
    void testMeasurement() {
        prepareData(someClosure)
    }

    def someClosure = {
        assertEquals("apple", a)
    }

    void prepareData(testCase) {
        def binding = new Binding()
        binding.setVariable("a", "apple")
        //this.setBinding(binding)
        testCase.setBinding(binding)
        testCase.call()
    }
}

This was answered on groovy mailing list:

In a script, def foo will create a local variable, not a property (private field + getter/setter). Think of a script a bit like if it's the body of a run() or main() method. That's where and how you can define local variables.

Ravindra