Я не знаю, как использовать привязку с закрытиями в Groovy. Я записал тестовый код и при выполнении его, это сказало, отсутствующий метод setBinding
на закрытии, переданном как параметр.
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()
}
У меня это работает с 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()
В этом примере сценария вызов setBinding устанавливает a
в привязке сценария (как вы можете видеть из документации Closure , вызова setBinding нет). Итак, после вызова setBinding вы можете вызвать
println a
, и он распечатает «яблоко»
. Чтобы сделать это в классе, вы можете установить делегат для закрытия (закрытие вернется к этому делегату, когда свойство не может быть найдено локально), например:
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()
}
}
И оно должно получить значение из a
из класса делегата (в данном случае привязки)
Эта страница здесь проходит через использование делегата и области видимости переменных в Closures
Действительно, вместо использования объекта Binding вы должны иметь возможность использовать простую карту вроде этого:
void prepareData( testCase ) {
testCase.delegate = [ a:'apple' ]
testCase.call()
}
Надеюсь, это поможет!
Это действительно странное поведение: удаление "def" перед объявлением someClosure заставляет скрипт работать в JDK1.6 Groovy:1.7.3
Обновление: Это было опубликовано в ответе выше. Моя ошибка в том, что я его повторил. Обновление: Почему это работает? Без def первая строка воспринимается как присвоение свойства, которое вызывает setProperty и делает переменную доступной в связывании, которое решается позже. def должен работать, как и в случае (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()
Я смог воспроизвести проблему, о которой вы говорите, с помощью следующего кода. Но я не уверен, что это правильный способ использования Binding. В GroovyDocs сказано, что они должны использоваться со скриптами. Не могли бы вы указать мне на документацию, которая предлагает такое использование Binding с 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()
}
}
На это был дан ответ в списке рассылки groovy:
В сценарии def foo создаст локальную переменную, а не свойство (приватное поле + геттер/сеттер). Думайте о скрипте примерно так же, как если бы это было тело метода run() или main(). Вот где и как вы можете определить локальные переменные.