Closure with conditional logging - groovy

I have a function like this:
private downloadAllFiles() {
sftpRetriever.listFiles().findAll {
filter.isResponse(it) || filter.isResponseTurned(it)
}.each { String fileName ->
log.info 'Downloading file: {}', fileName
sftpRetriever.downloadFile(fileName)
log.info 'File downloaded'
removeRemoteFile(fileName)
}
}
I am looking for a simple way of modyfing this closure inside of that function so if the size() of findAll is 0 it will simply log 'No more files to download' and .each won't be executed. Is there any simple way to make it in single closure? It is really simply task if I divide it in several parts, but trying to learn closures here and improve my expressiveness :) Thank you in advance for your help.

Take a look at creature below :) It works due the fact that each returns the collection on which it's invoked (+ elvis operator and quite nice Groovy's truth evaluation):
def printContents(Collection collection) {
collection.each {
println it
} ?: println('Collection is empty')
}
printContents([1,2,'hello'])
printContents([])
I don't like this syntax but it's the shorter version which came to my mind.
You can also use metaprogramming to add the method provided by Steinar. It must be added to metaClass before first use but you'll avoid an effort to make extension module:
Collection.metaClass.doIfEmpty { Closure ifEmptyClosure ->
if (delegate.empty) {
ifEmptyClosure()
}
return delegate
}
def printContents(Collection collection) {
collection.doIfEmpty {
println "Collection is empty"
}.each {
println it
}
}
printContents([1,2,'hello'])
printContents([])

One rather generic and reusable option is to extend Collection using an extension module. This is surprisingly easy to do and is even recognized in IDE's (at least in IntelliJ) so you get code completion, etc.
For example, write an the extension class for collections which will perform the closure if the collection is empty. In addtion, it should always return the collection to allow further chaining:
package stackoverflow
class CollectionExtension {
static <T extends Collection> T doIfEmpty(T self, Closure closure) {
if (self.empty) {
closure()
}
return self
}
}
You will also need to tell groovy that this file is an extension module. Add a property file as a resource on the classpath: META-INF/services/org.codehaus.groovy.runtime.ExtensionModule (note: this name and location is mandatory for extension modules, i.e. you cannot change it).
moduleName=stackoverflow-module
moduleVersion=1.0
extensionClasses=stackoverflow.CollectionExtension
Finally a simple test script to show how this can be used:
def printContents(Collection collection) {
collection.doIfEmpty {
println "Collection is empty"
}.each {
println it
}
}
printContents([1,2,'hello'])
printContents([])
Output:
1
2
hello
Collection is empty

You may try the following piece of code:
def l1 = [1,2,3,4]
def l2 = [5,6,7,8]
def m(list) {
list.findAll { it < 5}.with { l ->
size > 0 ?
l.each { e ->
println e
}
:
println('Zero elements found')
}
}
m(l1)
m(l2)
No better idea at the moment.

Related

Skip MissingPropertyException while using GroovyShell.evaluate

Is there a way to skip MissingPropertyException while using GroovyShell.evaluate?
def sharedData = new Binding()
def shell = new GroovyShell(sharedData)
shell.evaluate("a=5; b=1") // works fine
// How to not get MissingPropertyException, or silently ignore property 'a'
shell.evaluate("a; b=1") // MissingPropertyException for 'a'
I know about the Expando solution, is there a way to do it without defining a class?
A very minimal approach would be to override Binding.getVariable.
Note that this is very straight forward: "all exceptions" are ignored - you might want to have better logging or more accurate error handling.
import groovy.lang.*
class NoOpBinding extends Binding {
#Override
Object getVariable(String name) {
try {
return super.getVariable(name)
}
catch (Throwable t) {
println "Ignoring variable=`$name`"
return null
}
}
}
def shell = new GroovyShell(new NoOpBinding())
shell.evaluate("a; b=1") // MissingPropertyException for 'a'
// → Ignoring variable=`a`
println shell.getVariable('b')
// → 1
You could do something like this:
def binding = [:].withDefault { }
def shell = new GroovyShell(binding as Binding)
shell.evaluate 'a; b=1'

Jenkins Library / Groovy Script - Wrap Code dynamically

I'm developing a Jenkins shared library right now.
I wasn't able to figure how to easily "wrap" a code inside a function without copy-pasting the whole code. For example: If a developer sets a value to true, then I want to wrap the whole code inside a function. Right now I want to use this to allow e.g. the gitlabIntegration to be turned off from the Jenkinsfile.
Example:
// vars/stageWrapper.groovy
def call(Map parameters = [:], body) {
stage(stageName) {
if (pushtoGitlab) {
gitlabCommitStatus(stageName) {
if (!containerName) body()
else {
container(containerName) {
body()
}
}
}
} else {
if (!containerName) body()
else {
container(containerName) {
body()
}
}
}
}
}
let the user select if the stage should be pushed to gitlab via the gitlabCommitStatus wrapper.
switch to a specified container or use default container (if none is specified)
To realize this I currently repeat the code, which I really don't like...
Is there any way of achieving the same, but without repeating the same code over and over?
Thank You!
In Groovy you can reuse a Closure in different DSL-Builders by setting it's delegate to builder's delegate.
Something like this should work:
def containerNameBody = { body ->
if (!containerName)
body()
else
container(containerName) {
body()
}
}
def call(Map parameters = [:], body) {
stage(stageName) {
containerNameBody.delegate = delegate
if (pushtoGitlab)
gitlabCommitStatus(stageName) {
containerNameBody body
}
else
containerNameBody body
}
}
How about following approach to pass down the param into function, then decide how to do inside the function by the param value.
def gitHub(gitHubOn) {
}
def gitLab(gitLabOn) {
}
def call(Map parameters = [:], body){
//some code....
foo=bar
gitLab(parameters.gitLabOn)
gitHub(parameters.gitHubOn)
body()
}

Groovy: colon mark in closure?

I am trying to make my own Dsl and was playing around with different styles of closures in groovy.
I've stumbled upon follwing snippet:
myClosure {
testProperty: "hello!"
}
But can't figure out if this a valid code and how can I access then this testProperty. Is it valid? How can I read "hello!" value?
For now, lets put aside closures, consider the following code:
def f1() {
testProperty : 5
}
def f2() {
testProperty : "Hello"
}
println f1()
println f1().getClass()
println f2()
println f2().getClass()
This compiles (therefor the syntax is valid) and prints:
5
class java.lang.Integer
Hello
class java.lang.String
So what you see here is just a labeled statement (groovy supports labels see here)
And bottom line the code of f1 (just like f2) is:
def f1() {
return 5 // and return is optional, so we don't have to write it
}
With closures its just the same from this standpoint:
​def method(Closure c) {
def result = c.call()
println result
println result.getClass()
}
method {
test : "hello"
}
This prints
hello
class java.lang.String
as expected
Usually in DSL you have either this:
mySomething {
a = 42
b = 84
}
which corresponds to property setting
or this:
mySomething( a:42, b:84 ){
somethingElse{}
}
which is a method call with Map-literal.
The code you shown is not used as #mark-bramnik explained.

How can a Groovy closure curry itself for repetition?

I'm implementing Groovy step definitions for Cucumber-JVM and I want a step to be able store itself so that the next step can repeat it n times.
Given(~'the (\\S+) is in the blender') { String thing ->
// do stuff...
context.repeatable = self.curry(thing)
}
What should "self" be in the above code?
I can't use "this" as that refers to the enclosing object (whatever that is in this case, maybe the script).
Since curry is a method of the Closure class, directly invoking curry applies to the closure, both if it is named:
def context
test = { String thing ->
context = curry(thing)
thing.toUpperCase()
}
test('hello')
println context.call()
test('world')
println context.call()
=>
HELLO
WORLD
or anonymous:
def context
['test'].each { String thing ->
context = curry(thing)
thing.toUpperCase()
}
println context.call()
=>
TEST
You can try using unreferenced curry method passing the received parameters:
clos = { String text ->
if (text) {
println "text=$text"
a = curry null
a()
} else {
println "done"
}
}
clos "closure text"
Will print:
text=closure text
done
Update
You can also use clone():
closure = {
def clone = clone()
}

How to iterate over groovy class non-static closures and optionally replace them?

I'd like to iterate over groovy class non-static closures and optionally replace them.
I can get MetaClass with something like
MyClassName.metaClass
and from there I can get all properties like
metaClassObject.properties
which is the list of MetaProperty objects.
The problem is that I can't detect which of those properties are closures and which are simple objects. MetaProperty object's type property return Object in both case.
And about replacing: Let's say, I know that it is a closure A, then can I create another closure B that wraps closure A with some optional code and replace that closure A with B in the class definition? Should work like some sort of interceptor.
This is one way I have tried out:
class Test {
def name = 'tim'
def processor = { str ->
"Hello $name $str"
}
}
Test t = new Test()
t.metaClass.properties.each {
if( t[ it.name ].metaClass.respondsTo( it, 'doCall' ) ) {
println "$it.name is a closure"
def old = t[ it.name ]
t.metaClass[ it.name ] = { str ->
"WOO! ${old( str )}"
}
}
}
println t.processor( 'groovy!' ) // prints 'WOO! Hello tim groovy!'
However, it would need expanding as I rely on the fact that I know how many parameters it takes for the patching closure replacement
There may also be a simpler way to do this...

Resources