You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@groovy.apache.org by pa...@apache.org on 2018/11/07 04:12:15 UTC

groovy git commit: GROOVY-8870: Spread-dot operator on list of lists

Repository: groovy
Updated Branches:
  refs/heads/master 7fd540fba -> bf87f243f


GROOVY-8870: Spread-dot operator on list of lists


Project: http://git-wip-us.apache.org/repos/asf/groovy/repo
Commit: http://git-wip-us.apache.org/repos/asf/groovy/commit/bf87f243
Tree: http://git-wip-us.apache.org/repos/asf/groovy/tree/bf87f243
Diff: http://git-wip-us.apache.org/repos/asf/groovy/diff/bf87f243

Branch: refs/heads/master
Commit: bf87f243fb7ebcaf6c2d621773cc575411c531b7
Parents: 7fd540f
Author: Paul King <pa...@asert.com.au>
Authored: Wed Nov 7 14:11:54 2018 +1000
Committer: Paul King <pa...@asert.com.au>
Committed: Wed Nov 7 14:12:09 2018 +1000

----------------------------------------------------------------------
 src/spec/doc/core-operators.adoc   | 28 +++++++++++++++++--
 src/spec/test/OperatorsTest.groovy | 49 +++++++++++++++++++++++++++++++++
 2 files changed, 74 insertions(+), 3 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/groovy/blob/bf87f243/src/spec/doc/core-operators.adoc
----------------------------------------------------------------------
diff --git a/src/spec/doc/core-operators.adoc b/src/spec/doc/core-operators.adoc
index 31f409d..716d1eb 100644
--- a/src/spec/doc/core-operators.adoc
+++ b/src/spec/doc/core-operators.adoc
@@ -422,8 +422,8 @@ include::{projectdir}/src/spec/test/OperatorsTest.groovy[tags=pattern_matcher_st
 
 === Spread operator
 
-The Spread Operator (`*.`) is used to invoke an action on all items of an aggregate object. It is equivalent to calling the action on each item
-and collecting the result into a list:
+The Spread-dot Operator (`*.`), often abbreviated to just Spread Operator, is used to invoke an action on all items
+of an aggregate object. It is equivalent to calling the action on each item and collecting the result into a list:
 
 [source,groovy]
 ----
@@ -433,7 +433,14 @@ include::{projectdir}/src/spec/test/OperatorsTest.groovy[tags=spreaddot,indent=0
 <2> call the spread operator on the list, accessing the `make` property of each item
 <3> returns a list of strings corresponding to the collection of `make` items
 
-The spread operator is null-safe, meaning that if an element of the collection is null, it will return null instead of throwing a `NullPointerException`:
+The expression `cars*.make` is equivalent to `cars.collect{ it.make }`.
+Groovy's GPath notation allows a short-cut when the referenced property
+isn't a property of the containing list, in that case it is automatically
+spread. In the previously mentioned case, the expression `cars.make` can
+be used, though retaining the explicit spread-dot operator is often recommended.
+
+The spread operator is null-safe, meaning that if an element of the collection is null,
+it will return null instead of throwing a `NullPointerException`:
 
 [source,groovy]
 ----
@@ -450,6 +457,21 @@ The spread operator can be used on any class which implements the `Iterable` int
 include::{projectdir}/src/spec/test/OperatorsTest.groovy[tags=spreaddot_iterable,indent=0]
 ----
 
+Use multiple invocations of the spread-dot operator (here `cars*.models*.name`) when
+working with aggregates of data structures which themselves contain aggregates:
+
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/OperatorsTest.groovy[tags=spreaddot_multilevel,indent=0]
+----
+
+Consider using the `collectNested` DGM method instead of the spread-dot operator for collections of collections:
+
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/OperatorsTest.groovy[tags=spreaddot_alternative,indent=0]
+----
+
 ==== Spreading method arguments
 
 There may be situations when the arguments of a method call can be found in a list that you need to adapt to the method

http://git-wip-us.apache.org/repos/asf/groovy/blob/bf87f243/src/spec/test/OperatorsTest.groovy
----------------------------------------------------------------------
diff --git a/src/spec/test/OperatorsTest.groovy b/src/spec/test/OperatorsTest.groovy
index 474f8b6..d4d34ee 100644
--- a/src/spec/test/OperatorsTest.groovy
+++ b/src/spec/test/OperatorsTest.groovy
@@ -356,6 +356,55 @@ assert composite*.id == [1,2]
 assert composite*.name == ['Foo','Bar']
 // end::spreaddot_iterable[]
 '''
+        assertScript '''
+import groovy.transform.Canonical
+
+// tag::spreaddot_multilevel[]
+class Make {
+    String name
+    List<Model> models
+}
+
+@Canonical
+class Model {
+    String name
+}
+
+def cars = [
+    new Make(name: 'Peugeot',
+             models: [new Model('408'), new Model('508')]),
+    new Make(name: 'Renault',
+             models: [new Model('Clio'), new Model('Captur')])
+]
+
+def makes = cars*.name
+assert makes == ['Peugeot', 'Renault']
+
+def models = cars*.models*.name
+assert models == [['408', '508'], ['Clio', 'Captur']]
+assert models.sum() == ['408', '508', 'Clio', 'Captur'] // flatten one level
+assert models.flatten() == ['408', '508', 'Clio', 'Captur'] // flatten all levels (one in this case)
+// end::spreaddot_multilevel[]
+'''
+        assertScript '''
+// tag::spreaddot_alternative[]
+class Car {
+    String make
+    String model
+}
+def cars = [
+   [
+       new Car(make: 'Peugeot', model: '408'),
+       new Car(make: 'Peugeot', model: '508')
+   ], [
+       new Car(make: 'Renault', model: 'Clio'),
+       new Car(make: 'Renault', model: 'Captur')
+   ]
+]
+def models = cars.collectNested{ it.model }
+assert models == [['408', '508'], ['Clio', 'Captur']]
+// end::spreaddot_alternative[]
+'''
     }
 
     void testSpreadMethodArguments() {