how to get rid of "null" when concating string in groovy? - groovy

I have a class
class A{
String name
String address
}
def a = new A()
a.address = "some address"
println "${a.name} ${a.address}" => "null some address"
Here a.name is null, so the string printed will contains "null", however I hope the result is "some address" which ignore the null value.
I know I can use println "${a.name ?: ''} ${a.address ?: ''}" when printing, is there any simpler solution?

You could redefine the toString method for Groovy's null object to return an empty string instead of null.
def a = [a:null, b:'foobar']
println "${a.a} ${a.b}"
org.codehaus.groovy.runtime.NullObject.metaClass.toString = {return ''}
println "${a.a} ${a.b}"
This will print:
null foobar
foobar
If you only want to redefine toString temporarily, add the following after your last print... to change it back:
org.codehaus.groovy.runtime.NullObject.metaClass.toString = {return 'null'}
You can also change null's toString behavior using a Groovy Category [1] [2]. For example:
#Category(org.codehaus.groovy.runtime.NullObject) class MyNullObjectCategory {def toString() {''}}
use (MyNullObjectCategory) {
println "${a.a} ${a.b}"
}

You could implement a toString method in your class like so:
class A{
String name
String address
String toString() {
"${name ?: ''} ${address ?: ''}".trim()
}
}
then do
def a = new A( address:'some address' )
println a
To get some address printed out, but this still used the Elvis operator as you had in your question...
Not sure there's much simpler you can do...

Not sure if simpler, but:
[a.name, a.address].findAll().join(' ')
You may of course combine it with Tim's toString suggestion.
Notice that if any of the values might be "falsy" (e.g. 0), it will filter it out. You can fix that doing:
[a.name, a.address].findAll {it != null}.join(' ')

I think, a rather simple way of achieving it, i.e. removing null, is to concatenate the string and the use replace method.
myString=""
myString=myString + "Bla Bla"
myString.replace("null", '')

Related

Groovy - Replace ${} within a string

I receive a string like this: "The code is ${code}. Your currency is ${currency}".
The ${...} characters are already part of the string, not variables.
I have a map with key-value and I would like to replace all the occurrences of the ${key} with the value:
def myMap = [
'code' : '123456',
'currency' : 'CHF'
]
myMap.each{
fieldValue.replaceAll("${$.key}", it.value)
}
The expected result is the following one: "The code is 123456. Your currency is CHF".
I'm stuck because I don't know how to deal with the $ {} character escapes. I can escape the $ character but not {}. Any idea in order to achieve the expected result?
You need to quote the outer $ and use it.key: "\\${$it.key}"
Also you can use each here as it is for side-effects and replaceAll
does not modify the string (strings in java are immutable). So you need
something like this:
def result = myMap.inject(fieldValue){ acc, kv ->
acc.replaceAll("\\${$kv.key}", kv.value)
}
Or by using a regexp:
fieldValue.replaceAll(/\$\{(.+?)\}/, { _, k -> myMap[k] })
It works also with closure and with delegate strategy. You can evaluate your string in the context of the map. See this example:
def myMap = [
'code' : '123456',
'currency' : 'CHF'
]
closure = { "The code is ${code}. Your currency is ${currency}" }
closure.delegate = myMap
println closure()

java.lang.ClassCastException: geb.content.TemplateDerivedPageContent thrown when comparing two numbers as strings

I need to compare number of values against one parent within method:
def checkFilterAppliedByPriceDescending() {
firstPriceValue.text().replace(/\D*/, "")
allPrices.each() {
if (it.text().replace(/\D*/, "") > firsPriceValue) {
throw new Exception("Wrong price found: " + it)
}
}
}
I use with regex to eliminate all non-digits so it would look like 99999 for example. However, when I run the test I get following error:
checkFilterAppliedByPriceDescending()
|
java.lang.ClassCastException: geb.content.TemplateDerivedPageContent cannot be cast to java.base/java.lang.String
at SearchPageFiltersTest.Can navigate to AutoHero Search Page(RouterTest.groovy:21)
Caused by:
java.lang.ClassCastException: geb.content.TemplateDerivedPageContent cannot be cast to java.base/java.lang.String
Could you please help me understanding what's wrong with the method and how it can be fixed?
You have to be aware that
firstPriceValue.text().replace(/\D*/, "")
does not mutate firstPriceValue. Method text() returns a String representation and Strings are immutable, so calling replace() on a String returns a new one and does not mutate the String you called the method on. To fix it you have to capture the result from the above method and assign it to a variable, for instance:
def price = firstPriceValue.text().replace(/\D*/, "")
Another thing is that comparing Strings with > won't work as you expect. Take a look at this example from Groovy shell:
groovy:000> '9999' > '10000'
===> true
To avoid such problems you would have to cast number represented as String to a numeric value, BigDecimal for instance:
groovy:000> ('9999' as BigDecimal) > ('10000' as BigDecimal)
===> false
And lastly, you can use collection's every() method to make sure that all prices match specific predicate. Something like this:
def price = firstPriceValue.text().replace(/\D*/, "") as BigDecimal
assert allPrices.every {
def currentPrice = it.text().replace(/\D*/, "") as BigDecimal
return currentPrice > price
}
allPrices.every() will return true if all prices match given predicate and false otherwise.

how can i append to each line in scala and why is it saying unit?

im doing something stupid to try to send html email and not really understanding what im doing but I want to send a multiline string to a function and get the same string back with something appended to each line - what am i doing wrong?
def htmlizetext(intext: String) {
for(line <- intext.linesWithSeparators) {
<br>line<br/>
}
}
def htmlizetext(intext: String): String = {
for(line <- intext.linesWithSeparators) {
line + "<br/>"
}
}
Neither of the above work
You need yield, = (without = the method will still return Unit) and some form of concatenation:
def htmlizetext(intext: String) = {
for (line <- intext.linesWithSeparators) yield {
line + "<br/>
}
}.mkString
or the shorter equivalent:
def htmlizetext(intext: String) =
intext.linesWithSeparators.map(_ + "<br/>").mkString
Have a look at yield, that is probably what you are looking for.
def htmlizetext(intext: String) = {
for(line <- intext.linesWithSeparators) yield {
<br>line<br/>
}
}
You might additionally want to join all the elements from the returning list for returning a single String instead of a list of such strings
You are currently not returning a thing from your method as you do not return anything from your for statement which is the last method of your statement. Therefore, the Scala compiler infers that you are returning Unit.
Because for does't have a return value, unless you use yield...
A better solution would be to "map" your collection as follows:
intext.linesWithSeparators.map(line=> s"$line<br/>").mkString("")
this will turn your string in the desired format and then join all of them using mkString. If you need it, you can specify a separator instead of empty string

What does this code do in Groovy?

def host = /\/\/([a-zA-Z0-9-]+(\.[a-zA-Z0-9-])*?)(:|\/)/
assertHost 'http://a.b.c.d:8080/bla', host, 'a.b.c.d'
def assertHost (candidate, regex, expected){
candidate.eachMatch(regex){assert it[1] == expected}
}
I know the above code is asserting my inputs! But in line 4, inside the closure, the magic variable (it) is being represented in an array! I'm bit confused on it. How does it work?
How does this work in Groovy (illustrate with simple code)?
From http://groovy.codehaus.org/groovy-jdk/java/lang/String.html:
replaceAll
public String replaceAll(String regex, Closure closure)
Replaces all occurrences of a captured group by the result of a closure on that text.
For examples,
assert "hellO wOrld" == "hello world".replaceAll("(o)") { it[0].toUpperCase() }
assert "FOOBAR-FOOBAR-" == "foobar-FooBar-".replaceAll("(([fF][oO]{2})[bB]ar)", { Object[] it -> it[0].toUpperCase() })
Here,
it[0] is the global string of the matched group
it[1] is the first string in the matched group
it[2] is the second string in the matched group

very simple groovy, map and closure question, but what I'm doing wrong

This is OK
def variables=[
['var1':'test1'],
['var2':'test2'],
['var3':'test3']
]
println "${variables.size()}"
variables.each{entry ->
println "${entry} "
}
I got:
3
[var1:test1]
[var2:test2]
[var3:test3]
but this caused problems
def variables=[
['var1':'test1'],
['var2':'test2'],
['var3':'test3']
]
println "${variables.size()}"
variables.each{entry ->
println "${entry.key} "
}
since I got:
3
null
null
null
I'm expecting:
3
var1
var2
var3
what's wrong with my code?
thank you!!!
You want:
def variables=[
'var1':'test1',
'var2':'test2',
'var3':'test3'
]
println variables.size()
variables.each{entry ->
println entry.key
}
Before you had an ArrayList containing three LinkedHashMap objects. The above code is a single LinkedHashMap with three entries. You also don't need string interpolation, so I removed it.
Matthew's solution works great, and it's probably what you wanted (a simpler data structure to begin with).
However, in case you really wanted variables to be a list of three maps (as per your question), then this how you could get your desired output:
def variables=[
['var1':'test1'],
['var2':'test2'],
['var3':'test3']
]
println "${variables.size()}"
variables.each{ entry->
entry.each {
println it.key
}
}
In the outer closure, every entry is a map. So we iterate through each of those maps using the inner closure. In this inner closure, every it closure-param is a key:value pair, so we just print its key using it.key.
Like Matthew, I've also removed the string interpolation since you don't need it.

Resources