call name of method contained in a string - groovy

How can I call a method based on the value of a string in Groovy? For example instead of
switch (val) {
case "one":
Obj.one()
break
case "two":
Obj.two()
break
}
I’d like to do something like obj.val where val contains either "one" or "two" instead of a case statement.

Dynamic method invocation looks like this
obj."$val"()

Related

Using a range in a groovy case statement

I'm writing a Jenkins pipeline, and I'd like to use a groovy switch statement to match on a range on int values so I don't have to write a case for each number in the range. Not used to groovy, so apologies if this is a simple question. For example (not working):
switch (diskuse) {
case 1-5: //this doesn't work
println('disk use is under 50')
break
case [5-9]: //this also doesn't work
println('disk use is OVER 50!')
break
default: //the switch always hits this case
println('no disk use info available')
}
The correct range literal looks like 1..5 in Groovy.
Your switch op shall look like so:
switch (diskuse) {
case 1..5: //inclusive range
println('disk use is under 50')
break
case 5..<9: //exclusive range, 9 is exluded
println('disk use is OVER 50!')
break
default:
println('no disk use info available')
}

groovy iterate through list of key and value

I have this list:
service_name_status=[a-service=INSTALL, b-service=UPGRADE, C-service=UPGRADE, D-service=INSTALL]
And I need to iterate through this list so the first element will be the value of a parameter called "SERVICE_NAME" and the second element will be the value of a parameter called "HELM_COMMAND",
after asserting those values to the parameters I will run my command that uses those parameters and then continue the next items on the list which should replace the values of the parameters with items 3 and 4 and so on.
So what I am looking for is something like that:
def service_name_status=[a-service=INSTALL, b-service=UPGRADE, C-service=UPGRADE, D-service=INSTALL]
def SERVICE_NAME
def HELM_COMMAND
for(x in service_name_status){
SERVICE_NAME=x(0,2,4,6,8...)
HELM_COMMAND=x(1,3,5,7,9...)
println SERVICE_NAME=$SERVICE_NAME
println HELM_COMMAND=$HELM_COMMAND
}
the output should be:
SERVICE_NAME=a-service
HELM_COMMAND=INSTALL
SERVICE_NAME=b-service
HELM_COMMAND=UPGRADE
SERVICE_NAME=c-service
HELM_COMMAND=UPGRADE
SERVICE_NAME=d-service
HELM_COMMAND=INSTALL
and so on...
I couldn't find anything that takes any other element in groovy, any help will be appreciated.
The collection you want is a Map, not a List.
Take note of the quotes in the map, the values are strings so you need the quotes or it won't work. You may have to change that at the source where your data comes from.
I kept your all caps variable names so you will feel at home, but they are not the convention.
Note the list iteration with .each(key, value)
This will work:
Map service_name_status = ['a-service':'INSTALL', 'b-service':'UPGRADE', 'C-service':'UPGRADE', 'D-service':'INSTALL']
service_name_status.each {SERVICE_NAME, HELM_COMMAND ->
println "SERVICE_NAME=${SERVICE_NAME}"
println "HELM_COMMAND=${HELM_COMMAND}"
}
EDIT:
The following can be used to convert that to a map. Be careful, the replaceAll part is fragile and depends on the data to always look the same.
//assuming you can have it in a string like this
String st = "[a-service=INSTALL, b-service=UPGRADE, C-service=UPGRADE, D-service=INSTALL]"
//this part is dependent on format
String mpStr = st.replaceAll(/\[/, "['")
.replaceAll(/=/, "':'")
.replaceAll(/]/, "']")
.replaceAll(/, /, "', '")
println mpStr
//convert the properly formatted string to a map
Map mp = evaluate(mpStr)
assert mp instanceof java.util.LinkedHashMap

How to check if a String contains multiple values and ignore case with StringUtils

I wrote a method to check if a string contains various values.
def validateString(metricValue: String): Boolean = {
(!StringUtils.containsIgnoreCase(metricValue, "metric_1")
&& StringUtils.containsIgnoreCase(metricValue, "metric_2")
|| StringUtils.containsIgnoreCase(metricValue, "metric_3")
}
Then I decided to reduce the last two checks to a single one but haven't found anything that may be helpful in commons-lang-2.6.
I know there is a similar method in lang 3: StringUtils.equalsAnyIgnoreCase(str, "val1", "val2", "val3")). But I need something like containsAnyIgnoreCase.
Is there a way to check if any of multiple values is present in a String ignoring the case?
Try
List("metric_2", "metric_3")
.map(_.toLowerCase)
.contains(metricValue.toLowerCase)
If you want to use StringUtils:
def validateString(metricValue: String): Boolean =
List("metric_2", "metric_3").exists(metricToCheck => StringUtils.containsIgnoreCase(metricValue, metricToCheck))

How can I reference an unnamed argument of a when expression?

I have a when expression that looks something like this:
when(foo.toString()){
"" ->'A'
"HELLO" ->'B'
"GOODBYE"->'C'
else ->foo.toString()[0]//problematic method call duplication
}
Now, I don't want to call foo.toString() twice, but I also want this to remain a single expression. Is there a convenient way for me to access the value I passed into the when expression in its else block, such as the it or this# syntax found elsewhere in the language?
I'm currently using the following work-around:
with(foo.toString()){
when(this){
"" ->'A'
"HELLO" ->'B'
"GOODBYE"->'C'
else ->this[0]
}
}
But this introduces another block, and is less readable than I'd like. Is there a better solution?
For the when block there's no variable specified, but you can use the let() function for a similar behavior which might be a little better than your workaround, but behaving the same.
foo.toString().let{
when(it){
"" ->'A'
"HELLO" ->'B'
"GOODBYE"->'C'
else ->it[0]
}
}

Switching on String Value Yields Unexpected Results in Groovy

I am working in a groovy/grails set up and am having some trouble trying to execute a switch statement on a String value.
Basically, I am looping through the attribute names in a webservice response to see if they match pre-defined mappings that are configured on a per user basis. If they have established a mapping on that field, I pull the value out of the response and use it elsewhere.
The code looks something like this:
switch(attributeName)
{
case {attributeName} :
log.info("Currently switching on value... ${attributeName}")
case user.getFirstNameMapping():
model.user.userInfo.firstName = attributeValue
break
case user.getLastNameMapping():
model.user.userInfo.lastName = attributeValue
break
case user.getAuthenticationKeyMapping():
model.authenticationValue = attributeValue
break
case user.getEmailMapping():
model.email = attributeValue.toLowerCase()
break
}
The value being switched on (attributeName) is of type String, and the getter methods for the user instance also return type String.
Based on my research and understanding of the Groovy language, switching on an Object such as a String should end up using String.equals() to make the comparison. The result, however, is that it is matching on the user.getFirstNameMapping() case every time, and repeatedly overwriting the value in the model; therefore, the last value that comes back in the response is what ends up saved, and none of the other values are saved.
What's interesting is that if I use an if/else structure and do something like this:
if(attributeName.equals(user.getFirstNameMapping())
{
...
}
It works fine every time. I've verified through logging that it's not something silly like extra whitespace or a capitalization issue. I've also tried changing things around to run the switch by default and explicitly compare the attributeName in the case like this:
switch(true)
{
case {attributeName} :
log.info("Currently switching on value... ${attributeName}")
case {user.getFirstNameMapping().equals(attributeName)}:
model.user.userInfo.firstName = attributeValue
break
case {user.getLastNameMapping().equals(attributeName)}:
model.user.userInfo.lastName = attributeValue
break
case {user.getAuthenticationKeyMapping().equals(attributeName)}:
model.authenticationValue = attributeValue
break
case {user.getEmailMapping().equals(attributeName)}:
model.email = attributeValue.toLowerCase()
break
}
And it still fails to meet my expectations in the exact same way. So, I'm wondering why this is the behavior when the switch statement should simply be using .equals() to compare the strings, and when I explicitly compare them in an if/else using .equals(), it works as expected.
The issue is in your switch case.
Have a look here :-
case {attributeName} :
log.info("Currently switching on value... ${attributeName}")
case user.getFirstNameMapping():
model.user.userInfo.firstName = attributeValue
break
As you can see your these two cases will run every time because the switch condition is :-
switch(attributeName)
So the first one will get match and will run until it encounters break; which is at after case 2 i.e. case user.getFirstNameMapping(): so i would suggest you to print the value of {attributeName} before the swtich starts.
Hope that will help you.
Thanks
I don't know exactly what's your issue, but the case statement works just fine, even with methods. See my example
String something = "Foo"
class User {
String firstName
String lastName
}
User u = new User(firstName: 'Something', lastName:'Foo')
switch(something) {
case u.getFirstName():
println "firstName: ${u.firstName}"
break;
case u.getLastName():
println "lastName: ${u.lastName}"
break;
default:
println "nothing..."
}
This code will print lastName as expected.
​

Resources