Support for very basic inline tables

This commit is contained in:
moandji.ezana 2015-02-09 22:15:37 +02:00
parent de1bcbdca2
commit a5a6ab22dc
6 changed files with 198 additions and 2 deletions

View file

@ -0,0 +1,93 @@
package com.moandjiezana.toml;
import static com.moandjiezana.toml.ValueConverterUtils.INVALID;
import java.util.HashMap;
class InlineTableConverter implements ValueConverter {
static final InlineTableConverter INLINE_TABLE_PARSER = new InlineTableConverter();
private static final ValueConverters CONVERTERS = new ValueConverters();
@Override
public boolean canConvert(String s) {
return s.startsWith("{");
}
@Override
public Object convert(String s) {
char[] chars = s.toCharArray();
boolean inKey = true;
boolean pairHasKey = false;
boolean inValue = false;
boolean quoted = false;
boolean inString = false;
boolean terminated = false;
StringBuilder currentKey = new StringBuilder();
StringBuilder current = new StringBuilder();
HashMap<String, Object> results = new HashMap<String, Object>();
for (int i = 1; i < chars.length; i++) {
char c = chars[i];
if (terminated) {
if (Character.isWhitespace(c)) {
continue;
}
if (c == '#') {
break;
}
return INVALID;
}
if (c == '"') {
quoted = !quoted;
(inValue ? current : currentKey).append(c);
} else if (quoted) {
(inKey ? currentKey : current).append(c);
} else if (c == ',') {
Object converted = CONVERTERS.convert(current.toString().trim());
if (converted == INVALID) {
return INVALID;
}
results.put(currentKey.toString().trim(), converted);
inKey = true;
pairHasKey = false;
inValue = false;
currentKey = new StringBuilder();
current = new StringBuilder();
} else if (c == '=') {
inKey = false;
pairHasKey = true;
inValue = true;
} else if (c == '}') {
terminated = true;
if (current.toString().trim().length() == 0) {
continue;
}
Object converted = CONVERTERS.convert(current.toString().trim());
if (converted == INVALID) {
return INVALID;
}
results.put(currentKey.toString().trim(), converted);
} else {
(inKey ? currentKey : current).append(c);
}
}
if (!terminated) {
return INVALID;
}
return results;
}
private InlineTableConverter() {}
}

View file

@ -109,7 +109,15 @@ class Results {
void addValue(String key, Object value) {
Container currentTable = stack.peek();
if (currentTable.accepts(key)) {
if (value instanceof Map) {
startTable(key);
@SuppressWarnings("unchecked")
Map<String, Object> valueMap = (Map<String, Object>) value;
for (Map.Entry<String, Object> entry : valueMap.entrySet()) {
addValue(entry.getKey(), entry.getValue());
}
} else if (currentTable.accepts(key)) {
currentTable.put(key, value);
} else {
errors.duplicateKey(key, -1);

View file

@ -37,6 +37,7 @@ class TomlParser {
continue;
}
// TODO check that this works in multiline context
if (isTableArray(line)) {
String tableName = Keys.getTableArrayName(line);
if (tableName != null) {

View file

@ -3,6 +3,7 @@ package com.moandjiezana.toml;
import static com.moandjiezana.toml.ArrayConverter.ARRAY_PARSER;
import static com.moandjiezana.toml.BooleanConverter.BOOLEAN_PARSER;
import static com.moandjiezana.toml.DateConverter.DATE_PARSER;
import static com.moandjiezana.toml.InlineTableConverter.INLINE_TABLE_PARSER;
import static com.moandjiezana.toml.LiteralStringConverter.LITERAL_STRING_PARSER;
import static com.moandjiezana.toml.MultilineLiteralStringConverter.MULTILINE_LITERAL_STRING_CONVERTER;
import static com.moandjiezana.toml.MultilineStringConverter.MULTILINE_STRING_PARSER;
@ -13,7 +14,7 @@ import static com.moandjiezana.toml.ValueConverterUtils.INVALID;
class ValueConverters {
private static final ValueConverter[] PARSERS = {
MULTILINE_STRING_PARSER, MULTILINE_LITERAL_STRING_CONVERTER, LITERAL_STRING_PARSER, STRING_PARSER, DATE_PARSER, NUMBER_PARSER, BOOLEAN_PARSER, ARRAY_PARSER
MULTILINE_STRING_PARSER, MULTILINE_LITERAL_STRING_CONVERTER, LITERAL_STRING_PARSER, STRING_PARSER, DATE_PARSER, NUMBER_PARSER, BOOLEAN_PARSER, ARRAY_PARSER, INLINE_TABLE_PARSER
};
public Object convert(String value) {

View file

@ -0,0 +1,90 @@
package com.moandjiezana.toml;
import static org.hamcrest.Matchers.hasSize;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import java.util.Calendar;
import java.util.TimeZone;
import org.junit.Test;
public class InlineTableTest {
private static final TimeZone UTC = TimeZone.getTimeZone("UTC");
@Test
public void should_read_empty_inline_table() throws Exception {
Toml toml = new Toml().parse("key = {}");
assertNotNull(toml.getTable("key"));
}
@Test
public void should_read_inline_table_with_strings() throws Exception {
Toml toml = new Toml().parse("name = { first = \"Tom\", last = \"Preston-Werner\"}");
assertEquals("Tom", toml.getTable("name").getString("first"));
assertEquals("Preston-Werner", toml.getString("name.last"));
}
@Test
public void should_read_inline_table_with_integers() throws Exception {
Toml toml = new Toml().parse("point = { x = 1, y = 2 }");
assertEquals(1, toml.getTable("point").getLong("x").longValue());
assertEquals(2, toml.getLong("point.y").longValue());
}
@Test
public void should_read_inline_table_with_floats() throws Exception {
Toml toml = new Toml().parse("point = { x = 1.5, y = 2.3 }");
assertEquals(1.5, toml.getTable("point").getDouble("x").doubleValue(), 0);
assertEquals(2.3, toml.getDouble("point.y").doubleValue(), 0);
}
@Test
public void should_read_inline_table_with_booleans() throws Exception {
Toml toml = new Toml().parse("point = { x = false, y = true }");
assertTrue(toml.getTable("point").getBoolean("y"));
assertFalse(toml.getBoolean("point.x"));
}
@Test
public void should_read_inline_table_with_dates() throws Exception {
Toml toml = new Toml().parse("point = { x = 2015-02-09T22:05:00Z, y = 2015-02-09T21:05:00Z }");
Calendar x = Calendar.getInstance(UTC);
x.set(2015, Calendar.FEBRUARY, 9, 22, 5, 00);
x.set(Calendar.MILLISECOND, 0);
Calendar y = Calendar.getInstance(UTC);
y.set(2015, Calendar.FEBRUARY, 9, 21, 5, 00);
y.set(Calendar.MILLISECOND, 0);
assertEquals(x.getTime(), toml.getTable("point").getDate("x"));
assertEquals(y.getTime(), toml.getDate("point.y"));
}
@Test
public void should_support_array_of_inline_tables() throws Exception {
Toml toml = new Toml().parse(getClass().getResourceAsStream("should_support_array_of_inline_tables.toml"));
assertThat(toml.getList("points"), hasSize(4));
assertEquals(1, toml.getLong("points[0].x").longValue());
assertEquals(2, toml.getLong("points[0].y").longValue());
assertEquals(3, toml.getLong("points[0].z").longValue());
assertEquals(7, toml.getLong("points[1].x").longValue());
assertEquals(8, toml.getLong("points[1].y").longValue());
assertEquals(9, toml.getLong("points[1].z").longValue());
assertEquals(2, toml.getLong("points[2].x").longValue());
assertEquals(4, toml.getLong("points[2].y").longValue());
assertEquals(8, toml.getLong("points[2].z").longValue());
}
}

View file

@ -0,0 +1,3 @@
points = [ { x = 1, y = 2, z = 3 },
{ x = 7, y = 8, z = 9 },
{ x = 2, y = 4, z = 8 } ]