Groovy Array of Strings - groovy

I know curly brackets are not used to initialize array in Groovy but I have noticed one peculiar thing.
Why groovy doesn't give compiler error when I initialize an array like this.
String emailAddress = "test#gmail.com";
String [] var = {emailAddress};
println var[0];
Output: com.test.examples.GroovyTest$_main_closure1#12e4860e
When I try to declare like this I get error:
String [] var = {"a","b"};
Can anybody explain this?

When you do:
String [] var = {emailAddress};
That creates a Closure that returns a String emailAddress, and then crams that closure into a String array (by calling toString() on it), as that's what you told it to do ;-)
So var equals ['ConsoleScript0$_run_closure1#60fd82c1'] (or similar, depending on where you're running things)
When you do:
String [] var = {"a","b"};
The right-hand side is not a valid Closure, so the script fails to parse.
What you want is:
String[] var = ['a', 'b']
Or:
String[] var = [emailAddress]

Related

For comprehension parsing of optional string to int

Say I have the following for comprehension:
val validatedInput = for {
stringID <- parseToInt(optionalInputID)
} yield (stringID)
where optionalInputID is an input parameter of type Option[String]. I want to be able to convert an Option[String] into just a String, if of course there is an option present. As far as I'm aware, you cannot case match inside a for comprehension.
Some details have been omitted, such as other for comprehension items. Therefore I would like to know if it's possible to do this inside the for comprehension. If not, then what's a suitable alternative? Can I do it outside of the for comprehension?
Simply add it to the for comprehension:
val validatedInput = for {
inputID <- optionalInputID
stringID <- parseToInt(inputID)
} yield (stringID)
It will work only if parseToInt has type of Option. If it returns something of Try, you can't do it - because you can't mix Try and Option in the same for-comprehension.
If parseToInt returns Try, you can do the following:
val validatedInput = for {
inputID <- optionalInputID
stringID <- parseToInt(inputID).toOption
} yield (stringID)
I want to be able to convert an Option[String] into just a String.
Therefore I would like to know if it's possible to do this inside the for comprehension
In Scala, for-comprehension desugars into a combinitation of map, flatMap, filter, none of which allows to extract the value out of the Option.
If not, then what's a suitable alternative? Can I do it outside of the for comprehension?
To do so you can use one of get (unsafe), or it safer version getOrElse, or fold:
val validatedInput: Option[String] = Some("myString")
scala>validatedInput.get
// res1: String = "myString"
scala>validatedInput.getOrElse("empty")
// res2: String = "myString"
scala>validatedInput.fold("empty")(identity)
// res3: String = "myString"

How to declare a string array in Groovy?

How can I declare a string array in Groovy? I am trying as below but it is throwing an error
def String[] osList = new String[]
No expression for the array constructor call at line:
What am i doing wrong?
First of: welcome to SO!
You have a few options for creating arrays in groovy.
But let's start with what you've done wrong.
def String[] osList = new String[]
You used both def and String[] here.
Def is an anonymous type, which means that groovy will figure out which type it is for you.
String[] is the declared type, so what groovy will see here is:
String[] String[] osList = new String[]
which obviously won't work.
Arrays however need a fixed size, which needs to be given as an argument to the creation of the Array:
Type[] arr = new Type[sizeOfArray]
in your case if you'd want to have 10 items in the array you would do:
String[] osList = new String[10]
if you do not know how many Strings you will have, use a List instead. An ArrayList will do for this in most cases:
List<String> osList = new ArrayList<>()
now you can add items by calling:
osList.add("hey!")
or using groovy's list-add operator:
osList << "hey!"
For further issues you should refer to groovy's official documentation and see if you can't find the solution yourself!
A simple way is
String[] osList = []
assert osList.class.array
assert 'java.lang.String[]' == osList.class.typeName
Another question is that this definition is rather useless. This is an immutable zero-lenght String[] and can be used only as a constant somewhere.
​def arr = [] as String[]
or
String[] arr = [] as String[]
This should do it. You can test it and play around in here: https://groovyconsole.appspot.com/

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']

Get [String] from NSUserDefaults.standardUserDefaults().dictionaryRepresentation().keys

NSUserDefaults.standardUserDefaults().dictionaryRepresentation().keys returns [NSObject] but I need (and would expect) [String]. Is it just some coffee I'm missing?
dictionaryRepresentation() returns NSDictionary that does not support generic types. You can convert to Swift dictionary:
let dictionary = NSUserDefaults.standardUserDefaults().dictionaryRepresentation() as [String : AnyObject]
let keys = dictionary.keys
That actually returns a LazyBidirectionalCollection<MapCollectionView<Dictionary<Key, Value>, Key>>. You can add .array to get an array instance back, then use map to cast the values to String:
let keys = NSUserDefaults.standardUserDefaults().dictionaryRepresentation().keys.array.map { $0 as String }
println(keys)
// [NSLanguages, NSInterfaceStyle, AppleLanguages]

Resources