Repository: decorators-squad/eo-yaml (java)

Issue:
Building of Folded/Literal Scalars
We only have reading for these 2 types of Scalar, yet they should also be buildable. Currently, there is no way of specifying multi-line concerns when building YAML.

Pull request:
Building of Plain Scalars Implemented
Fixes #221 
 
* Added ``YamlScalarBuilder`` interface and method ``Yaml.createYamlScalarBuilder()``
* Added implementation ``RtYamlScalarBuilder``
* Implemented ``RtYamlScalarBuilder.buildPlainScalar()``
* Added unit tests
* Left puzzle to continue development of ``buildFolded/LiteralBlockScalar()`` in the next Issue
* Some javadoc fixes across the ``Rt*`` classes

Patch:
diff --git a/src/main/java/com/amihaiemil/eoyaml/ReadPlainScalarValue.java b/src/main/java/com/amihaiemil/eoyaml/ReadPlainScalarValue.java
index a76d6ac..fff7b4e 100644
--- a/src/main/java/com/amihaiemil/eoyaml/ReadPlainScalarValue.java
+++ b/src/main/java/com/amihaiemil/eoyaml/ReadPlainScalarValue.java
@@ -28,7 +28,7 @@
 package com.amihaiemil.eoyaml;
 
 /**
- * A plain scalar value read from a read mapping or a read sequence.
+ * A plain scalar value read from somewhere.
  * @author Mihai Andronace (amihaiemil@gmail.com)
  * @version $Id$
  * @since 3.1.3
@@ -39,7 +39,8 @@ final class ReadPlainScalarValue extends ComparableScalar {
      * Line where the plain scalar value is supposed to be found.
      * The Scalar can be either after the ":" character, if this
      * line is from a mapping, or after the "-" character, if
-     * this line is from a sequence.
+     * this line is from a sequence, or it represents the whole line,
+     * if no "-" or ":" are found.
      */
     private YamlLine line;
 
diff --git a/src/main/java/com/amihaiemil/eoyaml/RtYamlInput.java b/src/main/java/com/amihaiemil/eoyaml/RtYamlInput.java
index cee2538..0a13eaa 100644
--- a/src/main/java/com/amihaiemil/eoyaml/RtYamlInput.java
+++ b/src/main/java/com/amihaiemil/eoyaml/RtYamlInput.java
@@ -35,7 +35,7 @@ import java.util.ArrayList;
 import java.util.List;
 
 /**
- * Implementation for {@link YamlInput}.
+ * Implementation for {@link YamlInput}. "Rt" stands for "Runtime".
  * @author Mihai Andronache (amihaiemil@gmail.com)
  * @version $Id$
  * @since 1.0.0
diff --git a/src/main/java/com/amihaiemil/eoyaml/RtYamlLine.java b/src/main/java/com/amihaiemil/eoyaml/RtYamlLine.java
index 64540a7..252c946 100644
--- a/src/main/java/com/amihaiemil/eoyaml/RtYamlLine.java
+++ b/src/main/java/com/amihaiemil/eoyaml/RtYamlLine.java
@@ -29,6 +29,7 @@ package com.amihaiemil.eoyaml;
 
 /**
  * Default implementation of {@link YamlLine}.
+ * "Rt" stands for "Runtime".
  * @author Mihai Andronache (amihaiemil@gmail.com)
  * @version $Id$
  * @since 1.0.0
diff --git a/src/main/java/com/amihaiemil/eoyaml/RtYamlMappingBuilder.java b/src/main/java/com/amihaiemil/eoyaml/RtYamlMappingBuilder.java
index 3692b1a..19438dd 100644
--- a/src/main/java/com/amihaiemil/eoyaml/RtYamlMappingBuilder.java
+++ b/src/main/java/com/amihaiemil/eoyaml/RtYamlMappingBuilder.java
@@ -31,7 +31,7 @@ import java.util.HashMap;
 import java.util.Map;
 
 /**
- * YamlMappingBuilder implementation.
+ * YamlMappingBuilder implementation. "Rt" stands for "Runtime".
  * This class is immutable and thread-safe.
  * @author Mihai Andronache (amihaiemil@gmail.com)
  * @version $Id$
diff --git a/src/main/java/com/amihaiemil/eoyaml/RtYamlScalarBuilder.java b/src/main/java/com/amihaiemil/eoyaml/RtYamlScalarBuilder.java
new file mode 100644
index 0000000..5175126
--- /dev/null
+++ b/src/main/java/com/amihaiemil/eoyaml/RtYamlScalarBuilder.java
@@ -0,0 +1,93 @@
+/**
+ * Copyright (c) 2016-2020, Mihai Emil Andronache
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ *  modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright notice, this
+ *  list of conditions and the following disclaimer.
+ *  Redistributions in binary form must reproduce the above copyright notice,
+ *  this list of conditions and the following disclaimer in the documentation
+ *  and/or other materials provided with the distribution.
+ * Neither the name of the copyright holder nor the names of its
+ *  contributors may be used to endorse or promote products derived from
+ *  this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+package com.amihaiemil.eoyaml;
+
+import java.util.LinkedList;
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * Implementation for {@link YamlScalarBuilder}. "Rt" stands for "Runtime.
+ * This class is immutable and thread-safe.
+ * @author Mihai Andronache (amihaiemil@gmail.com)
+ * @version $Id$
+ * @since 4.0.0
+ * @todo #221:30min Finish the implementation of the methods in this interface.
+ *  Figure out how to implement literal and built block scalars, also in the
+ *  the context of indenting/printing a bigger YAML node, as well as printing
+ *  only that single scalar. Maybe we will need a class called YamlPrinter,
+ *  that looks for the type of the node to print.
+ */
+final class RtYamlScalarBuilder implements YamlScalarBuilder {
+
+    /**
+     * Added lines.
+     */
+    private final List<String> lines;
+
+    /**
+     * Default ctor.
+     */
+    RtYamlScalarBuilder() {
+        this(new LinkedList<>());
+    }
+
+    /**
+     * Constructor.
+     * @param lines String lines of the Scalar.
+     */
+    RtYamlScalarBuilder(final List<String> lines) {
+        this.lines = lines;
+    }
+
+    @Override
+    public YamlScalarBuilder addLine(final String value) {
+        final List<String> all = new LinkedList<>();
+        all.addAll(this.lines);
+        all.add(value);
+        return new RtYamlScalarBuilder(all);
+    }
+
+    @Override
+    public Scalar buildPlainScalar() {
+        final String plain = this.lines.stream().map(
+            line -> line.replaceAll(System.lineSeparator(), " ")
+        ).collect(Collectors.joining(" "));
+        return new PlainStringScalar(plain);
+    }
+
+    @Override
+    public Scalar buildFoldedBlockScalar() {
+        throw new UnsupportedOperationException("Not yet implemented.");
+    }
+
+    @Override
+    public Scalar buildLiteralBlockScalar() {
+        throw new UnsupportedOperationException("Not yet implemented.");
+    }
+}
diff --git a/src/main/java/com/amihaiemil/eoyaml/RtYamlSequenceBuilder.java b/src/main/java/com/amihaiemil/eoyaml/RtYamlSequenceBuilder.java
index 16cfcd7..a47f4cb 100644
--- a/src/main/java/com/amihaiemil/eoyaml/RtYamlSequenceBuilder.java
+++ b/src/main/java/com/amihaiemil/eoyaml/RtYamlSequenceBuilder.java
@@ -31,7 +31,7 @@ import java.util.LinkedList;
 import java.util.List;
 
 /**
- * YamlSequenceBuilder implementation.
+ * YamlSequenceBuilder implementation. "Rt" stands for "Runtime".
  * This class is immutable and thread-safe.
  * @author Salavat.Yalalov (s.yalalov@gmail.com)
  * @version $Id$
diff --git a/src/main/java/com/amihaiemil/eoyaml/RtYamlStreamBuilder.java b/src/main/java/com/amihaiemil/eoyaml/RtYamlStreamBuilder.java
index 43a7412..d7c5ce2 100644
--- a/src/main/java/com/amihaiemil/eoyaml/RtYamlStreamBuilder.java
+++ b/src/main/java/com/amihaiemil/eoyaml/RtYamlStreamBuilder.java
@@ -32,7 +32,7 @@ import java.util.LinkedList;
 import java.util.List;
 
 /**
- * YamlStreamBuilder implementation.
+ * YamlStreamBuilder implementation. "Rt" stands for "Runtime".
  * This class is immutable and thread-safe.
  * @author Mihai Andronache (amihaiemil@gmail.com)
  * @version $Id$
diff --git a/src/main/java/com/amihaiemil/eoyaml/Yaml.java b/src/main/java/com/amihaiemil/eoyaml/Yaml.java
index 7038342..6a4335f 100644
--- a/src/main/java/com/amihaiemil/eoyaml/Yaml.java
+++ b/src/main/java/com/amihaiemil/eoyaml/Yaml.java
@@ -62,7 +62,15 @@ public final class Yaml {
     public static YamlSequenceBuilder createYamlSequenceBuilder() {
         return new RtYamlSequenceBuilder();
     }
-    
+
+    /**
+     * Create a {@link YamlScalarBuilder}.
+     * @return Builder of Yaml Scalars.
+     */
+    public static YamlScalarBuilder createYamlScalarBuilder() {
+        return new RtYamlScalarBuilder();
+    }
+
     /**
      * Create a {@link YamlStreamBuilder}.
      * @return Builder of YamlStream.
diff --git a/src/main/java/com/amihaiemil/eoyaml/YamlScalarBuilder.java b/src/main/java/com/amihaiemil/eoyaml/YamlScalarBuilder.java
new file mode 100644
index 0000000..58499e7
--- /dev/null
+++ b/src/main/java/com/amihaiemil/eoyaml/YamlScalarBuilder.java
@@ -0,0 +1,82 @@
+/**
+ * Copyright (c) 2016-2020, Mihai Emil Andronache
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ *  modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright notice, this
+ *  list of conditions and the following disclaimer.
+ *  Redistributions in binary form must reproduce the above copyright notice,
+ *  this list of conditions and the following disclaimer in the documentation
+ *  and/or other materials provided with the distribution.
+ * Neither the name of the copyright holder nor the names of its
+ *  contributors may be used to endorse or promote products derived from
+ *  this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+package com.amihaiemil.eoyaml;
+
+/**
+ * Builder of Yaml Scalar. Implementations should be immutable and thread-safe.
+ * @author Mihai Andronache (amihaiemil@gmail.com)
+ * @version $Id$
+ * @since 4.0.0
+ */
+public interface YamlScalarBuilder {
+
+    /**
+     * Add a line of text this Scalar. You can use this multiple
+     * times or just once, if your String already contains NEW_LINE
+     * chars.
+     * @param value String
+     * @return An instance of this builder.
+     */
+    YamlScalarBuilder addLine(final String value);
+
+    /**
+     * Build a plain Scalar. Ideally, you should use this when
+     * your scalar is short, a single line of text.<br><br>
+     * If you added more lines of text, all of them will be put together,
+     * separated by spaces.
+     * @return The built Scalar.
+     */
+    Scalar buildPlainScalar();
+
+    /**
+     * Build a Folded Block Scalar. Use this when your scalar has multiple
+     * lines of text, but you don't care about the newlines, you want them
+     * all separated by spaces. <br><br>
+     *
+     * The difference from buildPlainScalar() comes when you are printing
+     * the created YAML:
+     * <pre>
+     *     plain: a very long scalar which should have been built as Folded
+     *     folded:>
+     *       a very long scalar which
+     *       has been folded for readability
+     * </pre>
+     *
+     * @return The built Scalar.
+     */
+    Scalar buildFoldedBlockScalar();
+
+    /**
+     * Build a Literal Block Scalar. Use this when your scalar has multiple
+     * lines and you want these lines to be separated.
+     *
+     * @return The built Scalar.
+     */
+    Scalar buildLiteralBlockScalar();
+
+}


Test patch:
diff --git a/src/test/java/com/amihaiemil/eoyaml/RtYamlScalarBuilderTest.java b/src/test/java/com/amihaiemil/eoyaml/RtYamlScalarBuilderTest.java
new file mode 100644
index 0000000..1c05fde
--- /dev/null
+++ b/src/test/java/com/amihaiemil/eoyaml/RtYamlScalarBuilderTest.java
@@ -0,0 +1,112 @@
+/**
+ * Copyright (c) 2016-2020, Mihai Emil Andronache
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ *  modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright notice, this
+ *  list of conditions and the following disclaimer.
+ *  Redistributions in binary form must reproduce the above copyright notice,
+ *  this list of conditions and the following disclaimer in the documentation
+ *  and/or other materials provided with the distribution.
+ * Neither the name of the copyright holder nor the names of its
+ *  contributors may be used to endorse or promote products derived from
+ *  this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+package com.amihaiemil.eoyaml;
+
+import org.hamcrest.MatcherAssert;
+import org.hamcrest.Matchers;
+import org.junit.Test;
+
+/**
+ * Unit tests for {@link RtYamlScalarBuilder}.
+ * @author Mihai Andronache (amihaiemil@gmail.com)
+ * @version $Id$
+ * @since 4.0.0
+ */
+public final class RtYamlScalarBuilderTest {
+
+    /**
+     * RtYamlScalarBuilder can add line of text.
+     */
+    @Test
+    public void addsLineOfText() {
+        final YamlScalarBuilder scalarBuilder = new RtYamlScalarBuilder();
+        final YamlScalarBuilder withAdded = scalarBuilder.addLine("a scalar");
+        MatcherAssert.assertThat(withAdded, Matchers.notNullValue());
+        MatcherAssert.assertThat(
+            scalarBuilder, Matchers.not(Matchers.is(withAdded))
+        );
+    }
+
+    /**
+     * RtYamlScalarBuilder can build a plain scalar with no newlines.
+     * @checkstyle LineLength (30 lines)
+     */
+    @Test
+    public void buildsPlainScalarNoNewLines() {
+        final Scalar scalar = new RtYamlScalarBuilder()
+            .addLine("a plain scalar")
+            .addLine("that will be on the same line")
+            .buildPlainScalar();
+        MatcherAssert.assertThat(
+            scalar.value(), Matchers.equalTo("a plain scalar that will be on the same line")
+        );
+    }
+
+    /**
+     * RtYamlScalarBuilder can build a plain scalar, while removing
+     * the hardcoded newlines.
+     * @checkstyle LineLength (30 lines)
+     */
+    @Test
+    public void buildsPlainScalarRemovesAddedNewLines() {
+        final Scalar scalar = new RtYamlScalarBuilder()
+            .addLine("a plain scalar")
+            .addLine("that will be" + System.lineSeparator() + "on the same line.")
+            .addLine("You cannot trick it.")
+            .buildPlainScalar();
+        MatcherAssert.assertThat(
+            scalar.value(),
+            Matchers.equalTo("a plain scalar that will be on the same line. You cannot trick it.")
+        );
+    }
+
+    /**
+     * RtYamlScalarBuilder can build on a single line of text.
+     */
+    @Test
+    public void buildsSingleLinePlainScalar() {
+        final Scalar scalar = new RtYamlScalarBuilder()
+            .addLine("value").buildPlainScalar();
+        MatcherAssert.assertThat(
+            scalar.value(),
+            Matchers.equalTo("value")
+        );
+    }
+
+    /**
+     * RtYamlScalarBuilder can build an empty plain scalar.
+     */
+    @Test
+    public void buildsEmptyPlainScalar() {
+        final Scalar scalar = new RtYamlScalarBuilder().buildPlainScalar();
+        MatcherAssert.assertThat(
+            scalar.value(),
+            Matchers.isEmptyString()
+        );
+    }
+}
diff --git a/src/test/java/com/amihaiemil/eoyaml/YamlTest.java b/src/test/java/com/amihaiemil/eoyaml/YamlTest.java
index 128c8a3..3870d53 100644
--- a/src/test/java/com/amihaiemil/eoyaml/YamlTest.java
+++ b/src/test/java/com/amihaiemil/eoyaml/YamlTest.java
@@ -62,6 +62,16 @@ public final class YamlTest {
         );
     }
 
+    /**
+     * Yaml can create a YamlScalarBuilder.
+     */
+    @Test
+    public void createsYamlScalarBuilder() {
+        MatcherAssert.assertThat(
+            Yaml.createYamlScalarBuilder(), Matchers.notNullValue()
+        );
+    }
+
     /**
      * Yaml can create a YamlStreamBuilder.
      */