Skip to content

Commit

Permalink
Merge pull request #1 from traversals/split-delegates
Browse files Browse the repository at this point in the history
Split delegates into required and optional
  • Loading branch information
mgouline authored Mar 24, 2017
2 parents 64da294 + bb909a1 commit 1cb6e25
Show file tree
Hide file tree
Showing 6 changed files with 44 additions and 21 deletions.
37 changes: 30 additions & 7 deletions kapsule-core/src/main/kotlin/space/traversal/kapsule/Delegate.kt
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,8 @@ import kotlin.reflect.KProperty
* @param <M> Module type that injects it.
* @param <T> Property value type.
* @param initializer Value initializer function.
* @param required True for required (non-null), otherwise optional (nullable).
*/
class Delegate<in M, T>(internal val initializer: M.() -> T, internal val required: Boolean = false) {
sealed class Delegate<in M, T>(internal val initializer: M.() -> T?) {

internal var value: T? = null

Expand All @@ -24,14 +23,38 @@ class Delegate<in M, T>(internal val initializer: M.() -> T, internal val requir
}

/**
* Delegate for value reads.
* Delegate for required (non-null) values.
*/
operator fun getValue(thisRef: Any?, property: KProperty<*>) = if (required) value!! else value
class Required<in M, T>(initializer: M.() -> T) : Delegate<M, T>(initializer) {

/**
* Delegate for value reads.
*/
operator fun getValue(thisRef: Any?, property: KProperty<*>) = value!!

/**
* Delegate for value writes.
*/
operator fun setValue(thisRef: Any?, property: KProperty<*>, t: T) {
value = t
}
}

/**
* Delegate for value writes.
* Delegate for optional (nullable) values.
*/
operator fun setValue(thisRef: Any?, property: KProperty<*>, t: T) {
value = t
class Optional<in M, T>(initializer: M.() -> T?) : Delegate<M, T>(initializer) {

/**
* Delegate for value reads.
*/
operator fun getValue(thisRef: Any?, property: KProperty<*>) = value

/**
* Delegate for value writes.
*/
operator fun setValue(thisRef: Any?, property: KProperty<*>, t: T?) {
value = t
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,14 @@ class Kapsule<M> {
*
* @param initializer Initializer function from the module context to value.
*/
fun <T> req(initializer: M.() -> T) = Delegate(initializer, true).apply { delegates += this }
fun <T> req(initializer: M.() -> T) = Delegate.Required(initializer).apply { delegates += this }

/**
* Creates and registers delegate for an optional (nullable) injectable property.
*
* @param initializer Initializer function from the module context to value.
*/
fun <T> opt(initializer: M.() -> T?) = Delegate(initializer, false).apply { delegates += this }
fun <T> opt(initializer: M.() -> T?) = Delegate.Optional(initializer).apply { delegates += this }

/**
* Shortcut for [req] by invoking the class like a function.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import kotlin.reflect.KProperty
class DelegateTestCase : TestCase() {

@Test fun testInitialize_required() {
val delegate = Delegate<RequiredModule, String>({ value }, true)
val delegate = Delegate.Required<RequiredModule, String> { value }
assertEquals(null, delegate.value)

listOf("one", "two").forEach { value ->
Expand All @@ -22,7 +22,7 @@ class DelegateTestCase : TestCase() {
}

@Test fun testInitialize_optional() {
val delegate = Delegate<OptionalModule, String?>({ value }, false)
val delegate = Delegate.Optional<OptionalModule, String?> { value }
assertEquals(null, delegate.value)

listOf(null, "three").forEach { value ->
Expand All @@ -33,7 +33,7 @@ class DelegateTestCase : TestCase() {
}

@Test fun testGetValue_required() {
val delegate = Delegate<RequiredModule, String>({ value }, true)
val delegate = Delegate.Required<RequiredModule, String> { value }
val prop = Mockito.mock(KProperty::class.java)

try {
Expand All @@ -49,7 +49,7 @@ class DelegateTestCase : TestCase() {
}

@Test fun testGetValue_optional() {
val delegate = Delegate<OptionalModule, String?>({ value }, false)
val delegate = Delegate.Optional<OptionalModule, String?> { value }
val prop = Mockito.mock(KProperty::class.java)

assertEquals(null, delegate.getValue(null, prop))
Expand All @@ -60,7 +60,7 @@ class DelegateTestCase : TestCase() {
}

@Test fun testSetValue_required() {
val delegate = Delegate<RequiredModule, String>({ value }, true)
val delegate = Delegate.Required<RequiredModule, String> { value }
val prop = Mockito.mock(KProperty::class.java)

listOf("test3", "test4").forEach { expected ->
Expand All @@ -70,7 +70,7 @@ class DelegateTestCase : TestCase() {
}

@Test fun testSetValue_optional() {
val delegate = Delegate<OptionalModule, String?>({ value }, false)
val delegate = Delegate.Optional<OptionalModule, String?> { value }
val prop = Mockito.mock(KProperty::class.java)

listOf("test3", null).forEach { expected ->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@ class KapsuleTestCase : TestCase() {

@Test fun testRequired() {
val kap = Kapsule<MultiModule>()
assertEquals(true, kap.req { reqInt }.required)
assertEquals(true, kap<Int> { reqInt }.required)
assertEquals(false, kap.opt<Int?> { reqInt }.required)
assertTrue(kap.req { reqInt } is Delegate.Required)
assertTrue(kap<Int> { reqInt } is Delegate.Required)
assertTrue(kap.opt<Int?> { reqInt } is Delegate.Optional)
}

@Test fun testDelegates() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ class Demo(context: Context) {

private val kap = Kapsule<DemoModule>()

val firstName by kap { firstName }
var firstName by kap { firstName }
val lastName by kap.opt { lastName }
val emails by kap { emails }

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ class DemoAppTestCase : TestCase() {
val demo = Demo(testContext)
assertEquals("Jane", demo.firstName)
assertEquals("Doe", demo.lastName)
assertTrue(demo.emails!!.contains("[email protected]"))
assertTrue(demo.emails!!.contains("[email protected]"))
assertTrue(demo.emails.contains("[email protected]"))
assertTrue(demo.emails.contains("[email protected]"))
}
}

0 comments on commit 1cb6e25

Please sign in to comment.