ES6 object property shorthand with Groovy

Recently someone asked on StackOverflow whether there is an equivalent in Groovy for the JavaScript shorthand for properties of the object literal. It basically looks like this:

const a = 'foo';
const b = 42;
const c = {};
const obj = { a, b, c };
// the same as: const obj = { a: a, b: b, c: c };

While this feature is not supported in Groovy directly, it's easy to reproduce using a very underused feature: a macro. Macros are supported in Groovy since 2.5.

Create new file to contain all macros. E.g. Macros.groovy:

import org.codehaus.groovy.ast.tools.GeneralUtils
import org.codehaus.groovy.macro.runtime.*
import org.codehaus.groovy.ast.expr.*
import org.codehaus.groovy.syntax.*

class Macros {
    @Macro
    static Expression mapOf(MacroContext ctx, final Expression... exps) {
        return new MapExpression(
            exps.collect{
                new MapEntryExpression(GeneralUtils.constX(it.getText()), it)
            }
        )
    }
}

Then compile this file (this is important to do first, or else Groovy gets confused when something references the class, but it's not there):

# groovyc Macros.groovy

Next make the macro known. There must a file META-INF/groovy/org.codehaus.groovy.runtime.ExtensionModule in the classpath containing the following lines to make Macros from above work:

moduleName=Some name
moduleVersion=0.1-SNAPSHOT
extensionClasses=Macros

And then finally try it out:

def labels=["a", "b"]
def values=[1, 2]
println(
    [labels, values]
        .transpose()
        .collect{ label, value -> 
            mapOf(label,value) 
        }
)

And run it:

# groovy test.groovy
[[label:a, value:1], [label:b, value:2]]