mirror of
https://github.com/plexusorg/toml4j.git
synced 2025-01-01 13:02:37 +00:00
Added support for simple table array
This commit is contained in:
parent
5c3c868682
commit
095e33a03b
8 changed files with 177 additions and 38 deletions
24
README.md
24
README.md
|
@ -85,6 +85,30 @@ Long c = toml.getLong("c"); // returns null
|
||||||
|
|
||||||
* Fail on invalid definitions
|
* 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
|
## License
|
||||||
|
|
||||||
toml4j is copyright of Moandji Ezana and is licensed under the [MIT License](http://www.opensource.org/licenses/mit-license.php)
|
toml4j is copyright of Moandji Ezana and is licensed under the [MIT License](http://www.opensource.org/licenses/mit-license.php)
|
||||||
|
|
|
@ -1,9 +1,8 @@
|
||||||
package com.moandjiezana.toml;
|
package com.moandjiezana.toml;
|
||||||
|
|
||||||
import com.google.gson.Gson;
|
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileNotFoundException;
|
import java.io.FileNotFoundException;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -14,6 +13,8 @@ import org.parboiled.Parboiled;
|
||||||
import org.parboiled.parserunners.RecoveringParseRunner;
|
import org.parboiled.parserunners.RecoveringParseRunner;
|
||||||
import org.parboiled.support.ParsingResult;
|
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.
|
* 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));
|
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")
|
@SuppressWarnings("unchecked")
|
||||||
private Object get(String key) {
|
private Object get(String key) {
|
||||||
String[] split = key.split("\\.");
|
String[] split = key.split("\\.");
|
||||||
|
|
|
@ -5,6 +5,7 @@ import java.util.ArrayList;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
|
@ -23,15 +24,19 @@ class TomlParser extends BaseParser<Object> {
|
||||||
}
|
}
|
||||||
|
|
||||||
public Rule Toml() {
|
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() {
|
Rule Table() {
|
||||||
return Sequence(Sequence(TableDelimiter(), TableName(), addTable((String) pop()), TableDelimiter(), Spacing()), checkTable(match()));
|
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) {
|
boolean checkTable(String definition) {
|
||||||
String afterBracket = definition.substring(definition.indexOf(']') + 1);
|
String afterBracket = definition.substring(definition.lastIndexOf(']') + 1);
|
||||||
for (char character : afterBracket.toCharArray()) {
|
for (char character : afterBracket.toCharArray()) {
|
||||||
if (character == '#') {
|
if (character == '#') {
|
||||||
return true;
|
return true;
|
||||||
|
@ -129,7 +134,6 @@ class TomlParser extends BaseParser<Object> {
|
||||||
|
|
||||||
Rule IllegalCharacters() {
|
Rule IllegalCharacters() {
|
||||||
return Sequence(ZeroOrMore(Whitespace()), OneOrMore(TestNot('#', NewLine()), ANY));
|
return Sequence(ZeroOrMore(Whitespace()), OneOrMore(TestNot('#', NewLine()), ANY));
|
||||||
//return Sequence(ZeroOrMore(Whitespace()), TestNot('#', NewLine()), OneOrMore(ANY));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressNode
|
@SuppressNode
|
||||||
|
@ -152,38 +156,12 @@ class TomlParser extends BaseParser<Object> {
|
||||||
return Sequence('#', ZeroOrMore(TestNot(NewLine()), ANY), FirstOf(NewLine(), EOI));
|
return Sequence('#', ZeroOrMore(TestNot(NewLine()), ANY), FirstOf(NewLine(), EOI));
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
boolean addTableArray(String name) {
|
||||||
|
return addTable(name, true);
|
||||||
|
}
|
||||||
|
|
||||||
boolean addTable(String name) {
|
boolean addTable(String name) {
|
||||||
String[] split = name.split("\\.");
|
return addTable(name, false);
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean addKey(String key, Object value) {
|
boolean addKey(String key, Object value) {
|
||||||
|
@ -273,8 +251,59 @@ class TomlParser extends BaseParser<Object> {
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@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();
|
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)) {
|
if (values.containsKey(name)) {
|
||||||
results().errors.append("Key ").append(name).append(" already exists!\n");
|
results().errors.append("Key ").append(name).append(" already exists!\n");
|
||||||
return;
|
return;
|
||||||
|
@ -282,7 +311,7 @@ class TomlParser extends BaseParser<Object> {
|
||||||
values.put(name, value);
|
values.put(name, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
TomlParser.Results results() {
|
private TomlParser.Results results() {
|
||||||
return (Results) peek(getContext().getValueStack().size() - 1);
|
return (Results) peek(getContext().getValueStack().size() - 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
32
src/test/java/com/moandjiezana/toml/TableArrayTest.java
Normal file
32
src/test/java/com/moandjiezana/toml/TableArrayTest.java
Normal 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"));
|
||||||
|
}
|
||||||
|
}
|
|
@ -11,6 +11,7 @@ import org.junit.Test;
|
||||||
|
|
||||||
import com.moandjiezana.toml.testutils.TableAsMap;
|
import com.moandjiezana.toml.testutils.TableAsMap;
|
||||||
import com.moandjiezana.toml.testutils.TomlPrimitives;
|
import com.moandjiezana.toml.testutils.TomlPrimitives;
|
||||||
|
import com.moandjiezana.toml.testutils.TomlTableArrays;
|
||||||
import com.moandjiezana.toml.testutils.TomlTables;
|
import com.moandjiezana.toml.testutils.TomlTables;
|
||||||
|
|
||||||
public class TomlToClassTest {
|
public class TomlToClassTest {
|
||||||
|
@ -69,6 +70,18 @@ public class TomlToClassTest {
|
||||||
assertEquals("value", tableAsMap.group.get("key"));
|
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) {
|
private File file(String fileName) {
|
||||||
return new File(getClass().getResource(fileName).getFile());
|
return new File(getClass().getResource(fileName).getFile());
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
|
@ -0,0 +1,10 @@
|
||||||
|
[[products]]
|
||||||
|
name = "Hammer"
|
||||||
|
sku = 738594937
|
||||||
|
|
||||||
|
[[products]]
|
||||||
|
|
||||||
|
[[products]]
|
||||||
|
name = "Nail"
|
||||||
|
sku = 284758393
|
||||||
|
color = "gray"
|
|
@ -0,0 +1,10 @@
|
||||||
|
name="My Name"
|
||||||
|
|
||||||
|
[primitives]
|
||||||
|
number=12
|
||||||
|
|
||||||
|
[[groupers]]
|
||||||
|
string="grouper 1"
|
||||||
|
|
||||||
|
[[groupers]]
|
||||||
|
string="grouper 2"
|
Loading…
Reference in a new issue