How do nested expressions work in groovy? - groovy

Right now I'm doing this:
// Returns a string that needs to be manipulated
def str = callSomeFunc arg1:'sdfsdf', arg2:'blah', arg3:'sdfs'
str = str.trim()
Because this doesn't work:
def str = (callSomeFunc arg1:'sdfsdf', arg2:'blah', arg3:'sdfs').trim()

Have a look at the docs:
In some cases parentheses are required, such as when making nested
method calls or when calling a method without parameters.
In your case this will work also:
def str = callSomeFunc(arg1:'sdfsdf', arg2:'blah', arg3:'sdfs').trim()

Related

Groovy from 2nd dimentional array to 1 dimentional as string with prefix

I have an 2 dimentional array:
def test = [[88,3,2],[22,33,4],[88,3,3]]
test.sort
what i need now is to create each item into string and prefix it with string "test-"
so the end result would ne one dimentional array:
def endResult = ["test-88.3.2"],["test-88.3.3"],["test-22.33.4"]
if i do:
test.each {println it.join(".")}
it prints the first part but as written i need to save it and add prefix
im new to groovy any help would be great
The each method does not produce any result - it only iterates the input collection and allows you to do something with each element (e.g. print it to the console like in the example you showed in your question.)
If you want to manipulate each element of the collection and store it as a new collection, you can use the collect method which also takes a closure as a parameter. This closure is applied to each element of the input collection, and the return value of this closure is used to return a new collection from the collect method.
Something like this should do the trick for you:
def test = [[88,3,2],[22,33,4],[88,3,3]]
def endResult = test.collect { 'test-' + it.join('.') }
println endResult // [test-88.3.2, test-22.33.4, test-88.3.3]
It's worth mentioning that the closure we passed to the collect method uses so-called implicit return - there is no return keyword, but the value it produces from 'test-' + it.join('.') is returned implicitly.

type mismatch; found : String required: Int

I wrote a program which processes a string using functional programming style. It gives an odd "type mismatch;
found : String
required: Int" error on this line else if(c==('s')) helper1(s(str), s.drop(1)). Thanks in advance.
def stringpipeline(string:String) : (String) => String = {
def r(s:String):String = {s.reverse}
def s(s:String) = {s.sorted}
def U(s:String) = {s.toUpperCase}
def l(s:String) = {s.toLowerCase}
def star(s:String):String = {s.trim}
def T(s:String):String = {s.split(' ').map(_.capitalize).mkString(" ")}
def helper1(str:String, s:String): String = {
if (s.length != 0)
{
val c = s(0)
if(c==('T')) helper1(T(str), s.drop(1))
if(c==('s')) helper1(s(str), s.drop(1))
if(c==('*')) helper1(star(str),s.drop(1))
else str
}
else str
}
def helper2(strn:String): String = {helper1(strn,string)}
helper2 _
}
helper1(s(str), s.drop(1))
In code s(str) you're calling String.apply(Int) method. str is String, so compiler notifies about it
The problem is that you have declared s in two different scopes. In the overall scope you have declared s as a method which acts on a String and returns a String. In the scope of helper1() you have also declared s as a String parameter. This declaration overrides (shadows) the declaration of the method s outside helper1().
Where the error is reported, you are trying to use the method s(str), but the compiler is picking up the declaration s:String. You should fix this by renaming the name of either the method or the parameter. In general I would suggest avoiding single character names for methods, parameters or variables and instead using longer and more descriptive names - this is not a requirement to fix this problem, but you would have been more likely to avoid it by using, for example, sorted().

How to validate a Map snippet in groovy

I have an dynamic html file that groovy is generated from. Part of this html template format is {routeId}{groovyMap} like so
USER_FORM[name:'Dean', user:randomFunction([item:'s', day:'Tuesday'])]
or something like
USER_FORM[name: 'Dean', user: user]
I made the first example more complex. Currently, I split on ':' and validate all the keys supplied. What I would like to do is take the groovy snippet and grab all the keys and validate
1. all keys are strings
2. validate the keys against some meta data I already have
I do not care about the values at all. Currently, I split on ':' but obviously that won't work for all cases. I am worried about other complex cases I may not be thinking about.
This is for a templating engine and I prefer to failfast if possible making it easier on the user when something is wrong.
I concur with others that you want to avoid parsing directly.
If you use GroovyShell, you can dope the input string with no-op methodMissing and propertyMissing handlers. In this way, even the complex example will work.
See code below, including test-cases (extracting map string from the "USER_FORMstr" format is left to the reader).
class KeyGenerator {
// these could be "final static". omitted for brevity
def shell = new GroovyShell()
def methodMissingHandler = "def methodMissing(String name, args) {}"
def propertyMissingHandler = "def propertyMissing(String name) {}"
def generateKeys(mapStr) {
def evalInput = "${methodMissingHandler} ; " +
"${propertyMissingHandler} ; " +
"${mapStr}"
def map = shell.evaluate(evalInput)
return map.keySet()
}
}
// ------- main
def keyGenerator = new KeyGenerator()
def expected = new HashSet()
expected << "name"
expected << "user"
def mapStr = "[name:'Dean', user:randomFunction([item:'s', day:'Tuesday'])]"
assert expected == keyGenerator.generateKeys(mapStr)
def mapStr2 = "[name: 'Dean', user: user]"
assert expected == keyGenerator.generateKeys(mapStr2)
If I got you right, you can use something like:
String val = "USER_FORM[name:'Dean', user:randomFunction([item:'s', day:'Tuesday'])]"
def res = []
val.eachMatch( /[\[,] ?(\w+):/ ){ res << it[ 1 ] }
assert '[name, user, item, day]' == res.toString()
all keys are strings
When using the literal syntax for creating a Map, i.e.
Map m = [foo: 'bar']
as opposed to
Map m = new HashMap()
m.put('foo', 'bar')
the keys are always strings, even if you have a variable in scope with the same name as the key. For example, in the following snippet, the key will be the string 'foo', not the integer 6
def foo = 6
Map m = [foo: 'bar']
The only way you can create a Map using the literal syntax with a key that is not a string is if you have a variable in scope with the same name as the key and you wrap the key name in parentheses. For example, in the following snippet, the key will be the integer 6, not the string 'foo'
def foo = 6
Map m = [(foo): 'bar']
Currently, I split on ':' but obviously that won't work for all cases. I am worried about other complex cases I may not be thinking about.
Parsing a map literal using regex/string splitting seems like a bad idea as you'll likely end up badly re-implementing the Groovy lexer. Something like the following seems a better option
def mapString = '[foo: "bar"]'
Map map = Eval.me(mapString)
// now you can process the map via the Map interface, e.g.
map.keySet().toList() == ['foo']

How to include Groovy G-String in a Regular Expression

I would think there would be many applications for the subject in general. I can illustrate with an example. Consider that I want a way to pull out a standard (maven) version from a released jar file. Regular expressions can be used something like:
def m = (~/.*-someUniquePortionHere-(.*)\.jar$/).matcher(jarFileName)
m.matches()
String version = "${m.group(1)}"
So the above is over-simplified, but, it works for that UniquePortion - and it helps keep the question simple. If I want to wrap this in a method that takes the unique portion in as a parameter, can I still use the slashy strings? I would like to include "$uniquePortion" in the regular expression. That is, what should the following be?
def exampleMethod(String uniquePortion, String jarFileName) {
// what would this look like here?
def m =
m.matches()
"${m.group(1)"
}
Why not? Slashy strings ARE GStrings as well. see link
def unique = "groovy-all"
def m = (~/.*$unique(.*)\.jar$/).matcher("groovy-all:2.2.jar")
m.matches()
String version = "${m.group(1)}"
assert version == ":2.2"
You can still concatenate the slashy strings together:
def test = "foo-bar-1.4.jar"
def bar = "bar"
def m = test =~ /.*-/ + bar + /-(.*).jar$/
assert m.matches() // true
assert m.group(1) == "1.4" // true

EachWithIndex groovy statement

I am new to groovy and I've been facing some issues understanding the each{} and eachwithindex{} statements in groovy.
Are each and eachWithIndex actually methods? If so what are the arguments that they take?
In the groovy documentation there is this certain example:
def numbers = [ 5, 7, 9, 12 ]
numbers.eachWithIndex{ num, idx -> println "$idx: $num" } //prints each index and number
Well, I see that numbers is an array. What are num and idx in the above statement? What does the -> operator do?
I do know that $idx and $num prints the value, but how is it that idx and num are automatically being associated with the index and contents of the array? What is the logic behind this? Please help.
These are plain methods but they follow quite a specific pattern - they take a Closure as their last argument. A Closure is a piece of functionality that you can pass around and call when applicable.
For example, method eachWithIndex might look like this (roughly):
void eachWithIndex(Closure operation) {
for (int i = 0; this.hasNext(); i++) {
operation(this.next(), i); // Here closure passed as parameter is being called
}
}
This approach allows one to build generic algorithms (like iteration over items) and change the concrete processing logic at runtime by passing different closures.
Regarding the parameters part, as you see in the example above we call the closure (operation) with two parameters - the current element and current index. This means that the eachWithIndex method expects to receive not just any closure but one which would accept these two parameters. From a syntax prospective one defines the parameters during closure definition like this:
{ elem, index ->
// logic
}
So -> is used to separate arguments part of closure definition from its logic. When a closure takes only one argument, its parameter definition can be omitted and then the parameter will be accessible within the closure's scope with the name it (implicit name for the first argument). For example:
[1,2,3].each {
println it
}
It could be rewritten like this:
[1,2,3].each({ elem ->
println elem
})
As you see the Groovy language adds some syntax sugar to make such constructions look prettier.
each and eachWithIndex are, amongst many others, taking so called Closure as an argument. The closure is just a piece of Groovy code wrapped in {} braces. In the code with array:
def numbers = [ 5, 7, 9, 12 ]
numbers.eachWithIndex{ num, idx -> println "$idx: $num" }
there is only one argument (closure, or more precisely: function), please note that in Groovy () braces are sometime optional. num and idx are just an optional aliases for closure (function) arguments, when we need just one argument, this is equivalent (it is implicit name of the first closure argument, very convenient):
def numbers = [ 5, 7, 9, 12 ]
numbers.each {println "$it" }
References:
http://groovy.codehaus.org/Closures
http://en.wikipedia.org/wiki/First-class_function
Normally, if you are using a functional programing language such as Groovy, you would want to avoid using each and eachWithIndex since they encourage you to modify state within the closure or do things that have side effects.
If possible, you may want to do your operations using other groovy collection methods such as .collect or .inject or findResult etc.
However, to use these for your problem, i.e print the list elements with their index, you will need to use the withIndex method on the original collection which will transform the collection to a collection of pairs of [element, index]
For example,
println(['a', 'b', 'c'].withIndex())
EachWithIndex can be used as follows:
package json
import groovy.json.*
import com.eviware.soapui.support.XmlHolder
def project = testRunner.testCase.testSuite.project
def testCase = testRunner.testCase;
def strArray = new String[200]
//Response for a step you want the json from
def response = context.expand('${Offers#Response#$[\'Data\']}').toString()
def json = new JsonSlurper().parseText(response)
//Value you want to compare with in your array
def offername = project.getPropertyValue("Offername")
log.info(offername)
Boolean flagpresent = false
Boolean flagnotpresent = false
strArray = json.Name
def id = 0;
//To find the offername in the array of offers displayed
strArray.eachWithIndex
{
name, index ->
if("${name}" != offername)
{
flagnotpresent= false;
}
else
{
id = "${index}";
flagpresent = true;
log.info("${index}.${name}")
log.info(id)
}
}

Resources