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

2018-11-06 Thread paulk
Repository: groovy
Updated Branches:
  refs/heads/GROOVY_2_5_X f3c2b77bc -> 62c72a773


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/62c72a77
Tree: http://git-wip-us.apache.org/repos/asf/groovy/tree/62c72a77
Diff: http://git-wip-us.apache.org/repos/asf/groovy/diff/62c72a77

Branch: refs/heads/GROOVY_2_5_X
Commit: 62c72a773fc6540c74d209dfc02475a617ac5f94
Parents: f3c2b77
Author: Paul King 
Authored: Wed Nov 7 14:11:54 2018 +1000
Committer: Paul King 
Committed: Wed Nov 7 14:18: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/62c72a77/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/62c72a77/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 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)

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

2018-11-06 Thread paulk
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 
Authored: Wed Nov 7 14:11:54 2018 +1000
Committer: Paul King 
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 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::spr