groovy list spreading - groovy

If you run the following Groovy code, the assertion passes
def foo(a, b) {
a + b
}
assert 'aaabbb' == foo(['aaa', 'bbb'])
This suggests that if a method is called with a List parameter that contains X elements, then the List will be spread and a method with X arguments will be invoked.
Of course, this will only happen if there isn't a method defined with a single parameter of type List (or ancestor thereof).
I only discovered this quite recently when reading another SO Groovy answer. I've never seen it mentioned in the Groovy docs, release notes, or books. Is it a hidden feature, a bug, or just something I've missed?

Going to be removed in Groovy 2 apparently:
http://groovy.329449.n5.nabble.com/removing-features-in-Groovy-2-td4422494.html
JT's first on the to-remove list and it seems everyone (with clout) on Groovy User agrees.

Related

Groovy - strange Collection#intersect behaviour

I have code like that:
def a1 = [[1],[2],[3]]
def a2 = [[2],[3],[4]]
a1.intersect(a2)
and as result got:
[]
After some time of research i found out that elements of lists must be instance of Comparable. In DefaultGroovyMethods we can see implementation of intersect method. First thing i noted was the collection (TreeSet) used for checking existence of objects in one of our lists (btw. if HashSet used it worked fine).
I checked the NumberAwareComparator there are two options for checking in compareTo method. The first is the delegation of comparison to another class (eaten exception ?!) and the second is hashCode checking.
The first option DefaultTypeTransformation explained us the behavior.
We can see that only allowed object to be compare are Comparable in other case we got exception eaten later.
My question is why is it like that? There is lack of information in documentation (or am i wrong?) about it. Did i missed something?
Can't find it documented.
Feels like a great pull request contribution to the project on github with a change to the existing documentation/javadoc to make this more explicit?
The elements have to be comparable, as otherwise you can't compare them to check for an intersection, but you're right the documentation isn't explicit.
You could write your own implementation like so:
Collection.metaClass.equalityIntersect = { Collection other ->
delegate.findAll { a -> other.find { it == a } }
}
So that a1.equalityIntersect(a2) == [[2], [3]]
This behavior has been introduced somewhere down the line - haven't pin-pointed it, maybe 2.4.2 or 2.4.2 as per this commit. It used to work in 2.2.1 and 2.4.0 and is broken on 2.4.6... but it's fixed in 2.4.7.
$ groovy -v
Groovy Version: 2.4.7 JVM: 1.8.0_92 Vendor: Oracle Corporation OS: Mac OS X
$ groovy intersect.groovy
[[2], [3]]
How can such breaking change roll out to a release is a mystery to me. Lack of testing?

Where can I find an overview of how the ec2.instancesCollection is built

In boto3 there's a function:
ec2.instances.filter()
The documentation:
http://boto3.readthedocs.org/en/latest/reference/services/ec2.html#instance
Say it returns a list(ec2.Instance) I wish...
when I try printing the return I get this:
ec2.instancesCollection(ec2.ServiceResource(), ec2.Instance)
I've tried searching for any mention of an ec2.instanceCollection, but the only thing I found was something similar for ruby.
I'd like to iterate through this instanceCollection so I can see how big it is, what machines are present and things like that.
Problem is I have no idea how it works, and when it's empty iteration doesn't work at all(It throws an error)
The filter method does not return a list, it returns an iterable. This is basically a Python generator that will produce the desired results on demand in an efficient way.
You can use this iterator in a loop like this:
for instance in ec2.instances.filter():
# do something with instance
or if you really want a list you can turn the iterator into a list with:
instances = list(ec2.instances.filter())
I'm adding this answer because 5 years later I had the same question and went round in circles trying to find the answer.
First off, the return type in the documentation is wrong (still). As you say, it states that the return type is: list(ec2.Instance)
where it should be:ec2.instancesCollection.
At the time of writing there's an open issue in github covering this - https://github.com/boto/boto3/issues/2000.
When you call the filter method a ResourceCollection is created for the particular type of resource against which you called the method. In this case the resource type is instance which gives an instancesCollection. You can see the code for the ResourceCollection superclass of instancesCollection here:
https://github.com/boto/boto3/blob/develop/boto3/resources/collection.py
The documentation here gives an overview of the collections: https://boto3.amazonaws.com/v1/documentation/api/latest/guide/collections.html
To get to how to use it and actually answer your question, what I did was to turn the iterator into a list and iterate over the list if the size is > 0.
testList = list(ec2.instances.filter(Filters=filters))
if len(testList) > 0;
for item in testList;
.
.
.
This may well not be the best way of doing it but it worked for me.

prolog recursive searching with contraints

I have a house with rooms that are defined with connections for when you can go from one room to another eg.
connection(garage,sidehall).
connection(sidehall,kitchen).
connection(kitchen,diningroom).
canget(X,Y):-connection(X,Y).
canget(X,Y):-connection(X,_),
write('player goes from '),write(X),write(' to '),write(Y),nl,
canget(_,Y).
Im trying to figure out how make it so the player can only get from one room to another when they have a specific item, such as you can only be in the kitchen when items = gloves.
canget(X,Y,Item):-connection(X,Y,Item),canbein(Y,Item).
canget(X,Y,Item):-connection(X,Somewhere,Item),canbein(Somewhere,Item),canget(Somewhere,Y,Item).
tried defining canbein with:
canbein(kitchen):- item(sword).
canbein(sidehall):- item(hat).
but that doesnt work!
Have defined my items as such, not sure if this is right either:
item(gloves,sword,helm,cheese).
Basically, have i declared my item values correctly?
How can i use the specific item value to make canget x to y false?
Thank you!
Well, I see a few problems with your code. Firstly, you call canbein with two arguments (from canget predicate). However, canbein is defined as single-argument predicate. Therefore, the call always fails as no canbein/2 predicate exists.
I suggest the following modification:
canbein(kitchen, sword).
canbein(sidehall, hat).
Than, the item definition is not required. Let's think about what happens during the unification of
canget(X,Y,Item) :- connection(X,Y,Item), canbein(Y,Item).
Let's assume the following setting X=sidehall, Y=kitchen, Item==sword. This predicate should be OK. Assuming the conection predicate is OK, prolog tries to find canbein(Y, Item) i.e. canbein(kitchen, sword) and it succeeds.
On the contrary, if the Item is different the unification fails, hence it works as expected.
The second problem is the item predicate. By your definition, it expects 4 arguments. That's nonsense, of course. You should declare it like
item(gloves).
item(sword).
item(helm).
item(cheese).
However, I don't think this predicate is necessary at all. Just to be clear, try to call item(X) and obtain all results (the four declared). Try it with the prior definition - what should you even ask for?
I hope it helps :)

Groovy slash operator (Jenkins job-dsl)

We would like to understand a couple of legacy job-dsl scripts but don't know what "slash operator" means in this context (as it cant be division):
def command = (shells.first() / command)
We have tried to look it up in several Groovy books but only found the trivial solution that it means 'division'.
It's an XML Node operation, to return a sub-node of a XML node, or create it if it doesn't exist. Probably the command node under the first of your shells nodes here.
Groovy allows operator overloading, so it is the same "division" operator, just redefined somewhat. This is common (but also controversial) in other languages allowing operator overloading, but does allow for richer DSLs.
Having had a quick look at (an old copy of) the JobDSL source, it seems that they're doing it using a class NodeEnhancement, notably this JavaDoc:
/**
Add div and leftShift operators to Node.
div - Will return the first child that matches name, and if it doesn't exists, it creates
...
**/

JUnit AssertSame fails on object.toString in groovy

I am trying to test the overridden toString() in groovy (I know it is trivial but that is what you get after reading kent beck's TDD book).
I assertSame on the expected string and the actual
Here is the code block:
#Test void testToString(){
def study = new Study(identifier:"default-study", OID:"S_DEFAULTS1", name:"Default Study")
def expected = "org.foo.oc.model.bar(OID:S_DEFAULTS1, name:Default Study, identifier:default-study)"
assertSame "Should be equal", expected, study.toString()
}
Here is the stack trace for the failed test:
junit.framework.AssertionFailedError: Should be equal expected same:org.foo.oc.model.bar(OID:S_DEFAULTS1, name:Default Study, identifier:default-study) was not:org.foo.oc.model.bar(OID:S_DEFAULTS1, name:Default Study, identifier:default-study)
at junit.framework.Assert.fail(Assert.java:47)
at junit.framework.Assert.failNotSame(Assert.java:273)
at junit.framework.Assert.assertSame(Assert.java:236)
Just to add that assertEquals works well with the same parameters.
I know it is no biggie but I want to understand why it fails.
Thanks
Why aren't you using assertEquals which uses .equals()? assertSame compares object references (== operator). Even though the strings are the same, they are two different objects, hence the assertion is failing.
UPDATE: This is a very common mistake in Java: String.equals() and == operator work differently. This has been discussed several times:
How do I compare strings in Java?
Java String.equals versus ==
Difference between Equals/equals and == operator?
I know you are using Groovy which does not suffer this problem, but JUnit is written in Java and behaves according to the rules above.
UPDATE: actually, your string are different:
org.foo.oc.model.bar(OID:S_DEFAULTS1, name:Default Study, identifier:default-study)
org.foo.oc.model.bar(OID:S_DEFAULTS1, name:Default Study, identifier:default-study)
Your original uses lowercase d in "default Study" but your expected string does not.
EDIT: when comparing strings you should always use equals() rather than comparing references. Two strings that pass the equals() test may or may not also be the same object.
BTW, in Groovy == is the same as equals().

Resources