From 72941c146d6251154d858c4ece00ff631522a8d4 Mon Sep 17 00:00:00 2001 From: Jonathan Wood Date: Sun, 28 Jun 2015 10:30:35 -0700 Subject: [PATCH] Add writer indentation policy controls. Set the default indentation to 0. --- .../com/moandjiezana/toml/MapValueWriter.java | 2 +- .../toml/TableArrayValueWriter.java | 2 +- .../com/moandjiezana/toml/TomlWriter.java | 22 +++- .../com/moandjiezana/toml/ValueWriters.java | 4 +- .../com/moandjiezana/toml/WriterContext.java | 46 ++++++-- .../toml/WriterIndentationPolicy.java | 41 +++++++ .../moandjiezana/toml/ValueWriterTest.java | 105 +++++++++++++----- 7 files changed, 185 insertions(+), 37 deletions(-) create mode 100644 src/main/java/com/moandjiezana/toml/WriterIndentationPolicy.java diff --git a/src/main/java/com/moandjiezana/toml/MapValueWriter.java b/src/main/java/com/moandjiezana/toml/MapValueWriter.java index 586c32b..d59bc65 100644 --- a/src/main/java/com/moandjiezana/toml/MapValueWriter.java +++ b/src/main/java/com/moandjiezana/toml/MapValueWriter.java @@ -56,7 +56,7 @@ class MapValueWriter implements ValueWriter { ValueWriter valueWriter = WRITERS.findWriterFor(fromValue); if (valueWriter.isTable() || valueWriter == TABLE_ARRAY_VALUE_WRITER) { - valueWriter.write(fromValue, context.extend(quoteKey(key))); + valueWriter.write(fromValue, context.pushTable(quoteKey(key))); } } } diff --git a/src/main/java/com/moandjiezana/toml/TableArrayValueWriter.java b/src/main/java/com/moandjiezana/toml/TableArrayValueWriter.java index acdff1e..d92ab17 100644 --- a/src/main/java/com/moandjiezana/toml/TableArrayValueWriter.java +++ b/src/main/java/com/moandjiezana/toml/TableArrayValueWriter.java @@ -16,7 +16,7 @@ class TableArrayValueWriter extends ArrayValueWriter { public void write(Object value, WriterContext context) { Collection values = normalize(value); - WriterContext subContext = context.extend().setIsArrayOfTable(true); + WriterContext subContext = context.pushTableFromArray(); for (Object elem : values) { WRITERS.write(elem, subContext); diff --git a/src/main/java/com/moandjiezana/toml/TomlWriter.java b/src/main/java/com/moandjiezana/toml/TomlWriter.java index 651d6df..28acc70 100644 --- a/src/main/java/com/moandjiezana/toml/TomlWriter.java +++ b/src/main/java/com/moandjiezana/toml/TomlWriter.java @@ -24,6 +24,9 @@ import static com.moandjiezana.toml.ValueWriters.WRITERS; * */ public class TomlWriter { + + private WriterIndentationPolicy indentationPolicy = new WriterIndentationPolicy(); + /** * Creates a TomlWriter instance. */ @@ -36,7 +39,7 @@ public class TomlWriter { * @return a string containing the TOML representation of the given Object */ public String write(Object from) { - return WRITERS.write(from); + return WRITERS.write(from, this); } /** @@ -73,4 +76,21 @@ public class TomlWriter { writer.write(write(from)); writer.close(); } + + public WriterIndentationPolicy getIndentationPolicy() { + return indentationPolicy; + } + + /** + * Set the {@link WriterIndentationPolicy} for this writer. + * + * If unset, the default policy (no indentation) is used. + * + * @param indentationPolicy the new policy + * @return this TomlWriter instance + */ + public TomlWriter setIndentationPolicy(WriterIndentationPolicy indentationPolicy) { + this.indentationPolicy = indentationPolicy; + return this; + } } diff --git a/src/main/java/com/moandjiezana/toml/ValueWriters.java b/src/main/java/com/moandjiezana/toml/ValueWriters.java index 4fe7695..aba1b99 100644 --- a/src/main/java/com/moandjiezana/toml/ValueWriters.java +++ b/src/main/java/com/moandjiezana/toml/ValueWriters.java @@ -23,8 +23,8 @@ class ValueWriters { return OBJECT_VALUE_WRITER; } - String write(Object value) { - WriterContext context = new WriterContext(); + String write(Object value, TomlWriter tomlWriter) { + WriterContext context = new WriterContext(tomlWriter); write(value, context); return context.output.toString(); diff --git a/src/main/java/com/moandjiezana/toml/WriterContext.java b/src/main/java/com/moandjiezana/toml/WriterContext.java index e07e828..ba6edb6 100644 --- a/src/main/java/com/moandjiezana/toml/WriterContext.java +++ b/src/main/java/com/moandjiezana/toml/WriterContext.java @@ -1,26 +1,43 @@ package com.moandjiezana.toml; +import java.util.Arrays; + class WriterContext { private String key = ""; + private String currentTableIndent = ""; + private String currentFieldIndent = ""; private boolean isArrayOfTable = false; + private final TomlWriter tomlWriter; StringBuilder output = new StringBuilder(); - WriterContext(String key, StringBuilder output) { + WriterContext(String key, String tableIndent, StringBuilder output, TomlWriter tomlWriter) { this.key = key; + this.currentTableIndent = tableIndent; + this.currentFieldIndent = tableIndent + fillStringWithSpaces(tomlWriter.getIndentationPolicy().getKeyValueIndent()); this.output = output; + this.tomlWriter = tomlWriter; } - WriterContext() { + WriterContext(TomlWriter tomlWriter) { + this.tomlWriter = tomlWriter; } - WriterContext extend(String newKey) { + WriterContext pushTable(String newKey) { + String newIndent = ""; + if (!key.isEmpty()) { + newIndent = growIndent(tomlWriter.getIndentationPolicy()); + } + String fullKey = key + (key.isEmpty() ? newKey : "." + newKey); - return new WriterContext(fullKey, output); + return new WriterContext(fullKey, newIndent, output, tomlWriter); } - WriterContext extend() { - return new WriterContext(key, output); + WriterContext pushTableFromArray() { + WriterContext subContext = new WriterContext(key, currentTableIndent, output, tomlWriter); + subContext.setIsArrayOfTable(true); + + return subContext; } void writeKey() { @@ -32,6 +49,8 @@ class WriterContext { output.append('\n'); } + output.append(currentTableIndent); + if (isArrayOfTable) { output.append("[[").append(key).append("]]\n"); } else { @@ -40,11 +59,24 @@ class WriterContext { } void indent() { - output.append(key.isEmpty() ? "" : " "); + if (!key.isEmpty()) { + output.append(currentFieldIndent); + } } WriterContext setIsArrayOfTable(boolean isArrayOfTable) { this.isArrayOfTable = isArrayOfTable; return this; } + + private String growIndent(WriterIndentationPolicy indentationPolicy) { + return currentTableIndent + fillStringWithSpaces(indentationPolicy.getTableIndent()); + } + + private String fillStringWithSpaces(int count) { + char[] chars = new char[count]; + Arrays.fill(chars, ' '); + + return new String(chars); + } } diff --git a/src/main/java/com/moandjiezana/toml/WriterIndentationPolicy.java b/src/main/java/com/moandjiezana/toml/WriterIndentationPolicy.java new file mode 100644 index 0000000..b8587c5 --- /dev/null +++ b/src/main/java/com/moandjiezana/toml/WriterIndentationPolicy.java @@ -0,0 +1,41 @@ +package com.moandjiezana.toml; + +/** + * Controls how a {@link TomlWriter} indents tables and key/value pairs. + * + * The default policy is to not indent. + */ +public class WriterIndentationPolicy { + private int tableIndent = 0; + private int keyValueIndent = 0; + + public int getTableIndent() { + return tableIndent; + } + + /** + * Sets the number of spaces a nested table name is indented. + * + * @param tableIndent number of spaces to indent + * @return this WriterIndentationPolicy instance + */ + public WriterIndentationPolicy setTableIndent(int tableIndent) { + this.tableIndent = tableIndent; + return this; + } + + public int getKeyValueIndent() { + return keyValueIndent; + } + + /** + * Sets the number of spaces key/value pairs within a table are indented. + * + * @param keyValueIndent number of spaces to indent + * @return this WriterIndentationPolicy instance + */ + public WriterIndentationPolicy setKeyValueIndent(int keyValueIndent) { + this.keyValueIndent = keyValueIndent; + return this; + } +} diff --git a/src/test/java/com/moandjiezana/toml/ValueWriterTest.java b/src/test/java/com/moandjiezana/toml/ValueWriterTest.java index 48a0a06..9545e55 100644 --- a/src/test/java/com/moandjiezana/toml/ValueWriterTest.java +++ b/src/test/java/com/moandjiezana/toml/ValueWriterTest.java @@ -60,21 +60,20 @@ public class ValueWriterTest { return dateString; } - @Test - public void should_write_nested_map() { - class SubChild { - int anInt; - } - class Child { - SubChild subChild; - int anInt; - } - class Parent { - Map aMap; - Child child; - boolean aBoolean; - } + class SubChild { + int anInt; + } + class Child { + SubChild subChild; + int anInt; + } + class Parent { + Map aMap; + Child child; + boolean aBoolean; + } + private Parent buildNestedMap() { Parent parent = new Parent(); parent.aMap = new LinkedHashMap(); parent.aMap.put("foo", 1); @@ -86,7 +85,29 @@ public class ValueWriterTest { parent.child.subChild.anInt = 4; parent.aBoolean = true; - String output = new TomlWriter().write(parent); + return parent; + } + + @Test + public void should_write_nested_map() { + String output = new TomlWriter().write(buildNestedMap()); + String expected = "aBoolean = true\n\n" + + "[aMap]\n" + + "foo = 1\n" + + "bar = \"value1\"\n" + + "\"baz.x\" = true\n\n" + + "[child]\n" + + "anInt = 2\n\n" + + "[child.subChild]\n" + + "anInt = 4\n"; + assertEquals(expected, output); + } + + @Test + public void should_follow_indentation_policy_of_indented_values() { + String output = new TomlWriter(). + setIndentationPolicy(new WriterIndentationPolicy().setKeyValueIndent(2)). + write(buildNestedMap()); String expected = "aBoolean = true\n\n" + "[aMap]\n" + " foo = 1\n" + @@ -99,6 +120,40 @@ public class ValueWriterTest { assertEquals(expected, output); } + @Test + public void should_follow_indentation_policy_of_indented_tables() { + String output = new TomlWriter(). + setIndentationPolicy(new WriterIndentationPolicy().setTableIndent(2)). + write(buildNestedMap()); + String expected = "aBoolean = true\n\n" + + "[aMap]\n" + + "foo = 1\n" + + "bar = \"value1\"\n" + + "\"baz.x\" = true\n\n" + + "[child]\n" + + "anInt = 2\n\n" + + " [child.subChild]\n" + + " anInt = 4\n"; + assertEquals(expected, output); + } + + @Test + public void should_follow_indentation_policy_of_indented_tables_and_values() { + String output = new TomlWriter(). + setIndentationPolicy(new WriterIndentationPolicy().setTableIndent(2).setKeyValueIndent(2)). + write(buildNestedMap()); + String expected = "aBoolean = true\n\n" + + "[aMap]\n" + + " foo = 1\n" + + " bar = \"value1\"\n" + + " \"baz.x\" = true\n\n" + + "[child]\n" + + " anInt = 2\n\n" + + " [child.subChild]\n" + + " anInt = 4\n"; + assertEquals(expected, output); + } + @Test public void should_write_array_of_primitive() { class ArrayTest { @@ -128,9 +183,9 @@ public class ValueWriterTest { String output = new TomlWriter().write(config); String expected = "[[table]]\n" + - " anInt = 1\n\n" + + "anInt = 1\n\n" + "[[table]]\n" + - " anInt = 2\n"; + "anInt = 2\n"; assertEquals(expected, output); } @@ -179,7 +234,7 @@ public class ValueWriterTest { B b = new B(); } - assertEquals("[b.c]\n anInt = 1\n", new TomlWriter().write(new A())); + assertEquals("[b.c]\nanInt = 1\n", new TomlWriter().write(new A())); } @Test @@ -221,23 +276,23 @@ public class ValueWriterTest { basket.fruit[1].variety[0].name = "plantain"; String expected = "[[fruit]]\n" + - " name = \"apple\"\n" + + "name = \"apple\"\n" + "\n" + "[fruit.physical]\n" + - " color = \"red\"\n" + - " shape = \"round\"\n" + + "color = \"red\"\n" + + "shape = \"round\"\n" + "\n" + "[[fruit.variety]]\n" + - " name = \"red delicious\"\n" + + "name = \"red delicious\"\n" + "\n" + "[[fruit.variety]]\n" + - " name = \"granny smith\"\n" + + "name = \"granny smith\"\n" + "\n" + "[[fruit]]\n" + - " name = \"banana\"\n" + + "name = \"banana\"\n" + "\n" + "[[fruit.variety]]\n" + - " name = \"plantain\"" + + "name = \"plantain\"" + "\n";