do a better job with origin when there's an empty config. add Config.empty().

This commit is contained in:
Havoc Pennington 2011-11-14 10:26:53 -05:00
parent 54cd4ec3dd
commit 9b3efbd2d0
5 changed files with 69 additions and 8 deletions

View File

@ -69,6 +69,10 @@ public final class Config {
return ConfigImpl.emptyRoot(rootPath); return ConfigImpl.emptyRoot(rootPath);
} }
public static ConfigObject empty() {
return ConfigImpl.empty();
}
public static ConfigRoot systemPropertiesRoot(String rootPath) { public static ConfigRoot systemPropertiesRoot(String rootPath) {
return ConfigImpl.systemPropertiesRoot(rootPath); return ConfigImpl.systemPropertiesRoot(rootPath);
} }

View File

@ -233,18 +233,39 @@ abstract class AbstractConfigObject extends AbstractConfigValue implements
if (stack.isEmpty()) if (stack.isEmpty())
throw new ConfigException.BugOrBroken( throw new ConfigException.BugOrBroken(
"can't merge origins on empty list"); "can't merge origins on empty list");
final String prefix = "merge of ";
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
String prefix = "merge of "; ConfigOrigin firstOrigin = null;
sb.append(prefix); int numMerged = 0;
for (AbstractConfigValue v : stack) { for (AbstractConfigValue v : stack) {
if (firstOrigin == null)
firstOrigin = v.origin();
String desc = v.origin().description(); String desc = v.origin().description();
if (desc.startsWith(prefix)) if (desc.startsWith(prefix))
desc = desc.substring(prefix.length()); desc = desc.substring(prefix.length());
sb.append(desc);
sb.append(","); if (v instanceof ConfigObject && ((ConfigObject) v).isEmpty()) {
// don't include empty files or the .empty()
// config in the description, since they are
// likely to be "implementation details"
} else {
sb.append(desc);
sb.append(",");
numMerged += 1;
}
}
if (numMerged > 0) {
sb.setLength(sb.length() - 1); // chop comma
if (numMerged > 1) {
return new SimpleConfigOrigin(prefix + sb.toString());
} else {
return new SimpleConfigOrigin(sb.toString());
}
} else {
// the configs were all empty.
return firstOrigin;
} }
sb.setLength(sb.length() - 1); // chop comma
return new SimpleConfigOrigin(sb.toString());
} }
static ConfigOrigin mergeOrigins(AbstractConfigObject... stack) { static ConfigOrigin mergeOrigins(AbstractConfigObject... stack) {

View File

@ -160,7 +160,13 @@ public class ConfigImpl {
/** For use ONLY by library internals, DO NOT TOUCH not guaranteed ABI */ /** For use ONLY by library internals, DO NOT TOUCH not guaranteed ABI */
public static ConfigRoot emptyRoot(String rootPath) { public static ConfigRoot emptyRoot(String rootPath) {
return SimpleConfigObject.empty().asRoot(Parser.parsePath(rootPath)); return SimpleConfigObject.empty(new SimpleConfigOrigin(rootPath))
.asRoot(
Parser.parsePath(rootPath));
}
public static ConfigObject empty() {
return SimpleConfigObject.empty();
} }
/** For use ONLY by library internals, DO NOT TOUCH not guaranteed ABI */ /** For use ONLY by library internals, DO NOT TOUCH not guaranteed ABI */

View File

@ -113,8 +113,10 @@ final class SimpleConfigObject extends AbstractConfigObject {
return new HashSet<ConfigValue>(value.values()); return new HashSet<ConfigValue>(value.values());
} }
final static String EMPTY_NAME = "empty config";
final static SimpleConfigObject empty() { final static SimpleConfigObject empty() {
return new SimpleConfigObject(new SimpleConfigOrigin("empty config"), return new SimpleConfigObject(new SimpleConfigOrigin(EMPTY_NAME),
Collections.<String, AbstractConfigValue> emptyMap()); Collections.<String, AbstractConfigValue> emptyMap());
} }

View File

@ -9,6 +9,7 @@ import com.typesafe.config.ConfigObject
import com.typesafe.config.ConfigList import com.typesafe.config.ConfigList
import com.typesafe.config.ConfigException import com.typesafe.config.ConfigException
import com.typesafe.config.ConfigValueType import com.typesafe.config.ConfigValueType
import com.typesafe.config.ConfigOrigin
class ConfigValueTest extends TestUtils { class ConfigValueTest extends TestUtils {
@ -330,4 +331,31 @@ class ConfigValueTest extends TestUtils {
assertEquals(Seq(a, b, c, d) map { "xx " + _ + " yy" }, assertEquals(Seq(a, b, c, d) map { "xx " + _ + " yy" },
Seq("a", "b", "c", "d") map { obj2.getString(_) }) Seq("a", "b", "c", "d") map { obj2.getString(_) })
} }
@Test
def mergeOriginsWorks() {
def o(desc: String, empty: Boolean) = {
val values = new java.util.HashMap[String, AbstractConfigValue]()
if (!empty)
values.put("hello", intValue(37))
new SimpleConfigObject(new SimpleConfigOrigin(desc), values);
}
def m(values: AbstractConfigObject*) = {
AbstractConfigObject.mergeOrigins(values: _*).description()
}
// simplest case
assertEquals("merge of a,b", m(o("a", false), o("b", false)))
// combine duplicate "merge of"
assertEquals("merge of a,x,y", m(o("a", false), o("merge of x,y", false)))
assertEquals("merge of a,b,x,y", m(o("merge of a,b", false), o("merge of x,y", false)))
// ignore empty objects
assertEquals("a", m(o("foo", true), o("a", false)))
// unless they are all empty, pick the first one
assertEquals("foo", m(o("foo", true), o("a", true)))
// merge just one
assertEquals("foo", m(o("foo", false)))
// merge three
assertEquals("merge of a,b,c", m(o("a", false), o("b", false), o("c", false)))
}
} }