I have a DSL where, if present, a closure called before will be called before every command.
In my setup I have 3 files: The script itself - Script, a ScriptBase, that is 'attached' to the script via a CompilerConfiguration, and a Handler.
In the script I may or may not have a closure called before.
before = {
//Do stuff.
}
Notice the lack of a type declaration, or def. If I understand Groovy correctly, this means that before is a in the binding, and accessible from outside code when evaluated with GroovyShell.evaluate().
In the ScriptBase I do the following:
class ProductSpecificationBase extends Script {
def before = null
}
This script base may or may not be overridden later on.
Then, in the Handler, I'm doing a check for whether a before closure is defined in the script:
def config = new CompilerConfiguration()
config.setScriptBaseClass(ScriptBase.class.name)
def shell = GroovyShell()
evaluatedScript = shell.evaluate(new File(thePathToScript))
if (evaluatedScript.before) {
theEvaluationOfMyScript.before()
}
The code works as expected if the script does contain a before closure, but if it doesn't it returns a MissingPropertyException. I've had a look at what this means, and it seems that my before in the ScriptBase isn't considered a property, and all the examples of using these ScriptBases I've found on the internet give examples of using methods. This is not feasible for my use case I'm afraid. How can I ensure that the closure in the ScriptBase is considered a property instead of a field(as I am assuming it is now).
To be paraphrase: I would like my code to not execute the if block if the script does not contain a before closure as well as not having been overridden in an extension of the ScriptBase. However, I would like the evaluation of evaluatedScript.before to be false as it is an empty/null Closure (i.e. it went all the way up to ScriptBase, and found the null closure)
I like to avoid a try/catch approach if possible.
in your example you would basically call the getter for the before property. To check, if there is a method with the name (and params) check with respondsTo. To see, if there is a property at all with that name use hasProperty (Thanks #dmahapatro for pointing this out)
class X {
void before() { println 'x' }
}
class Y { }
class Z {
def before = { println 'z' }
}
def x = new X()
def y = new Y()
def z = new Z()
assert x.respondsTo('before', null)
assert !y.respondsTo('before', null)
assert !z.respondsTo('before', null)
assert !x.hasProperty('before')
assert !y.hasProperty('before')
assert z.hasProperty('before')
x.before()
z.before()
Related
What does this syntax mean in Groovy?
class CreateMessagePage extends Page {
static at = { assert title == 'Messages : Create'; true }
static url = 'messages/form'
static content = {
submit { $('input[type=submit]') }
MyVeryStrangeForm { $('form') }
errors(required:false) { $('label.error, .alert-error')?.text() }
}
}
(taken from Spring MVC Test HtmlUnit manual)
The question is about Groovy and I would like know the answer in Groovy terms.
What is content? Is it a static variable? Is its name is random or predefined by base class of Page?
What is = (equal sign) after it? Is it an assignment operator?
What is at the right hand side of =? Is this a closure? Or if this an anonymous class? Or if these are the same?
What is submit inside curly braces?
Is this a variable? Why there is no assignment operator after it then?
Is this a function definition? Can I define functions in arbitrary places in Groovy? If this is a function definition, then what is errors then?
Is submit is a function call, receiving { $('input[type=submit]') } as a parameter? If yes, then where is this function can be defined? For example, where is MyVeryStrangeForm defined (is nowhere)?
If this was function call, then it won't work since it's undefined...
Quick answer to all questions: it's a block of code, like anonymous function, called closure in Groovy.
See http://www.groovy-lang.org/closures.html
In Groovy you can reference/pass/set such closure, as in any Functional Language.
So this:
static at = { assert title == 'Messages : Create'; true }
means that class field at will be set to this closure (notice, not result of closure execution, but closure itself, as block of code). Type of at is omitted there, but it could be static def at or static Object at, or static Closure at
This code could be executed anytime later, in different context, with title defined, etc.
This:
submit { $('input[type=submit]') }
means calling a function submit with closure as argument.
If you want to write own function like this, it should be something like:
def submit(Closure code) {
code.call()
}
Brackets could be omitted, so it could be written as submit({$('input[type=submit]')}). Same for other function as well, it could be println 'hello world!' instead of println('hello world').
There's also a common practice to define closure as last argument, like:
def errors(Map opts, Closure code) {
....
}
at this case you could pass first arguments as usual, wrapped in brackets, and closure outside:
errors(required:false) { ...... }
same to:
errors([required: false], { ..... })
I'm new to Gradle/Groovy and am running into issues with variable name resolution in nested closures. I have a custom task class that defines some properties and I am instantiating potentially multiple tasks of that type using a closure. This closure defines a variable named the same as one of the properties in the custom task class and I am running into some odd behavior which seems to go against what is defined in the Groovy language guide. Could someone please answer the questions in the code below?
class Something extends DefaultTask {
def thing = "a"
}
/*
def thing = "b" // produces the error message:
// > Could not find method b() for arguments [build_63hfhkn4xq8gcqdsf98mf9qak$_run_closure1#70805a56] on root project 'gradle-test'.
// ...why?
*/
(1..1).each {
def thing = "c"
task ("someTask${it}", type: Something) {
println resolveStrategy == Closure.DELEGATE_FIRST // prints "true"
println delegate.class // prints "class Something_Decorated"
println thing // prints "c" shouldn't this be "a" since it's using DELEGATE_FIRST?
/*
println owner.thing // produces the error message:
// > Could not find property 'thing' on root project 'gradle-test'
// shouldn't the "owner" of this closure be the enclosing closure?
// in that case shouldn't this resolve to "c"
*/
}
}
EDIT:
For some reason after changing all of the def into String and then back into def I can no longer replicate the def thing = "b" line producing that weird error
The code prints c because the variable named thing is declared within the lexical scope of the closure. It means that closure can just use the value of this variable. What will work:
Renaming the thing variable defined in the closure.
Explicitly referring to thing via delegate:
println delegate.thing
A SoapUI project can run random script upon load.
Load Script is invoked with log and project variables.
In my shared lib I have method - addAsserts() that traverses the whole project and adds schema compliance assertions to SOAP test steps. In my Load Script I call shared method
addAsserts(this)
passing 'this' as a parameter and set closure.delegate to it inside addAsserts method to make 'project' variable accessible within the closure scope
addAsserts method is defined in sharedUtil.groovy:
static def addAsserts(that){
def closure={
project.testSuites.each { testSuiteName, testSuiteObject ->
testSuiteObject.testCases.each { testCaseName, testCaseObject ->
testCaseObject.testSteps.each { testStepName, testStepObject ->
if ("class com.eviware.soapui.impl.wsdl.teststeps.WsdlTestRequestStep" == testStepObject.getClass().toString() ) {
log.info "adding 'Schema Compliance' assertion to ${testSuiteName}/${testCaseName}/${testStepName}"
testStepObject.addAssertion('Schema Compliance')
}
}
}
}
}//closure
closure.delegate=that // <--- i would like NOT to pass 'that' as parameter
// but rather detect in runtime with some kind of
// getCallerInstance() method
return closure.call()
}
QUESTION:
Is it possible to detect caller instance in runtime with some kind of getCallerInstance() method ?
No, I don't believe this is possible. Wasn't in Java either (you can find out the name/method of the calling class using some horrible stacktrace hacking, but not the instance of the class itself)
Edit...
It might be possible with a Category (but I am not experienced with SoapUI, so I don't know if this technique would fit)
Say we have a class Example defined like so:
class Example {
String name
}
We can then write a class very similar to your example code, which in this case will set the delegate of the closure, and the closure will print out the name property of the delegate (as we have set the resolve strategy to DELEGATE_ONLY)
class AssetAddingCategory {
static def addAsserts( that ) {
def closure = {
"Name of object: $name"
}
closure.delegate = that
closure.resolveStrategy = Closure.DELEGATE_ONLY
closure.call()
}
}
Later on in our code, it is then possible to do:
def tim = new Example( name:'tim' )
use( AssetAddingCategory ) {
println tim.addAsserts()
}
And this will print out
Name of object: tim
I have this test code:
def test = null
test.each { }
Why don't I get any exception?
The implementation of each tries to call the iterator method of it's target in a null-safe fashion. If each is called on a null object, or an object without an iterator method, nothing happens.
I haven't seen the source code, but it could look something like this§
Object each(Closure closure) {
if (this?.respondsTo("iterator")) {
def iterator = this.iterator()
while (iterator.hasNext() {
def item = iterator.next()
closure(item)
}
}
return this
}
§ In reality, this method is probably written in Java rather than Groovy
A null value when using the each closure is the same as a collection with 0 elements. If you have the code
def test=null
test.each {println "In closure with value "+it}
The print statement won't execute. If you change test to
def test=[1,2,3]
you will get output.
I need to mock a static method. I'm using the EMC approach described at Mocking static methods using groovy. Like this
TestDaemon.metaClass.'static'.newDownloadManager = {downloadManager}
The method newDownloadManager has no parameters and for some reason it is not replaced. The original code is called. In debug mode I can see that the closure that I define has a parameter. May be that's the reason? How can I define a closure without parameters? Or how can I mock a static method with no parameters?
Meta class changes aren't visible to Java code. Groovy can't help you to mock a static method that gets called from Java code. You will have to use something like JMockit instead (or refactor the code under test).
A closure written like that has an implicit parameter. Write the closure with { -> } syntax. Example:
x = { println "foo" }
y = { -> println "foo" }
assert x.parameterTypes as List == [Object]
assert y.parameterTypes as List == []