Groovy way to conditionally append to a String - groovy

Good old java way to conditionally append something to string is as follows:
if (booleanFlag) {
myString += "something to append"
}
Can I do the same in more groovy way, ideally in one line?

A very Groovy way to do this would be with GStrings:
"$myString${booleanFlag ? 'something to append' : ''}"

Here is a groovy way using GString closures:
>>> def world = false
>>> def people = true
>>>
>>> def message = "Hello${sw -> if (world) sw << ' World'; if (people) sw << ' People'}"
>>>
>>> message
Hello People
>>>
>>> people = false
>>> world = true
>>>
>>> message
Hello World
>>>
>>> world = false
>>> message
Hello
The string looks kinda long and could do with some indentation, but groovy shell did not allow me to split the lines. Switched to an IDE, turns out you can write the string better like this (with the help of triple quote strings):
def message =
"""Hello${sw ->
if (false) sw << ' World!'
if (false) sw << ' People!'
if (true) sw << ' Groovy!'
}"""
Now that's groovy!

Try:
def b = true
def s = 's'
s += b ? 's' : ''

Here's a solution creating a String.metaClass.when method:
String.metaClass.when = { it ? delegate : '' }
Testing:
flag = true
myString = 'foo '
myString += "to append".when flag
assert myString == 'foo to append'
myString = 'foo ' + "to append".when(false)
assert myString == 'foo '

I think this pattern is a good candidate for some meta-programming.
def myString = 'Hello'
use(StringBuilderCategory) {
assert new StringBuilder(myString).append(true, 'World').toString() == 'HelloWorld'
assert new StringBuilder(myString).append(false, 'World').toString() == 'Hello'
}
class StringBuilderCategory {
static StringBuilder append(StringBuilder builder, boolean condition, String str) {
if(condition) {
builder.append(str)
} else {
builder
}
}
}
I used a StringBuilder to avoid implying that Strings are mutable, but a similar method can be added to String to get it down to this:
use(TheCategory) {
myString = myString.append(booleanFlag, 'something to append')
}
Of course there's the option of using the meta class instead of a category.

Looks like one line to me:
if (booleanFlag) myString += "something to append";

Related

How to change variables with in a string into a Map

I have let's say 100 variables in a string , my requirement is to automatically create a Map out of the string:
String str = "$$test$$ $$test2$$ $$test$$ $$test3$$"
Expected Result:
["test":test, "test2":test2, "test3":test3];
EDIT (for dsharew)
This is the last version of my code
def list = queryText.findAll(/\$\$(.*?)\$\$/)
def map = [:]
list.each{
log.debug(it)
it = it.replace("\$\$", "")
log.debug(it)
map.putAt(it, it)
}
log.debug(list)
log.debug(map)
queryText = queryText.replaceAll(/\$\$(.*?)\$\$/) { k -> map[k[1]] ?: k[0] }
log.debug(queryText)
And the logs print the following result:
$$test$$
test
$$test2$$
test2
$$test$$
test
$$test3$$
test3
[$$test$$, $$test2$$, $$test$$, $$test3$$]
{test=test, test2=test2, test3=test3}
test test2 test test3
This should do what you want:
def queryText = "\$\$test\$\$ \$\$test2\$\$ \$\$test\$\$ \$\$test3\$\$"
toMap(queryText.findAll(/\$\$(.*?)\$\$/));
def toMap(list){
def map = [:]
list.each{
it = it.replace("\$\$", "")
map.putAt(it, it)
};
println map;
return map;
}
Following #dsharew answer, I've reduced it a little bit more:
​def queryText = "\$\$test\$\$ \$\$test2\$\$ \$\$test\$\$ \$\$test3\$\$"
def resultMap = queryText
.findAll(/\$\$(.*?)\$\$/)
.collectEntries { String next ->
[next.replace("\$\$", "")] * 2
}
collectEntries can be used to return a map from a collection if it returns a map or a tuple for every entry in the collection.
If you multiply a list by n, you are creating a bigger list with n times its content
BTW cool problem!
This is what I came up with
String str = '$$test$$ $$test2$$ $$test$$ $$test3$$'
str.replaceAll('\\$\\$', '').split(' ').collectEntries { [(it):it] }

evaluating value of an expression as expression in groovy

Here is the code i am trying to get working
def expr = ''
List params = []
params << 'filter-name'
params << 'servlet-name'
params << 'url-pattern'
params.each{expr = expr+ "it.'${it}'.text().trim()#"}
expr = expr.substring(0, expr.length()-1)
consNodes.each{
println "data is:$"{expr}"
println "actual : ${it.'filter-name'.text().trim()}#${it.'servlet-name'.text().trim()}#${it.'url-pattern'.text().trim()}"
}
in the above result comes like
data is:it.'filter-name'.text().trim()#it.'servlet-name'.text().trim()#it.'url-pattern'.text().trim()
actual : presenceLogoutFilter##/adfAuthentication/*
data is:it.'filter-name'.text().trim()#it.'servlet-name'.text().trim()#it.'url-pattern'.text().trim()
actual : remoteApplication##/rr/*
data is:it.'filter-name'.text().trim()#it.'servlet-name'.text().trim()#it.'url-pattern'.text().trim()
actual : ServletADFContextFilter#GetHandler#
data is:it.'filter-name'.text().trim()#it.'servlet-name'.text().trim()#it.'url-pattern'.text().trim()
actual : ServletADFContextFilter##/PresenceServlet/*
So, as you can see that my constructed expression is not able to evaluate further. Any advise on how to make it work?
The problem is that you're creating a GString like this: "it.'${it}'.text().trim()#", but then you're converting it into a String when you concatenate it: expr + "it.'${it}'.text().trim()#". Once you turn a GString into a String it no longer evaluates expressions. But even if you address that it won't solve your problem because GStrings do not evaluate like you think they do. The best way to explain it is with an example:
import org.codehaus.groovy.runtime.GStringImpl
// What you're doing
def a = 'John'
def b = 'Hello, $a'
def c = "${a}"
assert b == 'Hello, $a'
// What the compiler is doing (ignoring the variable name changes)
def aa = 'John'
def bb = 'Hello, $a'
def cc = new GStringImpl([] as Object[], ['Hello, $a'] as String[])
assert cc == 'Hello, $a'
// What you want the compiler to do, but it will not.
def aaa = 'John'
def bbb = 'Hello, $a'
def ccc = new GStringImpl(['John'] as Object[], ['Hello, '] as String[])
assert ccc == 'Hello, John'
If you really want to, you can build the GStrings manually, but that will be very difficult. And you'd end up depending on a class which is not guaranteed to remain backward-compatible between Groovy releases.
Here's what you can do instead:
def params = []
params << 'filter-name'
params << 'servlet-name'
params << 'url-pattern'
def evaluators = params.collect {
{ attr, node -> node[attr]?.text()?.trim() ?: '' }.curry(it)
}
consNodes.each { node ->
println evaluators.collect { c -> c(node) }.join('#')
}
The output looks like this:
presenceLogoutFilter##/adfAuthentication/*
remoteApplication##/rr/*
ServletADFContextFilter#GetHandler#
ServletADFContextFilter##/PresenceServlet/*
Instead of a single large expression you and up with a list of closures, each responsible for evaluating a node attribute. Then, you can join the results with '#'s.

How to check whether the input is a number or string by using isNan() in groovy

Hello i am a beginner to groovy i am cofused how to check whether the given input is a number or not i tried the following
def a= ' 12.571245ERROR'
if(a.isNan()==0)
{
println("not a number")
}
else
{
println("number")
}
Kindly help me how to use isNan in groovy.I googled it lot but didnt find any result . Thanks in advance
Groovy's String::isNumber() to the rescue:
def a = "a"
assert !a.isNumber()
def b = "10.90"
assert b.isNumber()
assert b.toDouble() == 10.90
To answer your question, I would not consider isNan(). It is mentioned on the web, but it does not appear in the String doc for the GDK.
Consider this:
def input = "12.37"
def isNumber = input.isDouble()
println "isNumber : ${isNumber}"
Or use something that is more Java-esque:
def input = "12.37error"
def isNumber = false
try {
double value = Double.parseDouble(input)
isNumber = true
} catch (Exception ex) {
}
println "isNumber : ${isNumber}"
You can try to cast it to number and catch an exception if its not a number
def a= ' 12.571245ERROR'
try {
a as Double
println "a is number"
}catch (e) {
println "a is not a number"
}
Or
if(a instanceof Number)
println "Number"
else
println "NaN"
Although keep in mind, in the second way of checking it, it would fail even if a is a valid number but in a String like "123". 123 is Number but "123" is not.
This will fail for the number format with commas (eg: 10,00,000)
def aNumber = "10,00,000"
aNumber.isNumber() and aNumber.isDouble() give answer as false.

How I can find the contents of inner nesting?

Lets say I have a string like this :
string = [+++[>>[--]]]abced
Now I want a someway to return a list that has: [[--],[>>],[+++]]. That is the contents of the deepest [ nesting followed by other nesting. I came up with this solution like this :
def string = "[+++[>>[--]]]"
loop = []
temp = []
string.each {
bool = false
if(it == "["){
temp = []
bool = true
}
else if( it != "]")
temp << it
if(bool)
loop << temp
}
println loop.reverse()
But this indeed takes the abced string after the last ] and put into the result!. But what I want is only [[--],[>>],[+++]]
Are there any groovy way of solving this?
You can use this, if you wouldn't mind using recursion
def sub(s , list){
if(!s.contains('[') && !s.contains('['))
return list
def clipped = s.substring(s.lastIndexOf('[')+1, s.indexOf(']'))
list.add(clipped)
s = s - "[$clipped]"
sub(s , list)
}
Calling
sub('''[+++[>>[--]]]abced''' , [])
returns a list of all subportions enclosed between braces.
['--', '>>', '+++']
If your brackets are symmetrical, you could just introduce a counter variable that holds the depth of the bracket nesting. Only depth levels above 0 are allowed in the output:
def string = "[+++[>>[--]]]abc"
loop = []
temp = []
depth = 0;
string.each {
bool = false
if(it == "["){
temp = []
bool = true
depth++;
}
else if (it == "]"){
depth--;
}
else if (depth > 0){
temp << it
}
if(bool){
loop << temp
}
}
println loop.reverse()
class Main {
private static final def pattern = ~/([^\[]*)\[(.+?)\][^\]]*/
static void main(String[] args) {
def string = "[+++[>>[--]]]abced"
def result = match(string)
println result
}
static def match(String val) {
def matcher = pattern.matcher(val);
if (matcher.matches()) {
return matcher.group(1) ? match(matcher.group(2)) + matcher.group(1) : match(matcher.group(2))
}
[val]
}
}
System.out
[--, >>, +++]
The capturing of the first group in the regex pattern could probably be improved. Right now the first group is any character that is not [ and if there are nothing in front of the first [ then the first group will contain an empty string.

How do I enumerate all the defined variables in a groovy script

I have a groovy script with an unknown number of variables in context at runtime, how do I find them all and print the name and value of each?
Well, if you're using a simple script (where you don't use the "def" keyword), the variables you define will be stored in the binding and you can get at them like this:
foo = "abc"
bar = "def"
if (true) {
baz = "ghi"
this.binding.variables.each {k,v -> println "$k = $v"}
}
Prints:
foo = abc
baz = ghi
args = {}
bar = def
I'm not aware of an easy way to enumerate through the variables defined with the "def" keyword, but I'll be watching this question with interest to see if someone else knows how.
Actually, Ted's answer will also work for 'def'ed variables.
def foo = "abc"
def bar = "def"
if (true) {
baz = "ghi"
this.binding.variables.each {k,v -> println "$k = $v"}
}
yields
baz = ghi
__ = [null, null, null]
foo = abc
_ = null
bar = def
I'm not sure what the _-variables signify, but I'm sure you can work around them.
Groovy Object contains method - dump()
https://docs.groovy-lang.org/latest/html/groovy-jdk/java/lang/Object.html
String dump()
Generates a detailed dump string of an object showing its class, hashCode and fields.
Example:
class MyClass {
def foo = "abc"
def bar = "def"
}
println(new MyClass().dump())
stdout: <MyClass#1fa268de foo=abc bar=def>

Resources