Issue 66: prepare flexible scalar style
diff --git a/src/main/java/org/yaml/snakeyaml/DumperOptions.java b/src/main/java/org/yaml/snakeyaml/DumperOptions.java
index 535e0f9..80ec8b1 100644
--- a/src/main/java/org/yaml/snakeyaml/DumperOptions.java
+++ b/src/main/java/org/yaml/snakeyaml/DumperOptions.java
@@ -31,6 +31,7 @@
* double-quoted style. These styles offer a range of trade-offs between
* expressive power and readability.
*
+ * @see http://yaml.org/spec/1.1/#id903915
* @see http://yaml.org/spec/1.1/#id858081
*/
public enum ScalarStyle {
diff --git a/src/main/java/org/yaml/snakeyaml/emitter/Emitter.java b/src/main/java/org/yaml/snakeyaml/emitter/Emitter.java
index 21fe6cb..c9c5876 100644
--- a/src/main/java/org/yaml/snakeyaml/emitter/Emitter.java
+++ b/src/main/java/org/yaml/snakeyaml/emitter/Emitter.java
@@ -1044,9 +1044,9 @@
allowFlowPlain = allowBlockPlain = allowSingleQuoted = allowBlock = false;
}
// Although the plain scalar writer supports breaks, we never emit
- // multiline plain scalars.
+ // multiline plain scalars in the flow context.
if (lineBreaks) {
- allowFlowPlain = allowBlockPlain = false;
+ allowFlowPlain = false;
}
// Flow indicators are forbidden for flow plain scalars.
if (flowIndicators) {
diff --git a/src/main/java/org/yaml/snakeyaml/events/ScalarEvent.java b/src/main/java/org/yaml/snakeyaml/events/ScalarEvent.java
index f967b35..1cbf00d 100644
--- a/src/main/java/org/yaml/snakeyaml/events/ScalarEvent.java
+++ b/src/main/java/org/yaml/snakeyaml/events/ScalarEvent.java
@@ -54,7 +54,7 @@
/**
* Style of the scalar.
* <dl>
- * <dt>''</dt>
+ * <dt>null</dt>
* <dd>Flow Style - Plain</dd>
* <dt>'\''</dt>
* <dd>Flow Style - Single-Quoted</dd>
diff --git a/src/main/java/org/yaml/snakeyaml/nodes/ScalarNode.java b/src/main/java/org/yaml/snakeyaml/nodes/ScalarNode.java
index fd4d9b6..5108f45 100644
--- a/src/main/java/org/yaml/snakeyaml/nodes/ScalarNode.java
+++ b/src/main/java/org/yaml/snakeyaml/nodes/ScalarNode.java
@@ -47,7 +47,7 @@
* Get scalar style of this node.
*
* @see org.yaml.snakeyaml.events.ScalarEvent
- * @see http://yaml.org/spec/1.1/#id864487
+ * @see http://yaml.org/spec/1.1/#id903915
* @return
*/
public Character getStyle() {
diff --git a/src/main/java/org/yaml/snakeyaml/representer/BaseRepresenter.java b/src/main/java/org/yaml/snakeyaml/representer/BaseRepresenter.java
index 3f2aa91..d4d7602 100644
--- a/src/main/java/org/yaml/snakeyaml/representer/BaseRepresenter.java
+++ b/src/main/java/org/yaml/snakeyaml/representer/BaseRepresenter.java
@@ -48,7 +48,7 @@
protected Represent nullRepresenter;
// the order is important (map can be also a sequence of key-values)
protected final Map<Class<?>, Represent> multiRepresenters = new LinkedHashMap<Class<?>, Represent>();
- private Character defaultStyle;
+ protected Character defaultScalarStyle;
protected FlowStyle defaultFlowStyle = FlowStyle.AUTO;
protected final Map<Object, Node> representedObjects = new IdentityHashMap<Object, Node>() {
private static final long serialVersionUID = -5576159264232131854L;
@@ -115,7 +115,7 @@
protected Node representScalar(Tag tag, String value, Character style) {
if (style == null) {
- style = this.defaultStyle;
+ style = this.defaultScalarStyle;
}
Node node = new ScalarNode(tag, value, null, null, style);
// representedObjects.put(objectToRepresent, node);
@@ -181,7 +181,7 @@
}
public void setDefaultScalarStyle(ScalarStyle defaultStyle) {
- this.defaultStyle = defaultStyle.getChar();
+ this.defaultScalarStyle = defaultStyle.getChar();
}
public void setDefaultFlowStyle(FlowStyle defaultFlowStyle) {
diff --git a/src/main/java/org/yaml/snakeyaml/representer/SafeRepresenter.java b/src/main/java/org/yaml/snakeyaml/representer/SafeRepresenter.java
index b52d22e..0f2491f 100644
--- a/src/main/java/org/yaml/snakeyaml/representer/SafeRepresenter.java
+++ b/src/main/java/org/yaml/snakeyaml/representer/SafeRepresenter.java
@@ -105,6 +105,7 @@
}
public static Pattern BINARY_PATTERN = Pattern.compile("[\\x00-\\x08\\x0B\\x0C\\x0E-\\x1F]");
+ public static Pattern MULTILINE_PATTERN = Pattern.compile("\n|\u0085|\u2028|\u2029");
protected class RepresentString implements Represent {
public Node representData(Object data) {
@@ -118,6 +119,11 @@
value = String.valueOf(binary);
style = '|';
}
+ // if no other scalar style is explicitly set, use literal style for
+ // multiline scalars
+ if (defaultScalarStyle == null && MULTILINE_PATTERN.matcher(value).find()) {
+ style = '|';
+ }
return representScalar(tag, value, style);
}
}
diff --git a/src/test/java/org/yaml/snakeyaml/Chapter2_3Test.java b/src/test/java/org/yaml/snakeyaml/Chapter2_3Test.java
index 25b7ea1..5d19e08 100644
--- a/src/test/java/org/yaml/snakeyaml/Chapter2_3Test.java
+++ b/src/test/java/org/yaml/snakeyaml/Chapter2_3Test.java
@@ -21,6 +21,8 @@
import junit.framework.TestCase;
+import org.yaml.snakeyaml.DumperOptions.ScalarStyle;
+
/**
* Test Chapter 2.3 from the YAML specification
*
@@ -45,13 +47,15 @@
String etalon = "Sammy Sosa completed another fine season with great stats.\n\n 63 Home Runs\n 0.288 Batting Average\n\nWhat a year!\n";
InputStream input = YamlDocument.class.getClassLoader().getResourceAsStream(
YamlDocument.ROOT + "example2_15.yaml");
- Yaml yaml = new Yaml();
+ DumperOptions options = new DumperOptions();
+ options.setDefaultScalarStyle(ScalarStyle.FOLDED);
+ Yaml yaml = new Yaml(options);
String data = (String) yaml.load(input);
assertEquals(etalon, data);
//
String dumped = yaml.dump(data);
- assertTrue(dumped.contains("Sammy Sosa completed another fine season with great stats"));
- assertEquals("Must be splitted into 2 lines.", 2, dumped.split("\n").length);
+ String etalonDumped = Util.getLocalResource("specification/example2_15_dumped.yaml");
+ assertEquals(etalonDumped, dumped);
}
@SuppressWarnings("unchecked")
diff --git a/src/test/java/org/yaml/snakeyaml/emitter/EmitterMultiLineTest.java b/src/test/java/org/yaml/snakeyaml/emitter/EmitterMultiLineTest.java
index 1e42317..dbe4504 100644
--- a/src/test/java/org/yaml/snakeyaml/emitter/EmitterMultiLineTest.java
+++ b/src/test/java/org/yaml/snakeyaml/emitter/EmitterMultiLineTest.java
@@ -16,6 +16,8 @@
package org.yaml.snakeyaml.emitter;
+import java.util.ArrayList;
+import java.util.List;
import java.util.Map;
import junit.framework.TestCase;
@@ -31,17 +33,39 @@
Yaml yaml = new Yaml();
String output = yaml.dump(plain);
// System.out.println(output);
- assertEquals("'mama\n\n mila\n\n ramu'\n", output);
+ assertEquals("|-\n mama\n mila\n ramu\n", output);
String parsed = (String) yaml.load(output);
// System.out.println(parsed);
assertEquals(plain, parsed);
}
+ public void testWriteMultiLinePlainList() {
+ String one = "first\nsecond\nthird";
+ String two = "one\ntwo\nthree\n";
+ byte[] binary = { 8, 14, 15, 10, 126, 32, 65, 65, 65 };
+ List<Object> list = new ArrayList<Object>(2);
+ list.add(one);
+ list.add(two);
+ list.add(binary);
+ DumperOptions options = new DumperOptions();
+ options.setDefaultFlowStyle(FlowStyle.BLOCK);
+ Yaml yaml = new Yaml(options);
+ String output = yaml.dump(list);
+ System.out.println(output);
+ String etalon = "- |-\n first\n second\n third\n- |\n one\n two\n three\n- !!binary |-\n CA4PCn4gQUFB\n";
+ assertEquals(etalon, output);
+ @SuppressWarnings("unchecked")
+ List<Object> parsed = (List<Object>) yaml.load(etalon);
+ assertEquals(3, parsed.size());
+ assertEquals(one, parsed.get(0));
+ assertEquals(two, parsed.get(1));
+ assertEquals(new String(binary), new String((byte[]) parsed.get(2)));
+ }
+
public void testWriteMultiLineLiteralNoChomping() {
String source = "a: 1\nb: |\n mama\n mila\n ramu\n";
// System.out.println("Source:\n" + source);
- DumperOptions options = new MyOptions();
- Yaml yaml = new Yaml(options);
+ Yaml yaml = new Yaml();
@SuppressWarnings("unchecked")
Map<String, Object> parsed = (Map<String, Object>) yaml.load(source);
String value = (String) parsed.get("b");
@@ -49,7 +73,7 @@
assertEquals("mama\nmila\nramu\n", value);
String dumped = yaml.dump(parsed);
// System.out.println(dumped);
- assertEquals("{a: 1, b: |\n mama\n mila\n ramu\n}\n", dumped);
+ assertEquals("a: 1\nb: |\n mama\n mila\n ramu\n", dumped);
}
public void testWriteMultiLineSingleQuotedInFlowContext() {
@@ -65,13 +89,13 @@
assertEquals("mama\nmila\nramu", value);
String dumped = yaml.dump(parsed);
// System.out.println(dumped);
- assertEquals(source, dumped);
+ assertEquals("{a: 1, b: \"mama\\nmila\\nramu\"}\n", dumped);
}
public void testWriteMultiLineLiteralWithStripChomping() {
String source = "a: 1\nb: |-\n mama\n mila\n ramu\n";
// System.out.println("Source:\n" + source);
- DumperOptions options = new MyOptions();
+ DumperOptions options = new DumperOptions();
options.setDefaultFlowStyle(FlowStyle.BLOCK);
Yaml yaml = new Yaml(options);
@SuppressWarnings("unchecked")
@@ -83,16 +107,4 @@
// System.out.println(dumped);
assertEquals(source, dumped);
}
-
- private class MyOptions extends DumperOptions {
- @Override
- public DumperOptions.ScalarStyle calculateScalarStyle(ScalarAnalysis analysis,
- DumperOptions.ScalarStyle style) {
- if (analysis.scalar.length() > 8) {
- return ScalarStyle.LITERAL;
- } else {
- return super.calculateScalarStyle(analysis, style);
- }
- }
- }
}
diff --git a/src/test/java/org/yaml/snakeyaml/emitter/EmitterTest.java b/src/test/java/org/yaml/snakeyaml/emitter/EmitterTest.java
index fd2a807..634b291 100644
--- a/src/test/java/org/yaml/snakeyaml/emitter/EmitterTest.java
+++ b/src/test/java/org/yaml/snakeyaml/emitter/EmitterTest.java
@@ -62,7 +62,7 @@
map.put("bbb", "\nbla-bla");
Yaml yaml = new Yaml(options);
String output = yaml.dump(map);
- String etalon = "{aaa: '0123456789 0123456789\n\n 0123456789 0123456789', bbb: '\n\n bla-bla'}\n";
+ String etalon = "aaa: |-\n 0123456789 0123456789\n 0123456789 0123456789\nbbb: |2-\n\n bla-bla\n";
assertEquals(etalon, output);
}
@@ -78,7 +78,7 @@
Yaml yaml = new Yaml(options);
String output = yaml.dump(map);
- String etalon = "{\n aaa: '0123456789 0123456789\n\n 0123456789 0123456789',\n bbb: '\n\n bla-bla'\n}\n";
+ String etalon = "aaa: |-\n 0123456789 0123456789\n 0123456789 0123456789\nbbb: |2-\n\n bla-bla\n";
assertEquals(etalon, output);
}
diff --git a/src/test/java/org/yaml/snakeyaml/types/StrTagTest.java b/src/test/java/org/yaml/snakeyaml/types/StrTagTest.java
index bd1eded..fd6c852 100644
--- a/src/test/java/org/yaml/snakeyaml/types/StrTagTest.java
+++ b/src/test/java/org/yaml/snakeyaml/types/StrTagTest.java
@@ -117,7 +117,7 @@
public void testEmitLongStringWithCR() {
String str = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\n\n";
String output = dump(str);
- assertEquals("'" + str + "\n '\n", output);
+ assertEquals("|+\n " + str, output);
}
public void testEmitDoubleQuoted() {
@@ -156,7 +156,7 @@
public void testEmitEndOfLine() {
String str = "xxxxxxx\n";
String output = dump(str);
- assertEquals("'" + str + "\n '\n", output);
+ assertEquals("|\n " + str, output);
}
public void testDumpUtf16() throws UnsupportedEncodingException {
diff --git a/src/test/resources/specification/example2_15_dumped.yaml b/src/test/resources/specification/example2_15_dumped.yaml
new file mode 100644
index 0000000..b7516cc
--- /dev/null
+++ b/src/test/resources/specification/example2_15_dumped.yaml
@@ -0,0 +1,7 @@
+>
+ Sammy Sosa completed another fine season with great stats.
+
+ 63 Home Runs
+ 0.288 Batting Average
+
+ What a year!
\ No newline at end of file
diff --git a/src/test/resources/specification/example2_27_dumped.yaml b/src/test/resources/specification/example2_27_dumped.yaml
index 1d865e0..5a36138 100644
--- a/src/test/resources/specification/example2_27_dumped.yaml
+++ b/src/test/resources/specification/example2_27_dumped.yaml
@@ -1,10 +1,12 @@
!!org.yaml.snakeyaml.Invoice
billTo: &id001
- address: {city: Royal Oak, lines: '458 Walkman Dr.
-
+ address:
+ city: Royal Oak
+ lines: |
+ 458 Walkman Dr.
Suite #292
-
- ', postal: '48046', state: MI}
+ postal: '48046'
+ state: MI
family: Dumars
given: Chris
comments: Late afternoon is best. Backup contact is Nancy Billsmer @ 338-4338.