Delegates.mapVal and mapVar preserve type of the receiver to when calling default value lambda.

This commit is contained in:
Ilya Gorbunov
2015-11-18 04:20:27 +03:00
parent 0f70def3db
commit 9d24f1d1cf
2 changed files with 32 additions and 17 deletions
@@ -55,9 +55,9 @@ public object Delegates {
* @param map the map where the property values are stored. * @param map the map where the property values are stored.
* @param default the function returning the value of the property for a given object if it's missing from the given map. * @param default the function returning the value of the property for a given object if it's missing from the given map.
*/ */
public fun <T> mapVar(map: MutableMap<in String, Any?>, public fun <R, T> mapVar(map: MutableMap<in String, Any?>,
default: (thisRef: Any?, desc: String) -> T): ReadWriteProperty<Any?, T> { default: (thisRef: R, propertyName: String) -> T): ReadWriteProperty<R, T> {
return FixedMapVar<Any?, String, T>(map, propertyNameSelector, default) return FixedMapVar<R, String, T>(map, propertyNameSelector, default)
} }
/** /**
@@ -76,9 +76,9 @@ public object Delegates {
* @param map the map where the property values are stored. * @param map the map where the property values are stored.
* @param default the function returning the value of the property for a given object if it's missing from the given map. * @param default the function returning the value of the property for a given object if it's missing from the given map.
*/ */
public fun <T> mapVal(map: Map<in String, Any?>, public fun <R, T> mapVal(map: Map<in String, Any?>,
default: (thisRef: Any?, desc: String) -> T): ReadOnlyProperty<Any?, T> { default: (thisRef: R, propertyName: String) -> T): ReadOnlyProperty<R, T> {
return FixedMapVal<Any?, String, T>(map, propertyNameSelector, default) return FixedMapVal<R, String, T>(map, propertyNameSelector, default)
} }
} }
@@ -8,6 +8,7 @@ import kotlin.test.*
data class B(val a: Int) data class B(val a: Int)
class MapValWithDifferentTypesTest() { class MapValWithDifferentTypesTest() {
val map = hashMapOf("a" to "a", "b" to 1, "c" to B(1), "d" to null) val map = hashMapOf("a" to "a", "b" to 1, "c" to B(1), "d" to null)
val a by Delegates.mapVal<String>(map) val a by Delegates.mapVal<String>(map)
@@ -75,11 +76,13 @@ class MapValWithDefaultTest() {
val a: String by Delegates.mapVal(map, default = { ref, desc -> "aDefault" }) val a: String by Delegates.mapVal(map, default = { ref, desc -> "aDefault" })
val b: String by FixedMapVal(map, default = { ref: MapValWithDefaultTest, desc: String -> "bDefault" }, key = {"b"}) val b: String by FixedMapVal(map, default = { ref: MapValWithDefaultTest, desc: String -> "bDefault" }, key = {"b"})
val c: String by FixedMapVal(map, default = { ref: MapValWithDefaultTest, desc: String -> "cDefault" }, key = { desc -> desc.name }) val c: String by FixedMapVal(map, default = { ref: MapValWithDefaultTest, desc: String -> "cDefault" }, key = { desc -> desc.name })
val d: String by Delegates.mapVal(map, default = { ref, name -> ref.c })
@test fun doTest() { @test fun doTest() {
assertTrue(a == "aDefault", "fail at 'a'") assertEquals("aDefault", a, "fail at 'a'")
assertTrue(b == "bDefault", "fail at 'b'") assertEquals("bDefault", b, "fail at 'b'")
assertTrue(c == "cDefault", "fail at 'c'") assertEquals("cDefault", c, "fail at 'c'")
assertEquals(c, d, "'d' must have the default value equal to 'c'")
} }
} }
@@ -88,17 +91,20 @@ class MapVarWithDefaultTest() {
var a: String by Delegates.mapVar(map, default = {ref, desc -> "aDefault" }) var a: String by Delegates.mapVar(map, default = {ref, desc -> "aDefault" })
var b: String by FixedMapVar(map, default = {ref: Any?, desc: String -> "bDefault" }, key = {"b"}) var b: String by FixedMapVar(map, default = {ref: Any?, desc: String -> "bDefault" }, key = {"b"})
var c: String by FixedMapVar(map, default = {ref: Any?, desc: String -> "cDefault" }, key = { desc -> desc.name }) var c: String by FixedMapVar(map, default = {ref: Any?, desc: String -> "cDefault" }, key = { desc -> desc.name })
var d: String by Delegates.mapVar(map, default = { ref, name -> ref.c })
@test fun doTest() { @test fun doTest() {
assertTrue(a == "aDefault", "fail at 'a'") assertEquals("aDefault", a, "fail at 'a'")
assertTrue(b == "bDefault", "fail at 'b'") assertEquals("bDefault", b, "fail at 'b'")
assertTrue(c == "cDefault", "fail at 'c'") assertEquals("cDefault", c, "fail at 'c'")
assertEquals(c, d, "'d' must have the default value equal to 'c'")
a = "a" a = "a"
b = "b" b = "b"
c = "c" c = "c"
assertTrue(a == "a", "fail at 'a' after set") assertEquals("a", a, "fail at 'a' after set")
assertTrue(b == "b", "fail at 'b' after set") assertEquals("b", b, "fail at 'b' after set")
assertTrue(c == "c", "fail at 'c' after set") assertEquals("c", c, "fail at 'c' after set")
assertEquals(c, d, "'d' must still have the default value equal to 'c'")
} }
} }
@@ -126,6 +132,15 @@ class MapPropertyFunctionTest() {
} }
} }
@Suppress("ALWAYS_NULL")
private val topLevel: String by Delegates.mapVal(emptyMap(), default = { ref, name -> ref.toString() })
class MapTopLevelVarWithDefaultTest() {
@test fun doTest() {
assertEquals("null", topLevel)
}
}
val mapVal = object : MapVal<MapPropertyCustomTest, String, String>() { val mapVal = object : MapVal<MapPropertyCustomTest, String, String>() {
override fun map(ref: MapPropertyCustomTest) = ref.map override fun map(ref: MapPropertyCustomTest) = ref.map
override fun key(property: KProperty<*>) = "${property.name}Desc" override fun key(property: KProperty<*>) = "${property.name}Desc"
@@ -152,14 +167,14 @@ val mapValWithDefault = object : MapVal<MapPropertyCustomWithDefaultTest, String
override fun map(ref: MapPropertyCustomWithDefaultTest) = ref.map override fun map(ref: MapPropertyCustomWithDefaultTest) = ref.map
override fun key(property: KProperty<*>) = property.name override fun key(property: KProperty<*>) = property.name
override fun default(ref: MapPropertyCustomWithDefaultTest, key: KProperty<*>) = "default" override fun default(ref: MapPropertyCustomWithDefaultTest, property: KProperty<*>) = "default"
} }
val mapVarWithDefault = object : MapVar<MapPropertyCustomWithDefaultTest, String, String>() { val mapVarWithDefault = object : MapVar<MapPropertyCustomWithDefaultTest, String, String>() {
override fun map(ref: MapPropertyCustomWithDefaultTest) = ref.map override fun map(ref: MapPropertyCustomWithDefaultTest) = ref.map
override fun key(property: KProperty<*>) = property.name override fun key(property: KProperty<*>) = property.name
override fun default(ref: MapPropertyCustomWithDefaultTest, key: KProperty<*>) = "default" override fun default(ref: MapPropertyCustomWithDefaultTest, property: KProperty<*>) = "default"
} }
class MapPropertyCustomWithDefaultTest() { class MapPropertyCustomWithDefaultTest() {