Added support for quoted keys

https://github.com/toml-lang/toml/pull/283
This commit is contained in:
moandji.ezana 2015-01-14 09:46:36 +02:00
parent 98701694c4
commit db950ab054
5 changed files with 117 additions and 5 deletions

View file

@ -51,6 +51,9 @@ name = "Mwanji Ezana"
[address] [address]
street = "123 A Street" street = "123 A Street"
city = "AnyVille" city = "AnyVille"
[contacts]
"email address" = me@example.com
```` ````
````java ````java
@ -62,6 +65,7 @@ class Address {
class User { class User {
String name; String name;
Address address; Address address;
Map<String, Object> contacts;
} }
```` ````
@ -70,10 +74,13 @@ User user = new Toml().parse(tomlFile).to(User.class);
assert user.name.equals("Mwanji Ezana"); assert user.name.equals("Mwanji Ezana");
assert user.address.street.equals("123 A Street"); assert user.address.street.equals("123 A Street");
assert user.contacts.get("\"email address\"").equals("me@example.com");
```` ````
Any keys not found in both the TOML and the class are ignored. Fields may be private. Any keys not found in both the TOML and the class are ignored. Fields may be private.
Quoted keys cannot be mapped directly to a Java object, but they can be used as keys within a `Map`.
All TOML primitives can be mapped, as well as a number of Java-specific types: All TOML primitives can be mapped, as well as a number of Java-specific types:
* A TOML Number can be converted to any primitive type (or the wrapper equivalent), `BigInteger` or `BigDecimal` * A TOML Number can be converted to any primitive type (or the wrapper equivalent), `BigInteger` or `BigDecimal`
@ -102,8 +109,11 @@ You can also navigate values within a table with a compound key of the form `tab
Non-existent keys return null. Non-existent keys return null.
When retrieving quoted keys, the quotes must be used and the key must be spelled exactly the same way, including whitespace.
```` ````
title = "TOML Example" title = "TOML Example"
"sub title" = "Now with quoted keys"
[database] [database]
ports = [ 8001, 8001, 8002 ] ports = [ 8001, 8001, 8002 ]
@ -136,6 +146,7 @@ title = "TOML Example"
Toml toml = new Toml().parse(getTomlFile()); Toml toml = new Toml().parse(getTomlFile());
String title = toml.getString("title"); String title = toml.getString("title");
String subTitle = toml.getString("\"sub title\"");
Boolean enabled = toml.getBoolean("database.enabled"); Boolean enabled = toml.getBoolean("database.enabled");
List<Long> ports = toml.getList("database.ports", Long.class); List<Long> ports = toml.getList("database.ports", Long.class);
String password = toml.getString("database.credentials.password"); String password = toml.getString("database.credentials.password");

View file

@ -0,0 +1,33 @@
package com.moandjiezana.toml;
import java.util.ArrayList;
import java.util.List;
class Keys {
static String[] split(String key) {
List<String> splitKey = new ArrayList<String>();
StringBuilder current = new StringBuilder();
char[] chars = key.toCharArray();
boolean quoted = false;
for (char c : chars) {
if (c == '"') {
quoted = !quoted;
}
if (c != '.' || quoted) {
current.append(c);
} else {
splitKey.add(current.toString());
current = new StringBuilder();
}
}
splitKey.add(current.toString());
return splitKey.toArray(new String[0]);
}
private Keys() {}
}

View file

@ -75,7 +75,7 @@ class Results {
stack.pop(); stack.pop();
} }
String[] tableParts = tableName.split("\\."); String[] tableParts = Keys.split(tableName);
for (int i = 0; i < tableParts.length; i++) { for (int i = 0; i < tableParts.length; i++) {
String tablePart = tableParts[i]; String tablePart = tableParts[i];
Container currentContainer = stack.peek(); Container currentContainer = stack.peek();

View file

@ -246,13 +246,14 @@ public class Toml {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
private Object get(String key) { private Object get(String key) {
String[] split = key.split("\\."); if (values.containsKey(key)) {
return values.get(key);
}
String[] split = Keys.split(key);
Object current = new HashMap<String, Object>(values); Object current = new HashMap<String, Object>(values);
for (int i = 0; i < split.length; i++) { for (int i = 0; i < split.length; i++) {
if (i == 0 && values.containsKey(key)) {
return values.get(key);
}
String keyWithDot = join(Arrays.copyOfRange(split, i, split.length)); String keyWithDot = join(Arrays.copyOfRange(split, i, split.length));
if (current instanceof Map && ((Map<String, Object>) current).containsKey(keyWithDot)) { if (current instanceof Map && ((Map<String, Object>) current).containsKey(keyWithDot)) {

View file

@ -0,0 +1,67 @@
package com.moandjiezana.toml;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import java.util.Map;
import org.junit.Test;
public class QuotedKeysTest {
@Test
public void should_accept_quoted_key_for_value() throws Exception {
Toml toml = new Toml().parse("\"127.0.0.1\" = \"localhost\" \n \"character encoding\" = \"UTF-8\" \n \"ʎǝʞ\" = \"value\"");
assertEquals("localhost", toml.getString("\"127.0.0.1\""));
assertEquals("UTF-8", toml.getString("\"character encoding\""));
assertEquals("value", toml.getString("\"ʎǝʞ\""));
}
@Test
public void should_accept_quoted_key_for_table_name() throws Exception {
Toml toml = new Toml().parse("[\"abc def\"]\n val = 1");
assertEquals(1L, toml.getTable("\"abc def\"").getLong("val").longValue());
}
@Test
public void should_accept_partially_quoted_table_name() throws Exception {
Toml toml = new Toml().parse("[dog.\"tater.man\"] \n type = \"pug0\" \n[dog.tater] \n type = \"pug1\"\n[dog.tater.man] \n type = \"pug2\"");
Toml dogs = toml.getTable("dog");
assertEquals("pug0", dogs.getTable("\"tater.man\"").getString("type"));
assertEquals("pug1", dogs.getTable("tater").getString("type"));
assertEquals("pug2", dogs.getTable("tater").getTable("man").getString("type"));
assertEquals("pug0", toml.getString("dog.\"tater.man\".type"));
assertEquals("pug2", toml.getString("dog.tater.man.type"));
}
@Test
@SuppressWarnings("unchecked")
public void should_conserve_quoted_key_in_map() throws Exception {
Toml toml = new Toml().parse("[dog.\"tater.man\"] \n type = \"pug0\" \n[dog.tater] \n type = \"pug1\"\n[dog.tater.man] \n type = \"pug2\"");
Toml dogs = toml.getTable("dog");
Map<String, Map<String, Object>> map = dogs.to(Map.class);
assertEquals("pug0", map.get("\"tater.man\"").get("type"));
assertEquals("pug1", map.get("tater").get("type"));
assertEquals("pug2", ((Map<String, Object>) map.get("tater").get("man")).get("type"));
}
@Test
public void should_convert() throws Exception {
Quoted quoted = new Toml().parse("\"ʎǝʞ\" = \"value\" \n[map] \n \"ʎǝʞ\" = \"value\"").to(Quoted.class);
assertNull(quoted.ʎǝʞ);
assertEquals("value", quoted.map.get("\"ʎǝʞ\""));
}
private static class Quoted {
String ʎǝʞ;
Map<String, Object> map;
}
}