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)}" }

Reply via email to