groovy-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From pa...@apache.org
Subject [groovy] branch master updated: GROOVY-9019: triple-single and triple-double quotes handle backslash escapes equally (improve doco further)
Date Sat, 23 Mar 2019 06:28:00 GMT
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 ec04ec7  GROOVY-9019: triple-single and triple-double quotes handle backslash escapes
equally (improve doco further)
ec04ec7 is described below

commit ec04ec7f39f63e869427481b295e554b043bfae8
Author: Paul King <paulk@asert.com.au>
AuthorDate: Sat Mar 23 16:27:49 2019 +1000

    GROOVY-9019: triple-single and triple-double quotes handle backslash escapes equally (improve
doco further)
---
 src/spec/doc/core-syntax.adoc   | 47 ++++++++++++++++++++++++++++++++---------
 src/spec/test/SyntaxTest.groovy | 46 ++++++++++++++++++++++++++--------------
 2 files changed, 67 insertions(+), 26 deletions(-)

diff --git a/src/spec/doc/core-syntax.adoc b/src/spec/doc/core-syntax.adoc
index c566daa..16fb6ed 100644
--- a/src/spec/doc/core-syntax.adoc
+++ b/src/spec/doc/core-syntax.adoc
@@ -244,8 +244,9 @@ include::{projectdir}/src/spec/test/SyntaxTest.groovy[tags=triple_single_0,inden
 
 NOTE: Triple-single-quoted strings are plain `java.lang.String` and don't support interpolation.
 
-Triple-single-quoted strings are multiline.
-You can span the content of the string across line boundaries without the need to split the
string in several pieces, without contatenation or newline escape characters:
+Triple-single-quoted strings may span multiple lines.
+The content of the string can cross line boundaries without the need to split the string
in several pieces
+and without concatenation or newline escape characters:
 
 [source,groovy]
 ----
@@ -351,8 +352,11 @@ NOTE: To escape a double quote, you can use the backslash character:
+"A double
 
 Any Groovy expression can be interpolated in all string literals, apart from single and triple-single-quoted
strings.
 Interpolation is the act of replacing a placeholder in the string with its value upon evaluation
of the string.
-The placeholder expressions are surrounded by `${}` or prefixed with `$` for dotted expressions.
-The expression value inside the placeholder is evaluated to its string representation when
the GString is passed to a method taking a String as argument by calling `toString()` on that
expression.
+The placeholder expressions are surrounded by `${}`. The curly braces may be omitted for
unambiguous dotted expressions,
+i.e. we can use just a $ prefix in those cases.
+If the GString is ever passed to a method taking a String, the expression value inside the
placeholder
+is evaluated to its string representation (by calling `toString()` on that expression) and
the resulting
+String is passed to the method.
 
 Here, we have a string with a placeholder referencing a local variable:
 
@@ -361,7 +365,7 @@ Here, we have a string with a placeholder referencing a local variable:
 include::{projectdir}/src/spec/test/SyntaxTest.groovy[tags=gstring_1,indent=0]
 ----
 
-But any Groovy expression is valid, as we can see in this example with an arithmetic expression:
+Any Groovy expression is valid, as we can see in this example with an arithmetic expression:
 
 [source,groovy]
 ----
@@ -380,7 +384,8 @@ In addition to `${}` placeholders, we can also use a lone `$` sign prefixing
a d
 include::{projectdir}/src/spec/test/SyntaxTest.groovy[tags=gstring_3,indent=0]
 ----
 
-But only dotted expressions of the form `a.b`, `a.b.c`, etc, are valid, but expressions that
would contain parentheses like method calls, curly braces for closures, or arithmetic operators
would be invalid.
+But only dotted expressions of the form `a.b`, `a.b.c`, etc, are valid. Expressions containing
parentheses like method calls,
+curly braces for closures, dots which aren't part of a property expression or arithmetic
operators would be invalid.
 Given the following variable definition of a number:
 
 [source,groovy]
@@ -397,6 +402,15 @@ include::{projectdir}/src/spec/test/SyntaxTest.groovy[tags=gstring_5,indent=0]
 
 NOTE: You can think of `"$number.toString()"` as being interpreted by the parser as `"${number.toString}()"`.
 
+Similarly, if the expression is ambiguous, you need to keep the curly braces:
+
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/SyntaxTest.groovy[tags=gstring_3b,indent=0]
+include::{projectdir}/src/spec/test/SyntaxTest.groovy[tags=gstring_3b2,indent=0]
+include::{projectdir}/src/spec/test/SyntaxTest.groovy[tags=gstring_3b3,indent=0]
+----
+
 If you need to escape the `$` or `${}` placeholders in a GString so they appear as is without
interpolation,
 you just need to use a `\` backslash character to escape the dollar sign:
 
@@ -516,14 +530,14 @@ Slashy strings are multiline:
 include::{projectdir}/src/spec/test/SyntaxTest.groovy[tags=slashy_3,indent=0]
 ----
 
-Slashy strings can also be interpolated (ie. a GString):
+Slashy strings can be thought of as just another way to define a GString but with different
escaping rules. They hence support interpolation:
 
 [source,groovy]
 ----
 include::{projectdir}/src/spec/test/SyntaxTest.groovy[tags=slashy_4,indent=0]
 ----
 
-There are a few gotchas to be aware of.
+==== Special cases
 
 An empty slashy string cannot be represented with a double forward slash, as it's understood
by the Groovy parser as a line comment. 
 That's why the following assert would actually not compile as it would look like a non-terminated
statement:
@@ -533,13 +547,23 @@ That's why the following assert would actually not compile as it would
look like
 include::{projectdir}/src/spec/test/SyntaxTest.groovy[tags=slashy_5,indent=0]
 ----
 
-NOTE: As slashy strings were mostly designed to make regexp easier so a few things that are
errors in GStrings like `$()` will work with slashy strings.
+As slashy strings were mostly designed to make regexp easier so a few things that
+are errors in GStrings like `$()` or `$5` will work with slashy strings.
+
+Remember that escaping backslashes is not required. An alternative way of thinking of this
is
+that in fact escaping is not supported. The slashy string `/\t/` won't contain a tab but
instead
+a backslash followed by the character 't'. Escaping is only allowed for the slash character,
i.e. `/\/folder/`
+will be a slashy string containing `'/folder'`. A consequence of slash escaping is that a
slashy string
+can't end with a backslash. Otherwise that will escape the slashy string terminator.
+You can instead use a special trick, `/ends with slash ${'\'}/`. But best just avoid using
a slashy string in such a case.
 
 === Dollar slashy string
 
 Dollar slashy strings are multiline GStrings delimited with an opening `$/` and and a closing
`/$`.
 The escaping character is the dollar sign, and it can escape another dollar, or a forward
slash.
-But both dollar and forward slashes don't need to be escaped, except to escape the dollar
of a string subsequence that would start like a GString placeholder sequence, or if you need
to escape a sequence that would start like a closing dollar slashy string delimiter.
+But both dollar and forward slashes don't need to be escaped, except to escape the dollar
of a string
+subsequence that would start like a GString placeholder sequence, or if you need to escape
a sequence
+that would start like a closing dollar slashy string delimiter.
 
 Here's an example:
 
@@ -548,6 +572,9 @@ Here's an example:
 include::{projectdir}/src/spec/test/SyntaxTest.groovy[tags=dollar_slashy_1,indent=0]
 ----
 
+It was created to overcome some of the limitations of the slashy string escaping rules.
+Use it when its escaping rules suit your string contents (typically if it has some slashes
you don't want to escape).
+
 === String summary table
 
 [cols="5*", ptions="header"]
diff --git a/src/spec/test/SyntaxTest.groovy b/src/spec/test/SyntaxTest.groovy
index 9053452..8f3d0b6 100644
--- a/src/spec/test/SyntaxTest.groovy
+++ b/src/spec/test/SyntaxTest.groovy
@@ -283,7 +283,7 @@ class SyntaxTest extends CompilableTestSupport {
         // end::string_0[]
 
         // tag::string_1[]
-        'a single quoted string'
+        'a single-quoted string'
         // end::string_1[]
 
         // tag::string_2[]
@@ -299,7 +299,7 @@ class SyntaxTest extends CompilableTestSupport {
         // end::string_4[]
 
         // tag::string_5[]
-        "a double quoted string"
+        "a double-quoted string"
         // end::string_5[]
     }
 
@@ -309,19 +309,6 @@ class SyntaxTest extends CompilableTestSupport {
         // end::string_plus[]
     }
 
-    void testCharacters() {
-        // tag::char[]
-        char c1 = 'A' // <1>
-        assert c1 instanceof Character
-
-        def c2 = 'B' as char // <2>
-        assert c2 instanceof Character
-
-        def c3 = (char)'C' // <3>
-        assert c3 instanceof Character
-        // end::char[]
-    }
-
     void testGString() {
         // tag::gstring_1[]
         def name = 'Guillaume' // a plain string
@@ -339,6 +326,19 @@ class SyntaxTest extends CompilableTestSupport {
         def person = [name: 'Guillaume', age: 36]
         assert "$person.name is $person.age years old" == 'Guillaume is 36 years old'
         // end::gstring_3[]
+        // tag::gstring_3b[]
+        String thing = 'treasure'
+        // end::gstring_3b[]
+        /*
+        // tag::gstring_3b2[]
+        assert 'The x-coordinate of the treasure is represented by treasure.x' ==
+            "The x-coordinate of the $thing is represented by $thing.x"   // <= Not allowed:
ambiguous!!
+        // end::gstring_3b2[]
+        */
+        // tag::gstring_3b3[]
+        assert 'The x-coordinate of the treasure is represented by treasure.x' ==
+                "The x-coordinate of the $thing is represented by ${thing}.x"  // <= Curly
braces required
+        // end::gstring_3b3[]
 
         // tag::gstring_4[]
         def number = 3.14
@@ -350,10 +350,24 @@ class SyntaxTest extends CompilableTestSupport {
         // end::gstring_5[]
 
         // tag::gstring_6[]
+        assert '$5' == "\$5"
         assert '${name}' == "\${name}"
         // end::gstring_6[]
     }
 
+    void testCharacters() {
+        // tag::char[]
+        char c1 = 'A' // <1>
+        assert c1 instanceof Character
+
+        def c2 = 'B' as char // <2>
+        assert c2 instanceof Character
+
+        def c3 = (char)'C' // <3>
+        assert c3 instanceof Character
+        // end::char[]
+    }
+
     void testInterpolatingClosuresInGstrings() {
         // tag::closure_in_gstring_1[]
         def sParameterLessClosure = "1 + 2 == ${-> 3}" // <1>
@@ -410,7 +424,7 @@ class SyntaxTest extends CompilableTestSupport {
 
     void testTripleSingleQuotedString() {
         // tag::triple_single_0[]
-        '''a triple single quoted string'''
+        '''a triple-single-quoted string'''
         // end::triple_single_0[]
 
         // tag::triple_single_1[]


Mime
View raw message