From 095e33a03bece4be867db74f692f2a0b8f1b6a56 Mon Sep 17 00:00:00 2001 From: "moandji.ezana" Date: Mon, 7 Apr 2014 13:10:44 +0200 Subject: [PATCH] Added support for simple table array --- README.md | 24 +++++ src/main/java/com/moandjiezana/toml/Toml.java | 15 ++- .../com/moandjiezana/toml/TomlParser.java | 101 +++++++++++------- .../com/moandjiezana/toml/TableArrayTest.java | 32 ++++++ .../moandjiezana/toml/TomlToClassTest.java | 13 +++ .../toml/testutils/TomlTableArrays.java | 10 ++ .../toml/products_table_array.toml | 10 ++ .../should_convert_table_array_to_class.toml | 10 ++ 8 files changed, 177 insertions(+), 38 deletions(-) create mode 100644 src/test/java/com/moandjiezana/toml/TableArrayTest.java create mode 100644 src/test/java/com/moandjiezana/toml/testutils/TomlTableArrays.java create mode 100644 src/test/resources/com/moandjiezana/toml/products_table_array.toml create mode 100644 src/test/resources/com/moandjiezana/toml/should_convert_table_array_to_class.toml diff --git a/README.md b/README.md index 7188ff4..1f9a2c0 100644 --- a/README.md +++ b/README.md @@ -85,6 +85,30 @@ Long c = toml.getLong("c"); // returns null * Fail on invalid definitions +## Coming in 0.2.0 + +### Table arrays + +Table arrays are mapped to `List`s with `Toml#getTables(String)`. Custom classes are also supported. + +```` +[[products]] + name = "Hammer" + sku = 738594937 + +[[products]] + name = "Nail" + sku = 284758393 + color = "gray" +```` + +````java +Toml toml = new Toml().parse(getTomlFile()); + +List tables = toml.getTables("products"); +tables.get(1).getLong("sku"); // returns 284758393 +```` + ## License toml4j is copyright of Moandji Ezana and is licensed under the [MIT License](http://www.opensource.org/licenses/mit-license.php) diff --git a/src/main/java/com/moandjiezana/toml/Toml.java b/src/main/java/com/moandjiezana/toml/Toml.java index 9470fd1..2fe38d3 100644 --- a/src/main/java/com/moandjiezana/toml/Toml.java +++ b/src/main/java/com/moandjiezana/toml/Toml.java @@ -1,9 +1,8 @@ package com.moandjiezana.toml; -import com.google.gson.Gson; - import java.io.File; import java.io.FileNotFoundException; +import java.util.ArrayList; import java.util.Date; import java.util.HashMap; import java.util.List; @@ -14,6 +13,8 @@ import org.parboiled.Parboiled; import org.parboiled.parserunners.RecoveringParseRunner; import org.parboiled.support.ParsingResult; +import com.google.gson.Gson; + /** * * All getters can fall back to default values if they have been provided and will return null if no matching key exists. @@ -86,6 +87,16 @@ public class Toml { return new Toml((Map) get(key)); } + @SuppressWarnings("unchecked") + public List getTables(String key) { + ArrayList tables = new ArrayList(); + for (Map table : (List>) get(key)) { + tables.add(new Toml(table)); + } + + return tables; + } + @SuppressWarnings("unchecked") private Object get(String key) { String[] split = key.split("\\."); diff --git a/src/main/java/com/moandjiezana/toml/TomlParser.java b/src/main/java/com/moandjiezana/toml/TomlParser.java index 622a213..2c02383 100644 --- a/src/main/java/com/moandjiezana/toml/TomlParser.java +++ b/src/main/java/com/moandjiezana/toml/TomlParser.java @@ -5,6 +5,7 @@ import java.util.ArrayList; import java.util.Date; import java.util.HashMap; import java.util.HashSet; +import java.util.List; import java.util.Map; import java.util.Set; @@ -23,15 +24,19 @@ class TomlParser extends BaseParser { } public Rule Toml() { - return Sequence(push(new TomlParser.Results()), push(((TomlParser.Results) peek()).values), OneOrMore(FirstOf(Table(), '\n', Comment(), Key()))); + return Sequence(push(new TomlParser.Results()), push(((TomlParser.Results) peek()).values), OneOrMore(FirstOf(TableArray(), Table(), '\n', Comment(), Key()))); } Rule Table() { return Sequence(Sequence(TableDelimiter(), TableName(), addTable((String) pop()), TableDelimiter(), Spacing()), checkTable(match())); } + Rule TableArray() { + return Sequence(Sequence(TableDelimiter(), TableDelimiter(), TableName(), addTableArray((String) pop()), TableDelimiter(), TableDelimiter(), Spacing()), checkTable(match())); + } + boolean checkTable(String definition) { - String afterBracket = definition.substring(definition.indexOf(']') + 1); + String afterBracket = definition.substring(definition.lastIndexOf(']') + 1); for (char character : afterBracket.toCharArray()) { if (character == '#') { return true; @@ -129,7 +134,6 @@ class TomlParser extends BaseParser { Rule IllegalCharacters() { return Sequence(ZeroOrMore(Whitespace()), OneOrMore(TestNot('#', NewLine()), ANY)); - //return Sequence(ZeroOrMore(Whitespace()), TestNot('#', NewLine()), OneOrMore(ANY)); } @SuppressNode @@ -152,38 +156,12 @@ class TomlParser extends BaseParser { return Sequence('#', ZeroOrMore(TestNot(NewLine()), ANY), FirstOf(NewLine(), EOI)); } - @SuppressWarnings("unchecked") + boolean addTableArray(String name) { + return addTable(name, true); + } + boolean addTable(String name) { - String[] split = name.split("\\."); - - while (getContext().getValueStack().size() > 2) { - drop(); - } - - Map newTable = (Map) getContext().getValueStack().peek(); - - if (!results().tables.add(name)) { - results().errors.append("Could not create key group ").append(name).append(": key group already exists!\n"); - - return true; - } - - for (String splitKey : split) { - if (!newTable.containsKey(splitKey)) { - newTable.put(splitKey, new HashMap()); - } - Object currentValue = newTable.get(splitKey); - if (!(currentValue instanceof Map)) { - results().errors.append("Could not create key group ").append(name).append(": key already has a value!\n"); - - return true; - } - newTable = (Map) currentValue; - } - - push(newTable); - - return true; + return addTable(name, false); } boolean addKey(String key, Object value) { @@ -273,8 +251,59 @@ class TomlParser extends BaseParser { } @SuppressWarnings("unchecked") - void putValue(String name, Object value) { + private boolean addTable(String name, boolean array) { + String[] split = name.split("\\."); + + while (getContext().getValueStack().size() > 2) { + drop(); + } + + Map newTable = (Map) getContext().getValueStack().peek(); + + boolean addedToTables = results().tables.add(name); + if (!addedToTables && !array) { + results().errors.append("Could not create table ").append(name).append(": table already exists!\n"); + + return true; + } + + for (String splitKey : split) { + if (!newTable.containsKey(splitKey)) { + if (array) { + ArrayList> newTableList = new ArrayList>(); + newTable.put(splitKey, newTableList); + } else { + newTable.put(splitKey, new HashMap()); + } + } + Object currentValue = newTable.get(splitKey); + if ((array && !(currentValue instanceof List)) || (!array && !(currentValue instanceof Map))) { + results().errors.append("Could not create table ").append(name).append(": key already has a value!\n"); + + return true; + } + + if (currentValue instanceof List) { + Map newTableListItem = new HashMap(); + currentValue = ((List>) currentValue).add(newTableListItem); + currentValue = newTableListItem; + } + + newTable = (Map) currentValue; + } + + push(newTable); + + return true; + } + + @SuppressWarnings("unchecked") + private void putValue(String name, Object value) { Map values = (Map) peek(); + Object top = peek(); + if (top instanceof List) { + values = ((List>) top).get(((List>) top).size() - 1); + } if (values.containsKey(name)) { results().errors.append("Key ").append(name).append(" already exists!\n"); return; @@ -282,7 +311,7 @@ class TomlParser extends BaseParser { values.put(name, value); } - TomlParser.Results results() { + private TomlParser.Results results() { return (Results) peek(getContext().getValueStack().size() - 1); } } diff --git a/src/test/java/com/moandjiezana/toml/TableArrayTest.java b/src/test/java/com/moandjiezana/toml/TableArrayTest.java new file mode 100644 index 0000000..570aaa1 --- /dev/null +++ b/src/test/java/com/moandjiezana/toml/TableArrayTest.java @@ -0,0 +1,32 @@ +package com.moandjiezana.toml; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; + +import java.io.File; +import java.util.List; + +import org.junit.Assert; +import org.junit.Test; + +public class TableArrayTest { + + @Test + public void should_parse_table_array() throws Exception { + Toml toml = new Toml().parse(new File(getClass().getResource("products_table_array.toml").getFile())); + + List products = toml.getTables("products"); + + assertEquals(3, products.size()); + + assertEquals("Hammer", products.get(0).getString("name")); + assertEquals(738594937L, products.get(0).getLong("sku").longValue()); + + Assert.assertNull(products.get(1).getString("name")); + assertNull(products.get(1).getLong("sku")); + + assertEquals("Nail", products.get(2).getString("name")); + assertEquals(284758393L, products.get(2).getLong("sku").longValue()); + assertEquals("gray", products.get(2).getString("color")); + } +} diff --git a/src/test/java/com/moandjiezana/toml/TomlToClassTest.java b/src/test/java/com/moandjiezana/toml/TomlToClassTest.java index 6a5d4b3..8ca6685 100644 --- a/src/test/java/com/moandjiezana/toml/TomlToClassTest.java +++ b/src/test/java/com/moandjiezana/toml/TomlToClassTest.java @@ -11,6 +11,7 @@ import org.junit.Test; import com.moandjiezana.toml.testutils.TableAsMap; import com.moandjiezana.toml.testutils.TomlPrimitives; +import com.moandjiezana.toml.testutils.TomlTableArrays; import com.moandjiezana.toml.testutils.TomlTables; public class TomlToClassTest { @@ -69,6 +70,18 @@ public class TomlToClassTest { assertEquals("value", tableAsMap.group.get("key")); } + @Test + public void should_convert_table_array() throws Exception { + TomlTableArrays toml = new Toml().parse(file("should_convert_table_array_to_class.toml")).to(TomlTableArrays.class); + + assertEquals(2, toml.groupers.size()); + assertEquals("grouper 1", toml.groupers.get(0).string); + assertEquals("grouper 2", toml.groupers.get(1).string); + + assertEquals("My Name", toml.name); + assertEquals(12, toml.primitives.number.intValue()); + } + private File file(String fileName) { return new File(getClass().getResource(fileName).getFile()); } diff --git a/src/test/java/com/moandjiezana/toml/testutils/TomlTableArrays.java b/src/test/java/com/moandjiezana/toml/testutils/TomlTableArrays.java new file mode 100644 index 0000000..c4becb4 --- /dev/null +++ b/src/test/java/com/moandjiezana/toml/testutils/TomlTableArrays.java @@ -0,0 +1,10 @@ +package com.moandjiezana.toml.testutils; + +import java.util.List; + +public class TomlTableArrays { + + public List groupers; + public String name; + public TomlPrimitives primitives; +} diff --git a/src/test/resources/com/moandjiezana/toml/products_table_array.toml b/src/test/resources/com/moandjiezana/toml/products_table_array.toml new file mode 100644 index 0000000..ac3883b --- /dev/null +++ b/src/test/resources/com/moandjiezana/toml/products_table_array.toml @@ -0,0 +1,10 @@ +[[products]] +name = "Hammer" +sku = 738594937 + +[[products]] + +[[products]] +name = "Nail" +sku = 284758393 +color = "gray" diff --git a/src/test/resources/com/moandjiezana/toml/should_convert_table_array_to_class.toml b/src/test/resources/com/moandjiezana/toml/should_convert_table_array_to_class.toml new file mode 100644 index 0000000..eeed352 --- /dev/null +++ b/src/test/resources/com/moandjiezana/toml/should_convert_table_array_to_class.toml @@ -0,0 +1,10 @@ +name="My Name" + +[primitives] + number=12 + +[[groupers]] + string="grouper 1" + +[[groupers]] + string="grouper 2" \ No newline at end of file