When/how/with what syntax do we want to include the imho super-helpful
"named variable" support* as a standard Groovy macro feature ?-)
Cheers,
mg
*As a reminder:
The functionality would allow for compact creation of typical (debug)
"<variable_name>=<variable_value>" strings, e.g.:
final myNumber = 123
final myString = 'abc'
NVL(myNumber,myString) // Note: NV macro is for a single variable
is equivalent to
"myNumber=$myNumber, myString =\"$myString\"" // Note: NVL macro
auto-quotes String values
so in our example the output would be
myNumber=123, myString ="abc"
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)
}
}
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" }
}
@Test @CompileStatic void NVL_Test() {
final x0 =9876 final x1 =2.7 final String s0 ="abc" final s1 ="DEFGH" final gs0 ="val0:$x0" final GString gs1
="val1:$x1" println"variables: ${NVL(x0, gs0, s0, s1, x1, gs1)}" final List<NameAndValue> navl =
(List<NameAndValue>) NVL(x0, gs0, s0, s1, x1, gs1)
final result0 ="variables: |${navl}|" final result1 ="variables: |${navl.join(' + ')}|" final result2
="${navl.collect{ "(${it.val}is named ${it.name.toUpperCase()})" }.join(' and ')}" final result3
="variables: |${NVL(x0, gs0, s0, s1, x1, gs1).join(' ~~> ')}|" println result0
println result1
println result2
println result3
assert result0 ==/variables: |[x0=9876, gs0="val0:9876", s0="abc", s1="DEFGH", x1=2.7,
gs1="val1:2.7"]|/ assert result1 ==/variables: |x0=9876 + gs0="val0:9876" + s0="abc" + s1="DEFGH" + x1=2.7
+ gs1="val1:2.7"|/ assert result2 ==/(9876 is named X0) and (val0:9876 is named GS0) and (abc is named S0)
and (DEFGH is named S1) and (2.7 is named X1) and (val1:2.7 is named
GS1)/ assert result3 ==/variables: |x0=9876 ~~> gs0="val0:9876" ~~> s0="abc" ~~> s1="DEFGH" ~~>
x1=2.7 ~~> gs1="val1:2.7"|/ }
@Test @CompileStatic void NV_Test() {
final x0 =9876 final x1 =2.7 final String s0 ="abc" final s1 ="DEFGH" final gs0 ="val0:$x0" final
GString gs1 ="val1:$x1" final result ="variables: ${NV(x0)}+ ${NV(gs0)}- ${NV(s0)}% ${NV(s1)}& ${NV(x1)}~
${NV(gs1)}" println result
assert result ==/variables: x0=9876 + gs0="val0:9876" - s0="abc" % s1="DEFGH" & x1=2.7 ~
gs1="val1:2.7"/ }
@Test @CompileStatic void NameAndValueTest() {
final x =12345 final result = [new NameAndValue("xyz",x),new NameAndValue("var0","the quick"),new
NameAndValue("gstr1","$x") ]
println result
assert result.toString() ==/[xyz=12345, var0="the quick", gstr1="12345"]/ }
@Test @CompileStatic void NVGS_Test() {
final x0 =9876 final x1 =2.7 final String s0 ="abc" final s1 ="DEFGH" final gs0
="val0:$x0" final GString gs1 ="val1:$x1" final nameAndValue4d = NVGS(x0, gs0, s0, s1, x1, gs1)
final result ="variables: |${nameAndValue4d}|" println result
assert result ==/variables: |x0=9876, gs0="val0:9876", s0="abc", s1="DEFGH", x1=2.7,
gs1="val1:2.7"|/ }
@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"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)}" }