This is an automated email from the ASF dual-hosted git repository.
paulk pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/groovy.git
The following commit(s) were added to refs/heads/master by this push:
new 77919a1 documentation for records (cont'd) plus minor
refactoring/cleanup
77919a1 is described below
commit 77919a1502280df0986772cd1f3b925292e11512
Author: Paul King <[email protected]>
AuthorDate: Sat Oct 30 10:39:08 2021 +1000
documentation for records (cont'd) plus minor refactoring/cleanup
---
.../groovy/transform/ImmutableASTTransformation.java | 5 +++--
.../transform/RecordTypeASTTransformation.java | 2 +-
src/spec/doc/_records.adoc | 20 ++++++++++++++------
src/spec/test/RecordSpecificationTest.groovy | 11 +++++++++++
4 files changed, 29 insertions(+), 9 deletions(-)
diff --git
a/src/main/java/org/codehaus/groovy/transform/ImmutableASTTransformation.java
b/src/main/java/org/codehaus/groovy/transform/ImmutableASTTransformation.java
index 0f2f760..695d551 100644
---
a/src/main/java/org/codehaus/groovy/transform/ImmutableASTTransformation.java
+++
b/src/main/java/org/codehaus/groovy/transform/ImmutableASTTransformation.java
@@ -31,6 +31,7 @@ import org.codehaus.groovy.ast.AnnotationNode;
import org.codehaus.groovy.ast.ClassHelper;
import org.codehaus.groovy.ast.ClassNode;
import org.codehaus.groovy.ast.FieldNode;
+import org.codehaus.groovy.ast.MethodNode;
import org.codehaus.groovy.ast.Parameter;
import org.codehaus.groovy.ast.PropertyNode;
import org.codehaus.groovy.ast.VariableScope;
@@ -287,7 +288,7 @@ public class ImmutableASTTransformation extends
AbstractASTTransformation implem
);
}
- static void createCopyWith(final ClassNode cNode, final List<PropertyNode>
pList) {
+ static MethodNode createCopyWith(final ClassNode cNode, final
List<PropertyNode> pList) {
BlockStatement body = new BlockStatement();
body.addStatement(ifS(
orX(
@@ -311,7 +312,7 @@ public class ImmutableASTTransformation extends
AbstractASTTransformation implem
final ClassNode clonedNode = cNode.getPlainNodeReference();
- addGeneratedMethod(cNode, "copyWith",
+ return addGeneratedMethod(cNode, "copyWith",
ACC_PUBLIC | ACC_FINAL,
clonedNode,
params(new Parameter(new ClassNode(Map.class), "map")),
diff --git
a/src/main/java/org/codehaus/groovy/transform/RecordTypeASTTransformation.java
b/src/main/java/org/codehaus/groovy/transform/RecordTypeASTTransformation.java
index bfb8f95..ba62ec7 100644
---
a/src/main/java/org/codehaus/groovy/transform/RecordTypeASTTransformation.java
+++
b/src/main/java/org/codehaus/groovy/transform/RecordTypeASTTransformation.java
@@ -185,7 +185,7 @@ public class RecordTypeASTTransformation extends
AbstractASTTransformation imple
if (unsupportedTupleAttribute(tupleCons, "callSuper")) return;
}
- if (!pList.isEmpty() && memberHasValue(node, "copyWith", Boolean.TRUE)
&& !hasDeclaredMethod(cNode, "copyWith", 1)) {
+ if (!pList.isEmpty() && !memberHasValue(node, "copyWith",
Boolean.FALSE) && !hasDeclaredMethod(cNode, "copyWith", 1)) {
ImmutableASTTransformation.createCopyWith(cNode, pList);
}
}
diff --git a/src/spec/doc/_records.adoc b/src/spec/doc/_records.adoc
index 235ce47..0ca5c30 100644
--- a/src/spec/doc/_records.adoc
+++ b/src/spec/doc/_records.adoc
@@ -57,7 +57,9 @@
include::../test/RecordSpecificationTest.groovy[tags=record_message_equivalent,i
----
Note the special naming convention for record getters. They are the same name
as the field
-(rather than the otherwise common JavaBean convention of capitalized with a
"get" prefix).
+(rather than the often common JavaBean convention of capitalized with a "get"
prefix).
+Rather than refering to a records fields or properties, the term _component_
+is typicaly used for records. So our `Message` record has `from`, `to`, and
`body` components.
Like in Java, you can override the normally implicitly supplied methods
by writing your own:
@@ -148,16 +150,22 @@
include::../test/RecordSpecificationTest.groovy[tags=record_point2d_tostring_ann
We can see here that without the package name it would have the same toString
as our previous example.
-=== CopyWith
+=== Copying
-For a record with many fields, it can be useful to make a copy with one or
more fields changes.
-This can be enabled by setting the `copyWith` annotation attribute to `true`:
+It can be useful to make a copy of a record with some components changed.
+This can be done using a provided `copyWith` method which takes named
arguments.
+Record components are set from the supplied arguments.
+For components not mentioned, a (shallow) copy of the original record
commponent is used.
+Here is how you might use `copyWith` for the `Fruit` record:
[source,groovy]
----
include::../test/RecordSpecificationTest.groovy[tags=record_copywith,indent=0]
----
+The `copyWith` functionality can be disabled by setting the
+`RecordBase#copyWith` annotation attribute to `false`.
+
=== Deep immutability
As with Java, records by default offer shallow immutability.
@@ -173,8 +181,8 @@ These examples illustrates the principal behind
Groovy's record feature offering three levels of convenience:
* Using the `record` keyword for maximum succinctness
-* Support low-ceremony customization using declarative annotations
-* Provide normal method implementations when full control is required
+* Supporting low-ceremony customization using declarative annotations
+* Allowing normal method implementations when full control is required
== Other differences to Java
diff --git a/src/spec/test/RecordSpecificationTest.groovy
b/src/spec/test/RecordSpecificationTest.groovy
index 13ff0ae..e8fe883 100644
--- a/src/spec/test/RecordSpecificationTest.groovy
+++ b/src/spec/test/RecordSpecificationTest.groovy
@@ -110,6 +110,17 @@ def orange = apple.copyWith(name: 'Orange')
assert orange.toString() == 'Fruit[name=Orange, price=11.6]'
// end::record_copywith[]
'''
+ assertScript '''
+import groovy.transform.RecordBase
+import static groovy.test.GroovyAssert.shouldFail
+
+@RecordBase(copyWith=false)
+record Fruit(String name, double price) {}
+def apple = new Fruit('Apple', 11.6)
+shouldFail(MissingMethodException) {
+ apple.copyWith(name: 'Orange')
+}
+'''
}
void testImmutable() {