Below is the source for the proposed NV etc macros + an explanation how
to use macros with IntelliJ IDE.
To build and use macros inside the same IntelliJ project:
1. In a Groovy 2.5 project, create a new module for the macro code
(e.g. groovy_macro) and one for the macro usage (e.g. groovy_macro_use).
2. In groovy_macro\src (folder marked as Sources Root)
1. Add \main\groovy\groovyx\macro\NameAndValueMacros.groovy (see below)
2. Add \main\groovy\groovyx\NameAndValue.groovy
3. In groovy_macro\resources (folder marked as Resources Root)
1. Add
resources\META-INF\groovy\org.codehaus.groovy.runtime.ExtensionModule
4. Add a depency to groovy_macro to groovy_macro_use
5. Use NV/NVL in code in Groovy code in groovy_macro module (example:
See NameAndValueMacrosTest.groovy below)
Note: As Paul already pointed out, compiling the macro code in the same
step as the code that uses it does not work - the compiled macro code
already needs to be on the classpath during compilation, which is why we
need two seperate modules inside the same project. Of course the macro
code can also be compiled independently and the resulting JAR added to
the "groovy_macro_use" module.
Cheers,
mg
// resources\META-INF\groovy\org.codehaus.groovy.runtime.ExtensionModule
moduleName=groovy-macro-ext moduleVersion=0.1.0
extensionClasses=main.groovy.groovyx.macro.NameAndValueMacros
// src\main\groovy\groovyx\NameAndValue.groovy
package main.groovy.groovyx
class NameAndValue {
final Stringname final val NameAndValue(String name, val) {
this.name = name
this.val = val
}
@Override public String toString() {
final String valStr = ((val instanceof String) || (val instanceof GString))
?"\"$val\"" :val.toString()
return "$name=$valStr" }
}
// src\main\groovy\groovyx\macro\NameAndValueMacros.groovy
package main.groovy.groovyx.macro
import main.groovy.groovyx.NameAndValue
import org.codehaus.groovy.ast.ClassHelper
import org.codehaus.groovy.ast.ClassNode
import org.codehaus.groovy.ast.expr.Expression
import org.codehaus.groovy.ast.expr.GStringExpression
import org.codehaus.groovy.ast.expr.ListExpression
import org.codehaus.groovy.macro.runtime.Macro import
org.codehaus.groovy.macro.runtime.MacroContext
import static org.codehaus.groovy.ast.tools.GeneralUtils.*
class NameAndValueMacros {
// Expose through GeneralUtils ? static ClassNode classNode(final Class
clazz) {
ClassHelper.makeCached(clazz)
}
// NVL: NameAndValueList @Macro public static Expression NVL(MacroContext
ctx, Expression... exps) {
final List nvExpList = exps.collect {NV(ctx,it) }
new ListExpression(nvExpList)
}
// NV: NameAndValue @Macro public static Expression NV(MacroContext ctx,
Expression exp) {
ctorX(classNode(NameAndValue),args(constX(exp.text), exp) )
}
// NVGS: NameAndValue-GString @Macro public static Expression
NVGS(MacroContext ctx, Expression... exps) {
final List<Expression> expList = Arrays.asList(exps)
int i=-1 final List<Expression> nameList = expList.collect { i++;constX((i >0 ?", "
:"") + it.text +"=") }
final quoteCharExp =constX('"')
final List<Expression> quoteIfStringExpList = expList.collect {final
Expression exp ->
final quotedExp =new
GStringExpression('verbatimExp',[quoteCharExp,quoteCharExp],[exp])
ternaryX(orX(isInstanceOfX(exp,classNode(String)),isInstanceOfX(exp,classNode(GString))),
quotedExp, exp)
}
new GStringExpression('', nameList, quoteIfStringExpList)
}
}
// NameAndValueMacrosTest.groovy
package main.groovy.groovyx.macro
import groovy.transform.CompileStatic import main.groovy.groovyx.NameAndValue
import org.junit.Ignore import org.junit.Test class NameAndValueMacrosTest {
@Test @Ignore @CompileStatic void NVL_LongVarNameTest() {
final ageOfTree =124 final towerHeight =987.654 final String visitorName ="abc" final s1 ="DEFGH" final gs0
="val0:$ageOfTree" final GString gs1 ="TheTower($towerHeight)" final List names =
["Peter","Ann","Raymond" ]
println"var0=$var0, var1=$var0" println"single variables: ${NV(ageOfTree)}and
${NV(gs0)}and ${NV(visitorName)}and ${NV(s1)}and ${NV(gs1)}and also ${NV(names)})}"
println"variable list: ${NVL(ageOfTree, gs0, visitorName, s1, towerHeight, gs1, names)}" }
}