Search code examples
groovyclosuresjenkins-groovy

Dynamically create Groovy closures


I have the need to dynamically create closures which should call other closures within itself.

Here is an example of what I expect the resulting code to do

Closure execute = {
  println("First")
  Closure second = {
    println("Second")
    Closure third = {
      println("Third")
    }.call()
    println("Second")
  }.call()
  println("First")
}

execute.call()

The above results in the following output:

First
Second
Third
Second
First

How can I create the above closure code dynamically given the following list:

List<String> commands = ["First", "Second", "Third"]

Any pointers appreciated.


Solution

  • So, lets make a function which returns a closure

    def wrap(String name, Closure cl = null) {
        { ->
            println(name)
            // If we were passed a closure, then run it and print the name again
            if (cl) {
                cl()
                println(name)
            }
        }
    }
    

    Then, take our list of commands

    List<String> commands = ["First", "Second", "Third"]
    

    And store the current closure in a variable

    Closure current = null
    

    Then, lets go backwards through the list, creating a new closure, and wrapping the previous one

    commands.reverse().each {
        current = wrap(it, current)
    }
    

    Then we can run the final closure:

    current()
    

    And we get the output:

    First
    Second
    Third
    Second
    First
    

    🎉

    In non-jenkins groovy you can use inject instead of the each with a mutating variable:

    Closure current = commands.reverse().inject(null) { curr, command ->
        wrap(command, curr)
    }
    

    But in my experience of answering Jenkins questions, inject rarely works, so stick with the first way