You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@groovy.apache.org by su...@apache.org on 2021/05/03 08:10:09 UTC

[groovy] 01/01: GROOVY-9804: Support TOML

This is an automated email from the ASF dual-hosted git repository.

sunlan pushed a commit to branch GROOVY-9804
in repository https://gitbox.apache.org/repos/asf/groovy.git

commit f43e35313cb377ebe0de4d77761f28348026241f
Author: Daniel Sun <su...@apache.org>
AuthorDate: Mon May 3 16:08:49 2021 +0800

    GROOVY-9804: Support TOML
---
 settings.gradle                                    |   1 +
 subprojects/groovy-binary/src/spec/doc/index.adoc  |   2 +
 subprojects/groovy-toml/build.gradle               |  40 ++++++
 .../src/main/java/groovy/toml/TomlBuilder.java     | 145 +++++++++++++++++++++
 .../java/groovy/toml/TomlRuntimeException.java     |  40 ++++++
 .../src/main/java/groovy/toml/TomlSlurper.java     |  94 +++++++++++++
 .../org/apache/groovy/toml/util/TomlConverter.java |  74 +++++++++++
 .../groovy-toml/src/spec/doc/toml-userguide.adoc   | 101 ++++++++++++++
 .../spec/test/groovy/toml/TomlBuilderTest.groovy   |  55 ++++++++
 .../spec/test/groovy/toml/TomlParserTest.groovy    | 110 ++++++++++++++++
 .../groovy/toml/TomlJavadocAssertionTest.groovy    |  28 ++++
 11 files changed, 690 insertions(+)

diff --git a/settings.gradle b/settings.gradle
index 0c7e7f4..d83b6fb 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -58,6 +58,7 @@ def subprojects = [
         'groovy-test',
         'groovy-test-junit5',
         'groovy-testng',
+        'groovy-toml',
         'groovy-typecheckers',
         'groovy-xml',
         'groovy-yaml',
diff --git a/subprojects/groovy-binary/src/spec/doc/index.adoc b/subprojects/groovy-binary/src/spec/doc/index.adoc
index 00b756e..52f199f 100644
--- a/subprojects/groovy-binary/src/spec/doc/index.adoc
+++ b/subprojects/groovy-binary/src/spec/doc/index.adoc
@@ -106,6 +106,8 @@ include::../../../../../subprojects/groovy-xml/src/spec/doc/xml-userguide.adoc[l
 
 include::../../../../../subprojects/groovy-yaml/src/spec/doc/yaml-userguide.adoc[leveloffset=+2]
 
+include::../../../../../subprojects/groovy-toml/src/spec/doc/toml-userguide.adoc[leveloffset=+2]
+
 include::../../../../../subprojects/groovy-contracts/src/spec/doc/contracts-userguide.adoc[leveloffset=+2]
 
 === Scripting Ant tasks
diff --git a/subprojects/groovy-toml/build.gradle b/subprojects/groovy-toml/build.gradle
new file mode 100644
index 0000000..8b5b626
--- /dev/null
+++ b/subprojects/groovy-toml/build.gradle
@@ -0,0 +1,40 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+plugins {
+    id 'org.apache.groovy-library'
+}
+
+dependencies {
+    api rootProject  // TomlBuilder extends GroovyObjectSupport...
+    implementation "com.fasterxml.jackson.dataformat:jackson-dataformat-toml:${versions.jackson}"
+    implementation project(':groovy-json')
+    testImplementation project(':groovy-test')
+    testRuntimeOnly project(':groovy-ant') // for JavadocAssertionTests
+}
+
+plugins.withId('eclipse') {
+    eclipse.classpath.file.whenMerged {
+        entries.removeAll { entry -> entry.path in ['/groovy-ant', '/groovy-groovydoc'] }
+    }
+}
+
+groovyLibrary {
+    optionalModule()
+    withoutBinaryCompatibilityChecks()
+}
diff --git a/subprojects/groovy-toml/src/main/java/groovy/toml/TomlBuilder.java b/subprojects/groovy-toml/src/main/java/groovy/toml/TomlBuilder.java
new file mode 100644
index 0000000..f286523
--- /dev/null
+++ b/subprojects/groovy-toml/src/main/java/groovy/toml/TomlBuilder.java
@@ -0,0 +1,145 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package groovy.toml;
+
+import groovy.json.JsonBuilder;
+import groovy.lang.Closure;
+import groovy.lang.GroovyObjectSupport;
+import groovy.lang.Writable;
+import org.apache.groovy.toml.util.TomlConverter;
+
+import java.io.IOException;
+import java.io.StringReader;
+import java.io.Writer;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+
+/**
+ *  A builder for creating TOML payloads.
+ *
+ *  @since 3.0.0
+ */
+public class TomlBuilder extends GroovyObjectSupport implements Writable {
+    private JsonBuilder jsonBuilder;
+
+    public TomlBuilder() {
+        this.jsonBuilder = new JsonBuilder();
+    }
+
+    public Object getContent() {
+        return jsonBuilder.getContent();
+    }
+
+    /**
+     * Named arguments can be passed to the TOML builder instance to create a root TOML object
+     *
+     * @param m a map of key / value pairs
+     * @return a map of key / value pairs
+     */
+    public Object call(Map m) {
+        return jsonBuilder.call(m);
+    }
+
+    /**
+     * A list of elements as arguments to the TOML builder creates a root TOML array
+     *
+     * @param l a list of values
+     * @return a list of values
+     */
+    public Object call(List l) {
+        return jsonBuilder.call(l);
+    }
+
+    /**
+     * Varargs elements as arguments to the TOML builder create a root TOML array
+     *
+     * @param args an array of values
+     * @return a list of values
+     */
+    public Object call(Object... args) {
+        return jsonBuilder.call(args);
+    }
+
+    /**
+     * A collection and closure passed to a TOML builder will create a root TOML array applying
+     * the closure to each object in the collection
+
+     * @param coll a collection
+     * @param c a closure used to convert the objects of coll
+     * @return a list of values
+     */
+    public Object call(Iterable coll, Closure c) {
+        return jsonBuilder.call(coll, c);
+    }
+
+    /**
+     * Delegates to {@link #call(Iterable, Closure)}
+     * @param coll
+     * @param c
+     */
+    public Object call(Collection coll, Closure c) {
+        return jsonBuilder.call(coll, c);
+    }
+
+    /**
+     * A closure passed to a TOML builder will create a root TOML object
+     *
+     * @param c a closure whose method call statements represent key / values of a TOML object
+     * @return a map of key / value pairs
+     */
+    public Object call(Closure c) {
+        return jsonBuilder.call(c);
+    }
+
+    /**
+     * A method call on the TOML builder instance will create a root object with only one key
+     * whose name is the name of the method being called.
+     *
+     * @param name the single key
+     * @param args the value associated with the key
+     * @return a map with a single key
+     */
+    @Override
+    public Object invokeMethod(String name, Object args) {
+        return jsonBuilder.invokeMethod(name, args);
+    }
+
+    /**
+     * Serializes the internal data structure built with the builder to a conformant TOML payload string
+     *
+     * @return a TOML output
+     */
+    @Override
+    public String toString() {
+        return TomlConverter.convertJsonToToml(new StringReader(jsonBuilder.toString()));
+    }
+
+    /**
+     * The TOML builder implements the <code>Writable</code> interface,
+     * so that you can have the builder serialize itself the TOML payload to a writer.
+     *
+     * @param out a writer on which to serialize the TOML payload
+     * @return the writer
+     */
+    @Override
+    public Writer writeTo(Writer out) throws IOException {
+        return out.append(toString());
+    }
+}
diff --git a/subprojects/groovy-toml/src/main/java/groovy/toml/TomlRuntimeException.java b/subprojects/groovy-toml/src/main/java/groovy/toml/TomlRuntimeException.java
new file mode 100644
index 0000000..12c3f3f
--- /dev/null
+++ b/subprojects/groovy-toml/src/main/java/groovy/toml/TomlRuntimeException.java
@@ -0,0 +1,40 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package groovy.toml;
+
+import groovy.lang.GroovyRuntimeException;
+
+/**
+ * Represents runtime exception occurred when parsing or building TOML
+ *
+ * @since 3.0.0
+ */
+public class TomlRuntimeException extends GroovyRuntimeException {
+    public TomlRuntimeException(String msg) {
+        super(msg);
+    }
+
+    public TomlRuntimeException(Throwable cause) {
+        super(cause);
+    }
+
+    public TomlRuntimeException(String msg, Throwable cause) {
+        super(msg, cause);
+    }
+}
diff --git a/subprojects/groovy-toml/src/main/java/groovy/toml/TomlSlurper.java b/subprojects/groovy-toml/src/main/java/groovy/toml/TomlSlurper.java
new file mode 100644
index 0000000..513d2e4
--- /dev/null
+++ b/subprojects/groovy-toml/src/main/java/groovy/toml/TomlSlurper.java
@@ -0,0 +1,94 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package groovy.toml;
+
+import groovy.json.JsonSlurper;
+import org.apache.groovy.toml.util.TomlConverter;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.io.StringReader;
+import java.nio.file.Files;
+import java.nio.file.Path;
+
+/**
+ *  Represents a TOML parser
+ *
+ *  @since 3.0.0
+ */
+public class TomlSlurper {
+    private JsonSlurper jsonSlurper;
+
+    public TomlSlurper() {
+        this.jsonSlurper = new JsonSlurper();
+    }
+
+    /**
+     * Parse the content of the specified toml into a tree of Nodes.
+     *
+     * @param toml the content of toml
+     * @return the root node of the parsed tree of Nodes
+     */
+    public Object parseText(String toml) {
+        return this.parse(new StringReader(toml));
+    }
+
+    /**
+     * Parse the content of the specified reader into a tree of Nodes.
+     *
+     * @param reader the reader of toml
+     * @return the root node of the parsed tree of Nodes
+     */
+    public Object parse(Reader reader) {
+        return jsonSlurper.parse(new StringReader(TomlConverter.convertTomlToJson(reader)));
+    }
+
+    /**
+     * Parse the content of the specified reader into a tree of Nodes.
+     *
+     * @param stream the reader of toml
+     * @return the root node of the parsed tree of Nodes
+     */
+    public Object parse(InputStream stream) {
+        return parse(new InputStreamReader(stream));
+    }
+
+    /**
+     * Parse the content of the specified file into a tree of Nodes.
+     *
+     * @param file the reader of toml
+     * @return the root node of the parsed tree of Nodes
+     */
+    public Object parse(java.io.File file) throws IOException {
+        return parse(file.toPath());
+    }
+
+    /**
+     * Parse the content of the specified path into a tree of Nodes.
+     *
+     * @param path the reader of toml
+     * @return the root node of the parsed tree of Nodes
+     */
+    public Object parse(Path path) throws IOException {
+        // note: convert to an input stream to allow the support of foreign file objects
+        return parse(Files.newInputStream(path));
+    }
+}
diff --git a/subprojects/groovy-toml/src/main/java/org/apache/groovy/toml/util/TomlConverter.java b/subprojects/groovy-toml/src/main/java/org/apache/groovy/toml/util/TomlConverter.java
new file mode 100644
index 0000000..62f902a
--- /dev/null
+++ b/subprojects/groovy-toml/src/main/java/org/apache/groovy/toml/util/TomlConverter.java
@@ -0,0 +1,74 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.apache.groovy.toml.util;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.dataformat.toml.TomlFactory;
+import com.fasterxml.jackson.dataformat.toml.TomlMapper;
+import groovy.toml.TomlRuntimeException;
+
+import java.io.IOException;
+import java.io.Reader;
+import java.io.StringReader;
+
+/**
+ *  A converter for converting TOML to JSON, vice versa
+ *  @since 3.0.0
+ */
+public class TomlConverter {
+    /**
+     * Convert toml to json
+     * @param tomlReader the reader of toml
+     * @return the text of json
+     */
+    public static String convertTomlToJson(Reader tomlReader) {
+        try (Reader reader = tomlReader) {
+            Object yaml = new ObjectMapper(new TomlFactory()).readValue(reader, Object.class);
+
+            return new ObjectMapper().writeValueAsString(yaml);
+        } catch (IOException e) {
+            throw new TomlRuntimeException(e);
+        }
+    }
+
+    /**
+     * Convert json to toml
+     * @param jsonReader the reader of json
+     * @return the text of toml
+     */
+    public static String convertJsonToToml(Reader jsonReader) {
+        try (Reader reader = jsonReader) {
+            JsonNode json = new ObjectMapper().readTree(reader);
+
+            return new TomlMapper().writeValueAsString(json);
+        } catch (IOException e) {
+            throw new TomlRuntimeException(e);
+        }
+    }
+
+    private TomlConverter() {}
+
+    public static void main(String[] args) {
+        String json = TomlConverter.convertTomlToJson(new StringReader("number = 42"));
+        System.out.println(json);
+        String toml = TomlConverter.convertJsonToToml(new StringReader(json));
+        System.out.println(toml);
+    }
+}
diff --git a/subprojects/groovy-toml/src/spec/doc/toml-userguide.adoc b/subprojects/groovy-toml/src/spec/doc/toml-userguide.adoc
new file mode 100644
index 0000000..d59ab19
--- /dev/null
+++ b/subprojects/groovy-toml/src/spec/doc/toml-userguide.adoc
@@ -0,0 +1,101 @@
+//////////////////////////////////////////
+
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+
+//////////////////////////////////////////
+ifndef::core-semantics[]
+:core-semantics: core-semantics.adoc
+endif::[]
+
+= Processing TOML
+
+Groovy has an optional `groovy-toml` module which provides support for converting between Groovy objects and TOML. The classes dedicated to
+TOML serialisation and parsing are found in the `groovy.toml` package.
+
+[[toml_tomlslurper]]
+== TomlSlurper
+
+`TomlSlurper` is a class that parses TOML text or reader content into Groovy data structures (objects) such as maps, lists and
+primitive types like `Integer`, `Double`, `Boolean` and `String`.
+
+The class comes with a bunch of overloaded `parse` methods plus some special methods such as `parseText`
+and others. For the next example we will use the `parseText` method. It parses a TOML `String` and recursively converts it to a
+list or map of objects. The other `parse*` methods are similar in that they return a TOML `String` but for different parameter
+types.
+
+[source,groovy]
+----
+include::../test/groovy/toml/TomlParserTest.groovy[tags=parse_text,indent=0]
+----
+
+Notice the result is a plain map and can be handled like a normal Groovy object instance. `TomlSlurper` parses the
+given TOML as defined by the https://toml.io/en/v1.0.0-rc.3[Tom's Obvious, Minimal Language].
+
+
+As `TomlSlurper` is returning pure Groovy object instances without any special TOML classes in the back, its usage
+is transparent. In fact, `TomlSlurper` results conform to GPath expressions. GPath is a powerful expression language
+that is supported by multiple slurpers for different data formats (`XmlSlurper` for XML being one example).
+
+[NOTE]
+For more details please have a look at the section on <<{core-semantics}#gpath_expressions,GPath expressions>>.
+
+The following table gives an overview of the TOML types and the corresponding Groovy data types:
+
+[cols="1,3" options="header"]
+|===
+|TOML
+|Groovy
+
+|string
+|`java.lang.String`
+
+|number
+|`java.lang.BigDecimal` or `java.lang.Integer`
+
+|object
+|`java.util.LinkedHashMap`
+
+|array
+|`java.util.ArrayList`
+
+|true
+|`true`
+
+|false
+|`false`
+
+|null
+|`null`
+
+|date
+|`java.util.Date` based on the `yyyy-MM-dd'T'HH:mm:ssZ` date format
+|===
+
+[NOTE]
+Whenever a value in TOML is `null`, `TomlSlurper` supplements it with the Groovy `null` value. This is in contrast to other
+TOML parsers that represent a `null` value with a library-provided singleton object.
+
+=== Builders
+
+Another way to create TOML from Groovy is to use `TomlBuilder`. The builder provide a
+DSL which allows to formulate an object graph which is then converted to TOML.
+
+[source,groovy]
+----
+include::../test/groovy/toml/TomlBuilderTest.groovy[tags=build_text,indent=0]
+----
diff --git a/subprojects/groovy-toml/src/spec/test/groovy/toml/TomlBuilderTest.groovy b/subprojects/groovy-toml/src/spec/test/groovy/toml/TomlBuilderTest.groovy
new file mode 100644
index 0000000..36e5b4a
--- /dev/null
+++ b/subprojects/groovy-toml/src/spec/test/groovy/toml/TomlBuilderTest.groovy
@@ -0,0 +1,55 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package groovy.toml
+
+import groovy.test.GroovyTestCase
+
+class TomlBuilderTest extends GroovyTestCase {
+
+    void testBuild() {
+        // tag::build_text[]
+        def builder = new TomlBuilder()
+        builder.records {
+            car {
+                name 'HSV Maloo'
+                make 'Holden'
+                year 2006
+                country 'Australia'
+                homepage new URL('http://example.org')
+                record {
+                    type 'speed'
+                    description 'production pickup truck with speed of 271kph'
+                }
+            }
+        }
+
+        println builder.toString()
+
+        assert builder.toString() == '''\
+records.car.name = 'HSV Maloo'
+records.car.make = 'Holden'
+records.car.year = 2006
+records.car.country = 'Australia'
+records.car.homepage = 'http://example.org'
+records.car.record.type = 'speed'
+records.car.record.description = 'production pickup truck with speed of 271kph'
+'''
+        // end::build_text[]
+    }
+}
\ No newline at end of file
diff --git a/subprojects/groovy-toml/src/spec/test/groovy/toml/TomlParserTest.groovy b/subprojects/groovy-toml/src/spec/test/groovy/toml/TomlParserTest.groovy
new file mode 100644
index 0000000..dacef27
--- /dev/null
+++ b/subprojects/groovy-toml/src/spec/test/groovy/toml/TomlParserTest.groovy
@@ -0,0 +1,110 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package groovy.toml
+
+
+import groovy.test.GroovyTestCase
+
+class TomlParserTest extends GroovyTestCase {
+
+    void testParse() {
+        // tag::parse_text[]
+        def ts = new TomlSlurper()
+        def toml = ts.parseText '''
+language = "groovy"
+sudo = "required"
+dist = "trusty"
+before_script = [ "unset _JAVA_OPTIONS\\n\\n    \\n" ]
+
+[[matrix.include]]
+jdk = "openjdk10"
+
+[[matrix.include]]
+jdk = "oraclejdk9"
+
+[[matrix.include]]
+jdk = "oraclejdk8"
+'''
+
+        assert 'groovy' == toml.language
+        assert 'required' == toml.sudo
+        assert 'trusty' == toml.dist
+        assert ['openjdk10', 'oraclejdk9', 'oraclejdk8'] ==  toml.matrix.include.jdk
+        assert ['unset _JAVA_OPTIONS'] == toml.before_script*.trim()
+        // end::parse_text[]
+    }
+
+    void testBuildAndParse() {
+        def builder = new TomlBuilder()
+        builder.records {
+            car {
+                name 'HSV Maloo'
+                make 'Holden'
+                year 2006
+                country 'Australia'
+                homepage new URL('http://example.org')
+                record {
+                    type 'speed'
+                    description 'production pickup truck with speed of 271kph'
+                }
+            }
+        }
+
+        def ts = new TomlSlurper()
+        def toml = ts.parseText(builder.toString())
+
+        assert 'HSV Maloo' == toml.records.car.name
+        assert 'Holden' == toml.records.car.make
+        assert 2006 == toml.records.car.year
+        assert 'Australia' == toml.records.car.country
+        assert 'http://example.org' == toml.records.car.homepage
+        assert 'speed' == toml.records.car.record.type
+        assert 'production pickup truck with speed of 271kph' == toml.records.car.record.description
+    }
+
+
+    void testParsePath() {
+        def file = File.createTempFile('test','yml')
+        file.deleteOnExit()
+        file.text = '''
+language = "groovy"
+sudo = "required"
+dist = "trusty"
+
+[[matrix.include]]
+jdk = "openjdk10"
+
+[[matrix.include]]
+jdk = "oraclejdk9"
+
+[[matrix.include]]
+jdk = "oraclejdk8"
+'''
+
+        def ts = new TomlSlurper()
+        def toml = ts.parse(file.toPath())
+
+        // check
+        assert 'groovy' == toml.language
+        assert 'required' == toml.sudo
+        assert 'trusty' == toml.dist
+        assert ['openjdk10', 'oraclejdk9', 'oraclejdk8'] ==  toml.matrix.include.jdk
+
+    }
+}
diff --git a/subprojects/groovy-toml/src/test/groovy/groovy/toml/TomlJavadocAssertionTest.groovy b/subprojects/groovy-toml/src/test/groovy/groovy/toml/TomlJavadocAssertionTest.groovy
new file mode 100644
index 0000000..43c6e4f
--- /dev/null
+++ b/subprojects/groovy-toml/src/test/groovy/groovy/toml/TomlJavadocAssertionTest.groovy
@@ -0,0 +1,28 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package groovy.toml
+
+import groovy.test.JavadocAssertionTestSuite
+import org.junit.runner.RunWith
+import org.junit.runners.Suite
+
+@RunWith(Suite)
+@Suite.SuiteClasses(JavadocAssertionTestSuite)
+class TomlJavadocAssertionTest {
+}