add atPath() and atKey() to place a value inside a Config

Otherwise it's sort of clunky to do this because you have to
create a map then parseMap, or other roundabout approach.
This commit is contained in:
Havoc Pennington 2012-06-19 16:30:48 -04:00
parent e1d5bc7506
commit d15ade876a
5 changed files with 120 additions and 1 deletions

View File

@ -506,4 +506,25 @@ public interface Config extends ConfigMergeable {
* @return a copy of the config minus the specified path
*/
Config withoutPath(String path);
/**
* Places the config inside another {@code Config} at the given path.
*
* @param path
* path to store this config at.
* @return a {@code Config} instance containing this config at the given
* path.
*/
Config atPath(String path);
/**
* Places the config inside a {@code Config} at the given key. See also
* atPath().
*
* @param key
* key to store this config at.
* @return a {@code Config} instance containing this config at the given
* key.
*/
Config atKey(String key);
}

View File

@ -76,7 +76,7 @@ public interface ConfigValue extends ConfigMergeable {
* HOCON-specific features (such as comments), the rendering will be valid
* JSON. If you enable HOCON-only features such as comments, the rendering
* will not be valid JSON.
*
*
* @param options
* the rendering options
* @return the rendered value
@ -85,4 +85,25 @@ public interface ConfigValue extends ConfigMergeable {
@Override
ConfigValue withFallback(ConfigMergeable other);
/**
* Places the value inside a {@code Config} at the given path. See also
* atKey().
*
* @param path
* path to store this value at.
* @return a {@code Config} instance containing this value at the given
* path.
*/
Config atPath(String path);
/**
* Places the value inside a {@code Config} at the given key. See also
* atPath().
*
* @param key
* key to store this value at.
* @return a {@code Config} instance containing this value at the given key.
*/
Config atKey(String key);
}

View File

@ -7,7 +7,9 @@ import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import com.typesafe.config.Config;
import com.typesafe.config.ConfigException;
import com.typesafe.config.ConfigMergeable;
import com.typesafe.config.ConfigOrigin;
@ -327,4 +329,28 @@ abstract class AbstractConfigValue implements ConfigValue, MergeableValue {
String transformToString() {
return null;
}
SimpleConfig atKey(ConfigOrigin origin, String key) {
Map<String, AbstractConfigValue> m = Collections.singletonMap(key, this);
return (new SimpleConfigObject(origin, m)).toConfig();
}
@Override
public SimpleConfig atKey(String key) {
return atKey(SimpleConfigOrigin.newSimple("atKey(" + key + ")"), key);
}
@Override
public Config atPath(String pathExpression) {
SimpleConfigOrigin origin = SimpleConfigOrigin.newSimple("atPath(" + pathExpression + ")");
Path path = Path.newPath(pathExpression);
Path parent = path.parent();
SimpleConfig result = atKey(origin, path.last());
while (parent != null) {
String key = parent.last();
result = result.atKey(origin, key);
parent = parent.parent();
}
return result;
}
}

View File

@ -846,6 +846,20 @@ final class SimpleConfig implements Config, MergeableValue, Serializable {
return new SimpleConfig(root().withoutPath(path));
}
SimpleConfig atKey(ConfigOrigin origin, String key) {
return root().atKey(origin, key);
}
@Override
public SimpleConfig atKey(String key) {
return root().atKey(key);
}
@Override
public Config atPath(String path) {
return root().atPath(path);
}
// serialization all goes through SerializedConfigValue
private Object writeReplace() throws ObjectStreamException {
return new SerializedConfigValue(this);

View File

@ -14,6 +14,7 @@ import com.typesafe.config.ConfigList
import com.typesafe.config.ConfigException
import com.typesafe.config.ConfigValueType
import com.typesafe.config.ConfigOrigin
import com.typesafe.config.ConfigValueFactory
class ConfigValueTest extends TestUtils {
@ -751,6 +752,42 @@ class ConfigValueTest extends TestUtils {
assertEquals(ResolveStatus.RESOLVED, obj.withoutKey("a").withoutKey("b").resolveStatus())
}
@Test
def atPathWorksOneElement() {
val v = ConfigValueFactory.fromAnyRef(42)
val config = v.atPath("a")
assertEquals(parseConfig("a=42"), config)
assertTrue(config.getValue("a") eq v)
assertTrue(config.origin.description.contains("atPath"))
}
@Test
def atPathWorksTwoElements() {
val v = ConfigValueFactory.fromAnyRef(42)
val config = v.atPath("a.b")
assertEquals(parseConfig("a.b=42"), config)
assertTrue(config.getValue("a.b") eq v)
assertTrue(config.origin.description.contains("atPath"))
}
@Test
def atPathWorksFourElements() {
val v = ConfigValueFactory.fromAnyRef(42)
val config = v.atPath("a.b.c.d")
assertEquals(parseConfig("a.b.c.d=42"), config)
assertTrue(config.getValue("a.b.c.d") eq v)
assertTrue(config.origin.description.contains("atPath"))
}
@Test
def atKeyWorks() {
val v = ConfigValueFactory.fromAnyRef(42)
val config = v.atKey("a")
assertEquals(parseConfig("a=42"), config)
assertTrue(config.getValue("a") eq v)
assertTrue(config.origin.description.contains("atKey"))
}
@Test
def configOriginsInSerialization() {
import scala.collection.JavaConverters._