mirror of
https://github.com/lightbend/config.git
synced 2025-03-23 07:40:25 +08:00
Implement include keyword
This commit is contained in:
parent
5a51d590af
commit
145cb40ec2
@ -326,6 +326,51 @@ final class Parser {
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isIncludeKeyword(Token t) {
|
||||
return Tokens.isUnquotedText(t)
|
||||
&& Tokens.getUnquotedText(t).equals("include");
|
||||
}
|
||||
|
||||
private static boolean isUnquotedWhitespace(Token t) {
|
||||
if (!Tokens.isUnquotedText(t))
|
||||
return false;
|
||||
|
||||
String s = Tokens.getUnquotedText(t);
|
||||
|
||||
for (int i = 0; i < s.length(); ++i) {
|
||||
char c = s.charAt(i);
|
||||
if (!Character.isWhitespace(c))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private void parseInclude(Map<String, AbstractConfigValue> values) {
|
||||
Token t = nextTokenIgnoringNewline();
|
||||
while (isUnquotedWhitespace(t)) {
|
||||
t = nextTokenIgnoringNewline();
|
||||
}
|
||||
|
||||
if (Tokens.isValueWithType(t, ConfigValueType.STRING)) {
|
||||
String name = (String) Tokens.getValue(t).unwrapped();
|
||||
AbstractConfigObject obj = includer.include(name);
|
||||
|
||||
for (String key : obj.keySet()) {
|
||||
AbstractConfigValue v = obj.get(key);
|
||||
AbstractConfigValue existing = values.get(key);
|
||||
if (existing != null) {
|
||||
values.put(key, v.withFallback(existing));
|
||||
} else {
|
||||
values.put(key, v);
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
throw parseError("include keyword is not followed by a quoted string, but by: "
|
||||
+ t);
|
||||
}
|
||||
}
|
||||
|
||||
private AbstractConfigObject parseObject() {
|
||||
// invoked just after the OPEN_CURLY
|
||||
Map<String, AbstractConfigValue> values = new HashMap<String, AbstractConfigValue>();
|
||||
@ -338,6 +383,10 @@ final class Parser {
|
||||
throw parseError("expecting a field name after comma, got a close brace }");
|
||||
}
|
||||
break;
|
||||
} else if (flavor != SyntaxFlavor.JSON && isIncludeKeyword(t)) {
|
||||
parseInclude(values);
|
||||
|
||||
afterComma = false;
|
||||
} else {
|
||||
Path path = parseKey(t);
|
||||
Token afterKey = nextTokenIgnoringNewline();
|
||||
|
17
src/test/resources/test03.conf
Normal file
17
src/test/resources/test03.conf
Normal file
@ -0,0 +1,17 @@
|
||||
{
|
||||
"test01" : {
|
||||
"ints" : 12,
|
||||
include "test01",
|
||||
"booleans" : 42
|
||||
},
|
||||
|
||||
"test02" : {
|
||||
include
|
||||
|
||||
"test02.conf"
|
||||
},
|
||||
|
||||
"equiv01" : {
|
||||
include "equiv01/original.json"
|
||||
}
|
||||
}
|
@ -634,4 +634,22 @@ class ConfigTest extends TestUtils {
|
||||
assertEquals(57, conf.getInt(""" "a"."b"."c" """))
|
||||
assertEquals(103, conf.getInt(""" "a.b.c" """))
|
||||
}
|
||||
|
||||
@Test
|
||||
def test03Includes() {
|
||||
val conf = Config.load("test03")
|
||||
|
||||
// include should have overridden the "ints" value in test03
|
||||
assertEquals(42, conf.getInt("test01.ints.fortyTwo"))
|
||||
// include should have been overridden by 42
|
||||
assertEquals(42, conf.getInt("test01.booleans"));
|
||||
assertEquals(42, conf.getInt("test01.booleans"));
|
||||
// include should have gotten .properties and .json also
|
||||
assertEquals("abc", conf.getString("test01.fromProps.abc"))
|
||||
assertEquals("A", conf.getString("test01.fromJsonA"))
|
||||
// test02 was included
|
||||
assertEquals(57, conf.getInt("test02.a.b.c"))
|
||||
// equiv01/original.json was included (it has a slash in the name)
|
||||
assertEquals("a", conf.getString("equiv01.strings.a"))
|
||||
}
|
||||
}
|
||||
|
@ -134,6 +134,9 @@ abstract trait TestUtils {
|
||||
"""{ "a" : ${a} }""", // simple cycle
|
||||
"""[ { "a" : 2, "b" : ${${a}} } ]""", // nested substitution
|
||||
"[ = ]", // = is not a valid token
|
||||
"{ include \"bar\" : 10 }", // include with a value after it
|
||||
"{ include foo }", // include with unquoted string
|
||||
"{ include : { \"a\" : 1 } }", // include used as unquoted key
|
||||
"") // empty document again, just for clean formatting of this list ;-)
|
||||
|
||||
// We'll automatically try each of these with whitespace modifications
|
||||
@ -178,6 +181,11 @@ abstract trait TestUtils {
|
||||
"[ trux ]",
|
||||
"[ truex ]",
|
||||
"[ 10x ]", // number token with trailing junk
|
||||
"{ include \"foo\" }", // valid include
|
||||
"{ include\n\"foo\" }", // include with just a newline separating from string
|
||||
"{ include\"foo\" }", // include with no whitespace after it
|
||||
"[ include ]", // include can be a string value in an array
|
||||
"{ foo : include }", // include can be a field value also
|
||||
"[ ${foo} ]",
|
||||
"[ ${\"foo\"} ]",
|
||||
"[ ${foo.bar} ]",
|
||||
|
Loading…
Reference in New Issue
Block a user