Added support for simple table array

This commit is contained in:
moandji.ezana 2014-04-07 13:10:44 +02:00
parent 5c3c868682
commit 095e33a03b
8 changed files with 177 additions and 38 deletions

View file

@ -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<Toml> 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)

View file

@ -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<String, Object>) get(key));
}
@SuppressWarnings("unchecked")
public List<Toml> getTables(String key) {
ArrayList<Toml> tables = new ArrayList<Toml>();
for (Map<String, Object> table : (List<Map<String, Object>>) get(key)) {
tables.add(new Toml(table));
}
return tables;
}
@SuppressWarnings("unchecked")
private Object get(String key) {
String[] split = key.split("\\.");

View file

@ -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<Object> {
}
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<Object> {
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<Object> {
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<String, Object> newTable = (Map<String, Object>) 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<String, Object>());
}
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<String, Object>) currentValue;
}
push(newTable);
return true;
return addTable(name, false);
}
boolean addKey(String key, Object value) {
@ -273,8 +251,59 @@ class TomlParser extends BaseParser<Object> {
}
@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<String, Object> newTable = (Map<String, Object>) 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<Map<String, Object>> newTableList = new ArrayList<Map<String, Object>>();
newTable.put(splitKey, newTableList);
} else {
newTable.put(splitKey, new HashMap<String, Object>());
}
}
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<String, Object> newTableListItem = new HashMap<String,Object>();
currentValue = ((List<Map<String, Object>>) currentValue).add(newTableListItem);
currentValue = newTableListItem;
}
newTable = (Map<String, Object>) currentValue;
}
push(newTable);
return true;
}
@SuppressWarnings("unchecked")
private void putValue(String name, Object value) {
Map<String, Object> values = (Map<String, Object>) peek();
Object top = peek();
if (top instanceof List) {
values = ((List<Map<String, Object>>) top).get(((List<Map<String, Object>>) 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<Object> {
values.put(name, value);
}
TomlParser.Results results() {
private TomlParser.Results results() {
return (Results) peek(getContext().getValueStack().size() - 1);
}
}

View file

@ -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<Toml> 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"));
}
}

View file

@ -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());
}

View file

@ -0,0 +1,10 @@
package com.moandjiezana.toml.testutils;
import java.util.List;
public class TomlTableArrays {
public List<TomlPrimitives> groupers;
public String name;
public TomlPrimitives primitives;
}

View file

@ -0,0 +1,10 @@
[[products]]
name = "Hammer"
sku = 738594937
[[products]]
[[products]]
name = "Nail"
sku = 284758393
color = "gray"

View file

@ -0,0 +1,10 @@
name="My Name"
[primitives]
number=12
[[groupers]]
string="grouper 1"
[[groupers]]
string="grouper 2"