6

I would like to know if it is possible to retrieve the name of a variable.

For example if I have a method:

def printSomething(def something){
//instead of having the literal String something, I want to be able to use the name of the variable that was passed
println('something is: ' + something)
}

If I call this method as follows:

 def ordinary = 58
 printSomething(ordinary)

I want to get:

ordinary is 58

On the other hand if I call this method like this:

def extraOrdinary = 67
printSomething(extraOrdinary)

I want to get:

extraOrdinary is 67

Edit

I need the variable name because I have this snippet of code which runs before each TestSuite in Katalon Studio, basically it gives you the flexibility of passing GlobalVariables using a katalon.features file. The idea is from: kazurayam/KatalonPropertiesDemo

  @BeforeTestSuite
    def sampleBeforeTestSuite(TestSuiteContext testSuiteContext) {
        KatalonProperties props = new KatalonProperties()
        // get appropriate value for GlobalVariable.hostname loaded from katalon.properties files
        WebUI.comment(">>> GlobalVariable.G_Url default value: \'${GlobalVariable.G_Url}\'");

//gets the internal value of GlobalVariable.G_Url, if it's empty then use the one from katalon.features file
            String preferedHostname = props.getProperty('GlobalVariable.G_Url')
            if (preferedHostname != null) {
                GlobalVariable.G_Url = preferedHostname;
                WebUI.comment(">>> GlobalVariable.G_Url new value: \'${preferedHostname}\'");
            } else {
                WebUI.comment(">>> GlobalVariable.G_Url stays unchanged");
            }
 //doing the same for other variables is a lot of duplicate code
        }

Now this only handles 1 variable value, if I do this for say 20 variables, that is a lot of duplicate code, so I wanted to create a helper function:

def setProperty(KatalonProperties props, GlobalVariable var){
   WebUI.comment(">>> " + var.getName()" + default value: \'${var}\'");

//gets the internal value of var, if it's null then use the one from katalon.features file
            GlobalVariable preferedVar = props.getProperty(var.getName())
            if (preferedVar != null) {
                var = preferedVar;
                WebUI.comment(">>> " + var.getName() + " new value: \'${preferedVar}\'");
            } else {
                WebUI.comment(">>> " + var.getName() + " stays unchanged");
            }
}

Here I just put var.getName() to explain what I am looking for, that is just a method I assume.

Mate Mrše
  • 7,997
  • 10
  • 40
  • 77
street_jesus
  • 373
  • 5
  • 17
  • @Carcigenicate it's not purely out of curiosity, I need to use the variable name for passing it to a function: `KatalonProperties.getProperty(String key)` which retrieves the value of a property based on the name of the property. I can change the parameter to be a String instead of **def** to control what is passed to my function...but I still need to know how to get the name of a variable – street_jesus Apr 02 '19 at 16:48
  • No, it's not possible – tim_yates Apr 02 '19 at 16:54
  • @tim_yates well that's a bummer :( – street_jesus Apr 02 '19 at 16:55
  • The stack would be immense – tim_yates Apr 02 '19 at 16:56
  • Possible duplicate of https://stackoverflow.com/questions/24319732/how-to-get-name-of-a-variable-in-groovy – Aditya T Apr 02 '19 at 17:01
  • 2
    @AdityaT don't think it's a duplicate. That's about getting the argument name. This is about getting the name of the variable that was passed to the method – tim_yates Apr 02 '19 at 17:17
  • @tim_yates Looks legit, my bad. :) – Aditya T Apr 02 '19 at 17:28
  • 1
    @tim_yate isn't that possible with Macro-Methods, or am I wrong here? – Mene Apr 02 '19 at 17:42

2 Answers2

3

Yes, this is possible with ASTTransformations or with Macros (Groovy 2.5+).

I currently don't have a proper dev environment, but here are some pointers:

Not that both options are not trivial, are not what I would recommend a Groovy novice and you'll have to do some research. If I remember correctly either option requires a separate build/project from your calling code to work reliable. Also either of them might give you obscure and hard to debug compile time errors, for example when your code expects a variable as parameter but a literal or a method call is passed. So: there be dragons. That being said: I have worked a lot with these things and they can be really fun ;)

Groovy Documentation for Macros

If you are on Groovy 2.5+ you can use Macros. For your use-case take a look at the @Macro methods section. Your Method will have two parameters: MacroContext macroContext, MethodCallExpression callExpression the latter being the interesting one. The MethodCallExpression has the getArguments()-Methods, which allows you to access the Abstract Syntax Tree Nodes that where passed to the method as parameter. In your case that should be a VariableExpression which has the getName() method to give you the name that you're looking for.

Developing AST transformations

This is the more complicated version. You'll still get to the same VariableExpression as with the Macro-Method, but it'll be tedious to get there as you'll have to identify the correct MethodCallExpression yourself. You start from a ClassNode and work your way to the VariableExpression yourself. I would recommend to use a local transformation and create an Annotation. But identifying the correct MethodCallExpression is not trivial.

Mene
  • 3,739
  • 21
  • 40
  • that sounds like too much work for my level of expertise :( – street_jesus Apr 02 '19 at 17:06
  • Didn't mean to discourage you :/ But maybe best to learn the basics and then come back. Groovy is super powerful and becomes even more powerful when you start to play with the AST ;) – Mene Apr 02 '19 at 17:08
-1

no. it's not possible.

however think about using map as a parameter and passing name and value of the property:

def printSomething(Map m){
    println m
}

printSomething(ordinary:58)
printSomething(extraOrdinary:67)
printSomething(ordinary:11,extraOrdinary:22)

this will output

[ordinary:58]
[extraOrdinary:67]
[ordinary:11, extraOrdinary:22]
daggett
  • 26,404
  • 3
  • 40
  • 56
  • Wrong answer. It is possible to get the name of variable. – Aditya T Apr 02 '19 at 17:18
  • Apologies dude, I actually mistook the question, right I am not sure if its possible or not. :D Can you edit the answer to clarify the point that its possible for method arguments but not for variable name. :) – Aditya T Apr 02 '19 at 17:26
  • @AdityaT if it's possible for method arguments, then I can work with that too. – street_jesus Apr 03 '19 at 13:43
  • Ok , I will add a answer than. – Aditya T Apr 03 '19 at 14:52
  • @AdityaT looking forward to your answer. – street_jesus Apr 03 '19 at 17:55
  • Well, I have to admit it's not possible or I don't know how to get it done, the link I posted for being duplicate is actually not working I tried that myself before actually posting an answer, but metaClass didn't seem to contain any information on variable or method parameters. – Aditya T Apr 04 '19 at 03:00
  • I am not sure why was metaClass.methods accepted as answer in that post. – Aditya T Apr 04 '19 at 03:01