diff --git a/README.md b/README.md index fdb2599..afd99a2 100644 --- a/README.md +++ b/README.md @@ -62,8 +62,10 @@ interface CommentRepository { Redux with CoRed implementation (the setup part should be under 35~ lines) ```kotlin -class CommentsState(val comments: List? = null) : State +// State definition for you application +class CommentsState(val comments: List? = null) +// Actions object Load class SetComments(val comments: List?) @@ -73,12 +75,12 @@ val store = Store( scope = viewScope, initialState = CommentsState(), reducers = mapOf( - "SetComments" to Reducer { currentState: CommentsState, action: SetComments -> // This reducer is connected with SetComments action by using "SetComments" string as a Key + SetComments::class to Reducer { currentState: CommentsState, action: SetComments -> // This reducer is connected with SetComments action by using SetComments::class as a Key currentState.copy(comments = action.comments) } ), middlewares = mapOf( - "Load" to Middleware { order: Order, store: Store, state: CommentsState, action: Load -> + Load::class to Middleware { order: Order, store: Store, state: CommentsState, action: Load -> // This middleware is connected with Load action by using Load::class as a Key if (order == Order.AfterReduced) { scope.launch { val result = repository.getComments() diff --git a/cored/src/commonMain/kotlin/com/github/kittinunf/cored/StoreAdapter.kt b/cored/src/commonMain/kotlin/com/github/kittinunf/cored/StoreAdapter.kt index 75df8b3..8485d9a 100644 --- a/cored/src/commonMain/kotlin/com/github/kittinunf/cored/StoreAdapter.kt +++ b/cored/src/commonMain/kotlin/com/github/kittinunf/cored/StoreAdapter.kt @@ -2,28 +2,19 @@ package com.github.kittinunf.cored import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.GlobalScope +import kotlin.reflect.KClass -interface Identifiable { - - val identifier: String -} - -typealias ReducerType = Pair> -typealias EffectType = Pair> - -private object SetStateActionIdentifiable : Identifiable { - // prepend with 2 underscores so it won't collide with the client identifier string - override val identifier: String = "__SetState" -} +typealias ReducerType = Pair, Reducer> +typealias EffectType = Pair, Middleware> @Suppress("FunctionName") -private fun SetStateReducerType(): ReducerType = SetStateActionIdentifiable.identifier to SetStateReducer() +private fun SetStateReducerType(): ReducerType = SetStateAction::class to SetStateReducer() @Suppress("FunctionName") fun Store( scope: CoroutineScope = GlobalScope, initialState: S, - reducers: Map> + reducers: Map, Reducer> ): StoreType { return StoreAdapter(Store(scope, initialState, StoreAdapterEngine((reducers + SetStateReducerType()).toMutableMap(), mutableMapOf()))) } @@ -32,21 +23,19 @@ fun Store( fun Store( scope: CoroutineScope = GlobalScope, initialState: S, - reducers: Map>, - middlewares: Map> + reducers: Map, Reducer>, + middlewares: Map, Middleware> ): StoreType { return StoreAdapter(Store(scope, initialState, StoreAdapterEngine((reducers + SetStateReducerType()).toMutableMap(), middlewares.toMutableMap()))) } private class StoreAdapterEngine( - val reducerMap: MutableMap>, - val middlewareMap: MutableMap> + val reducerMap: MutableMap, Reducer>, + val middlewareMap: MutableMap, Middleware> ) : StateScannerEngine { override suspend fun scan(storeType: StoreType, state: S, action: Any): S { - // check whether it is identifiable or it is a SetStateAction - val id = if (action is SetStateAction<*>) SetStateActionIdentifiable else action as? Identifiable - val identifier = id?.identifier ?: action::class.simpleName!! + val identifier = action::class val middleware = middlewareMap[identifier] val reducer = reducerMap.getValue(identifier) diff --git a/cored/src/commonTest/kotlin/com/github/kittinunf/cored/ReduxTest.kt b/cored/src/commonTest/kotlin/com/github/kittinunf/cored/ReduxTest.kt index 0015b82..bc3f41c 100644 --- a/cored/src/commonTest/kotlin/com/github/kittinunf/cored/ReduxTest.kt +++ b/cored/src/commonTest/kotlin/com/github/kittinunf/cored/ReduxTest.kt @@ -13,20 +13,13 @@ import kotlin.test.assertEquals import kotlin.test.assertTrue import kotlin.test.fail +// State definition data class CounterState(val counter: Int = 0) -typealias CounterAction = Any - -class Increment(val by: Int) : CounterAction(), Identifiable { - override val identifier: String = "inc" -} - -class Decrement(val by: Int) : CounterAction(), Identifiable { - override val identifier: String = "dec" -} - -// no need to implement Identifier if you don't want to customize it, by default it is class::simpleName -class Set(val value: Int) : CounterAction() +// Action definition +class Increment(val by: Int) +class Decrement(val by: Int) +class Set(val value: Int) typealias CounterStore = StoreType @@ -291,8 +284,8 @@ class ReduxTest { assertEquals(310, store.currentState.counter) } - class Multiply(val by: Int) : CounterAction() - class Divide(val by: Int) : CounterAction() + class Multiply(val by: Int) + class Divide(val by: Int) @Test fun `should ignore action that is not unknown with the current known action reducer`() { diff --git a/cored/src/commonTest/kotlin/com/github/kittinunf/cored/StoreAdapterTest.kt b/cored/src/commonTest/kotlin/com/github/kittinunf/cored/StoreAdapterTest.kt index f7754fc..6b192a7 100644 --- a/cored/src/commonTest/kotlin/com/github/kittinunf/cored/StoreAdapterTest.kt +++ b/cored/src/commonTest/kotlin/com/github/kittinunf/cored/StoreAdapterTest.kt @@ -18,10 +18,10 @@ class StoreAdapterTest { private val testScope = CoroutineScope(Dispatchers.Unconfined) private val reducers = mapOf( - "inc" to Reducer { currentState: CounterState, action: Increment -> + Increment::class to Reducer { currentState: CounterState, action: Increment -> currentState.copy(counter = currentState.counter + action.by) }, - "dec" to Reducer { currentState: CounterState, action: Decrement -> + Decrement::class to Reducer { currentState: CounterState, action: Decrement -> currentState.copy(counter = currentState.counter - action.by) } ) @@ -152,17 +152,15 @@ class StoreAdapterTest { val sideEffectData = SideEffectData(100) - val middlewares = mapOf( - "inc" to Middleware { order: Order, store: CounterStore, state: CounterState, action: Increment -> + val localStore = Store(testScope, CounterState(), reducers, mapOf( + Increment::class to Middleware { order: Order, store: CounterStore, state: CounterState, action: Increment -> if (order == Order.BeforeReduce) { assertEquals(0, state.counter) } else { sideEffectData.value = sideEffectData.value + state.counter } } - ) - - val localStore = Store(testScope, CounterState(), reducers, middlewares) + )) runBlockingTest { localStore.states @@ -184,17 +182,15 @@ class StoreAdapterTest { @Test fun `should invoke middleware in the correct order`() { - val middlewares = mapOf( - "inc" to Middleware { order: Order, store: CounterStore, state: CounterState, action: Increment -> + val localStore = Store(testScope, CounterState(), reducers, mapOf( + Increment::class to Middleware { order: Order, store: CounterStore, state: CounterState, action: Increment -> if (order == Order.BeforeReduce) { assertEquals(0, state.counter) } else { assertEquals(100, state.counter) } } - ) - - val localStore = Store(testScope, CounterState(), reducers, middlewares) + )) runBlockingTest { localStore.states @@ -208,13 +204,11 @@ class StoreAdapterTest { @Test fun `should invoke even we don't provide the customization on the identifier with the qualified name`() { - val reducers = mapOf( - "Set" to Reducer { currentState: CounterState, action: Set -> + val localStore = Store(testScope, CounterState(), mapOf( + Set::class to Reducer { currentState: CounterState, action: Set -> currentState.copy(counter = action.value) } - ) - - val localStore = Store(testScope, CounterState(), reducers) + )) runBlockingTest { localStore.states @@ -230,8 +224,8 @@ class StoreAdapterTest { @Test fun `should be able to dispatch action from the middleware`() { - val middlewares = mapOf( - "inc" to Middleware { order: Order, store: CounterStore, state: CounterState, action: Increment -> + val localStore = Store(testScope, CounterState(), reducers, mapOf( + Increment::class to Middleware { order: Order, store: CounterStore, state: CounterState, action: Increment -> if (order == Order.AfterReduced) { if (state.counter == 100) { // dispatch another action from middleware @@ -243,9 +237,7 @@ class StoreAdapterTest { } } } - ) - - val localStore = Store(testScope, CounterState(), reducers, middlewares) + )) runBlockingTest { localStore.states diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index e708b1c..7454180 100644 Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index f371643..05679dc 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.0-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.1.1-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew index 4f906e0..744e882 100755 --- a/gradlew +++ b/gradlew @@ -72,7 +72,7 @@ case "`uname`" in Darwin* ) darwin=true ;; - MINGW* ) + MSYS* | MINGW* ) msys=true ;; NONSTOP* )