From b98bf4e8d8b0a66dd74882687b1e4b6106e92d75 Mon Sep 17 00:00:00 2001 From: Henning Post Date: Mon, 13 Jan 2020 11:53:40 -0800 Subject: [PATCH] Add mapOptionalOnce --- README.md | 14 +++++++++++++- build.gradle | 2 +- .../kotlin/cc/femto/rx/extensions/Mapping.kt | 14 ++++++++++++++ .../cc/femto/rx/extensions/MappingSpec.kt | 19 +++++++++++++++++++ 4 files changed, 47 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 6e668ec..acbab2c 100644 --- a/README.md +++ b/README.md @@ -78,6 +78,18 @@ state().mapOptional { bar } ``` +### Observable.mapOptionalOnce +Map to one nullable property of the state, wrap in `Optional`, and ensure +that only first value is observed + +```kotlin +state().mapOptionalOnce { bar } + .subscribe { println(it) } + +// --> None +``` + + ### Observable.mapOptionalDistinct Map to one nullable property of the state and wrap in `Optional` and ensure that subsequently emitted values are distinct @@ -131,7 +143,7 @@ state().mapSomeOnce { bar } ## Binaries ```gradle dependencies { - implementation "cc.femto:rx-mapping-extensions:0.3" + implementation "cc.femto:rx-mapping-extensions:0.4" } ``` diff --git a/build.gradle b/build.gradle index be2fef0..8668d40 100644 --- a/build.gradle +++ b/build.gradle @@ -12,7 +12,7 @@ plugins { } group 'com.github.hpost' -version '0.3' +version '0.4' repositories { mavenCentral() diff --git a/src/main/kotlin/cc/femto/rx/extensions/Mapping.kt b/src/main/kotlin/cc/femto/rx/extensions/Mapping.kt index d09bf9d..84ce7dd 100644 --- a/src/main/kotlin/cc/femto/rx/extensions/Mapping.kt +++ b/src/main/kotlin/cc/femto/rx/extensions/Mapping.kt @@ -44,6 +44,20 @@ inline fun Observable.mapOnce(crossinline mapper: T.() -> R): Ob inline fun Observable.mapOptional(crossinline mapper: T.() -> R?): Observable> = this.map { mapper(it).toOptional() } +/** + * Map the stream to the value returned from [mapper], which is wrapped in an [Optional], + * and then apply [Observable.take] with value `1` to ensure the stream will + * complete after emitting one value + * + * Usage: + * + * stream.mapOptionalOnce { foo } + * .subscribe { /* access at most one value wrapped in Optional */ } + * + */ +inline fun Observable.mapOptionalOnce(crossinline mapper: T.() -> R?): Observable> = + this.mapOptional(mapper).take(1) + /** * Applies [mapOptional] and then [Observable.distinctUntilChanged] to ensure * the stream won't emit if the value in [mapper] has not changed diff --git a/src/test/kotlin/cc/femto/rx/extensions/MappingSpec.kt b/src/test/kotlin/cc/femto/rx/extensions/MappingSpec.kt index a565a89..265f905 100644 --- a/src/test/kotlin/cc/femto/rx/extensions/MappingSpec.kt +++ b/src/test/kotlin/cc/femto/rx/extensions/MappingSpec.kt @@ -77,6 +77,25 @@ class MappingSpec : Spek({ } } + describe("mapOptionalOnce") { + lateinit var observer: TestObserver> + + beforeEachTest { + state = Observable.just( + State(bar = "initialized"), + State(bar = null), + State(bar = "changed") + ) + observer = state.mapOptionalOnce { bar }.test() + } + + it("maps to nullable property, wraps in `Optional`, and completes after one emission") { + observer.assertValues( + Some("initialized") + ) + } + } + describe("mapOptionalDistinct") { lateinit var observer: TestObserver>