diff --git a/README.md b/README.md index 06454cf..d62b0eb 100644 --- a/README.md +++ b/README.md @@ -30,16 +30,34 @@ val v = when (optional) { is Some -> optional.value // Smart Casts Optional to Some and allows you access its value. is None -> "fallback" } + +// Filter only Some values emitted by RxJava2 Observable. +val values: Observable = Observable + .just(Some("a"), None, Some("b")) + .filterSome() + +// Filter only None values emitted by RxJava2 Observable. +val nones: Observable = Observable + .just(Some("a"), None, Some("b")) + .filterNone() ``` ### Download Koptional is [available on jcenter](https://jcenter.bintray.com/com/gojuno/koptional). +Optional type: + ```groovy compile 'com.gojuno.koptional:koptional:put-some-version' ``` +[RxJava 2][rxjava2] extensions: + +```groovy +compile 'com.gojuno.koptional:koptional-rxjava2-extensions:put-some-version' +``` + All the releases and changelogs can be found on [Releases Page](https://github.com/gojuno/koptional/releases). ### How to build @@ -67,3 +85,5 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ``` + +[rxjava2]: https://github.com/ReactiveX/RxJava/ diff --git a/build.gradle b/build.gradle index 2734601..f1b0ec1 100644 --- a/build.gradle +++ b/build.gradle @@ -24,35 +24,3 @@ allprojects { apply plugin: 'com.github.ben-manes.versions' } - -def gitTag() { - def tag = 'git tag --list --points-at HEAD'.execute((List) null, rootProject.projectDir).text.trim() - - if (tag.split(System.lineSeparator()).length > 1) { - throw new IllegalStateException("gitTag is accessed but commit has multiple tags: $tag") - } - - return tag -} - -def projectVersion() { - def tag = gitTag() - - if (tag.startsWith('v')) { - return tag.substring(1) - } else if (tag.isEmpty()) { - return "development" - } - - return tag -} - -def validateTagAndVersion() { - if (gitTag().isEmpty()) { - throw new IllegalStateException('Publishing is not allowed because current commit has no tag') - } - - if (projectVersion().isEmpty()) { - throw new IllegalStateException('Publishing is not allowed because current projectVersion is empty') - } -} diff --git a/dependencies.gradle b/dependencies.gradle index 7fa0511..6c6191a 100644 --- a/dependencies.gradle +++ b/dependencies.gradle @@ -1,19 +1,25 @@ ext.versions = [ - kotlin : '1.1.1', + kotlin : '1.1.1', + rxJava2 : '2.1.0', - junit : '4.12', - junitPlatform : '1.0.0-M4', - spek : '1.1.2', - assertJ : '3.5.2', + junit : '4.12', + junitPlatform: '1.0.0-M4', + spek : '1.1.2', + assertJ : '3.5.2', ] ext.libraries = [ - kotlinStd : "org.jetbrains.kotlin:kotlin-stdlib:$versions.kotlin", - kotlinRuntime : "org.jetbrains.kotlin:kotlin-runtime:$versions.kotlin", - kotlinReflect : "org.jetbrains.kotlin:kotlin-reflect:$versions.kotlin", + koptional : project(':koptional'), + koptionalRxJava2Extensions: project(':koptional-rxjava2-extensions'), - junit : "junit:junit:$versions.junit", - spek : "org.jetbrains.spek:spek-api:$versions.spek", - spekJunitPlatformEngine: "org.jetbrains.spek:spek-junit-platform-engine:$versions.spek", - assertJ : "org.assertj:assertj-core:$versions.assertJ", + kotlinStd : "org.jetbrains.kotlin:kotlin-stdlib:$versions.kotlin", + kotlinRuntime : "org.jetbrains.kotlin:kotlin-runtime:$versions.kotlin", + kotlinReflect : "org.jetbrains.kotlin:kotlin-reflect:$versions.kotlin", + rxJava2 : "io.reactivex.rxjava2:rxjava:$versions.rxJava2", + + + junit : "junit:junit:$versions.junit", + spek : "org.jetbrains.spek:spek-api:$versions.spek", + spekJunitPlatformEngine : "org.jetbrains.spek:spek-junit-platform-engine:$versions.spek", + assertJ : "org.assertj:assertj-core:$versions.assertJ", ] diff --git a/gradle/publishing.gradle b/gradle/publishing.gradle new file mode 100644 index 0000000..f907626 --- /dev/null +++ b/gradle/publishing.gradle @@ -0,0 +1,119 @@ +apply plugin: 'maven' +apply plugin: 'maven-publish' +apply plugin: 'com.jfrog.bintray' + +def gitTag() { + def tag = 'git tag --list --points-at HEAD'.execute((List) null, rootProject.projectDir).text.trim() + + if (tag.split(System.lineSeparator()).length > 1) { + throw new IllegalStateException("gitTag is accessed but commit has multiple tags: $tag") + } + + return tag +} + +def projectVersion() { + def tag = gitTag() + + if (tag.startsWith('v')) { + return tag.substring(1) + } else if (tag.isEmpty()) { + return "development" + } + + return tag +} + +def validateTagAndVersion() { + if (gitTag().isEmpty()) { + throw new IllegalStateException('Publishing is not allowed because current commit has no tag') + } + + if (projectVersion().isEmpty()) { + throw new IllegalStateException('Publishing is not allowed because current projectVersion is empty') + } +} + +def pomConfig = { + licenses { + license { + name 'The Apache Software License, Version 2.0' + url 'http://www.apache.org/licenses/LICENSE-2.0.txt' + distribution 'repo' + } + } + developers { + developer { + id 'gojuno' + name 'Juno Inc.' + email 'opensource@gojuno.com' + } + } +} + + +task sourcesJar(type: Jar, dependsOn: classes) { + classifier = 'sources' + from sourceSets.main.allSource +} + +task javadocJar(type: Jar, dependsOn: javadoc) { + classifier = 'javadoc' + from javadoc.destinationDir +} + +task validatePublishing { + doLast { + validateTagAndVersion() + } +} + +bintrayUpload.dependsOn validatePublishing + +publishing { + publications { + KoptionalPublication(MavenPublication) { + from components.java + + artifact sourcesJar + artifact javadocJar + + groupId 'com.gojuno.koptional' + artifactId project.name + version projectVersion() + + pom.withXml { + def root = asNode() + root.appendNode('description', project.description) + root.appendNode('name', project.name) + root.appendNode('url', 'https://github.com/gojuno/koptional') + root.children().last() + pomConfig + } + } + } +} + +bintray { + user = System.getenv('BINTRAY_USER') + key = System.getenv('BINTRAY_API_KEY') + publish = true + + pkg { + repo = 'maven' + name = 'koptional' + licenses = ['Apache-2.0'] + vcsUrl = 'https://github.com/gojuno/koptional.git' + issueTrackerUrl = 'https://github.com/gojuno/koptional/issues' + publications = ['KoptionalPublication'] + + version { + name = projectVersion() + vcsTag = gitTag() + + gpg { + sign = true + passphrase = System.getenv('BINTRAY_GPG_PASSPHRASE') + } + } + } +} diff --git a/koptional-rxjava2-extensions/build.gradle b/koptional-rxjava2-extensions/build.gradle new file mode 100644 index 0000000..da60d50 --- /dev/null +++ b/koptional-rxjava2-extensions/build.gradle @@ -0,0 +1,24 @@ +apply plugin: 'kotlin' +apply plugin: 'org.junit.platform.gradle.plugin' +apply from: '../gradle/publishing.gradle' + +dependencies { + compile libraries.koptional + compile libraries.rxJava2 +} + +dependencies { + testCompile libraries.spek + testCompile libraries.spekJunitPlatformEngine + testCompile libraries.assertJ +} + +junitPlatform { + platformVersion = versions.junitPlatform + + filters { + engines { + include 'spek' + } + } +} diff --git a/koptional-rxjava2-extensions/gradle.properties b/koptional-rxjava2-extensions/gradle.properties new file mode 100644 index 0000000..872d82f --- /dev/null +++ b/koptional-rxjava2-extensions/gradle.properties @@ -0,0 +1 @@ +description=Extensions to work with Optional in RxJava2 streams. diff --git a/koptional-rxjava2-extensions/src/main/kotlin/com/gojuno/koptional/rxjava2/rxjava2.kt b/koptional-rxjava2-extensions/src/main/kotlin/com/gojuno/koptional/rxjava2/rxjava2.kt new file mode 100644 index 0000000..8eb7c4d --- /dev/null +++ b/koptional-rxjava2-extensions/src/main/kotlin/com/gojuno/koptional/rxjava2/rxjava2.kt @@ -0,0 +1,36 @@ +package com.gojuno.koptional.rxjava2 + +import com.gojuno.koptional.None +import com.gojuno.koptional.Optional +import com.gojuno.koptional.Some +import io.reactivex.Observable + +private inline fun Observable<*>.ofType(): Observable = ofType(R::class.java) + +/** + * Filters items emitted by an ObservableSource by only emitting those that are `Some`. + *

+ * + *

+ *
Scheduler:
+ *
{@code filter} does not operate by default on a particular {@link Scheduler}.
+ *
+ * + * @return an Observable that emits `Some.value` of those items emitted by the source ObservableSource that are `Some`. + * @see ReactiveX operators documentation: Filter + */ +fun Observable>.filterSome(): Observable = ofType>().map { it.value } + +/** + * Filters items emitted by an ObservableSource by only emitting those that are `None`. + *

+ * + *

+ *
Scheduler:
+ *
{@code filter} does not operate by default on a particular {@link Scheduler}.
+ *
+ * + * @return an Observable that emits `Unit` for each item emitted by the source ObservableSource that is `None`. + * @see ReactiveX operators documentation: Filter + */ +fun Observable>.filterNone(): Observable = ofType().map { Unit } diff --git a/koptional-rxjava2-extensions/src/test/kotlin/com/gojuno/koptional/rxjava2/RxJava2ExtensionsSpec.kt b/koptional-rxjava2-extensions/src/test/kotlin/com/gojuno/koptional/rxjava2/RxJava2ExtensionsSpec.kt new file mode 100644 index 0000000..706d1c1 --- /dev/null +++ b/koptional-rxjava2-extensions/src/test/kotlin/com/gojuno/koptional/rxjava2/RxJava2ExtensionsSpec.kt @@ -0,0 +1,62 @@ +package com.gojuno.koptional.rxjava2 + +import com.gojuno.koptional.None +import com.gojuno.koptional.Some +import io.reactivex.Observable +import io.reactivex.observers.TestObserver +import org.jetbrains.spek.api.Spek +import org.jetbrains.spek.api.dsl.context +import org.jetbrains.spek.api.dsl.it + +class RxJava2ExtensionsSpec : Spek({ + + val stream by memoized { + Observable.just(Some("a"), None, Some("b"), Some("c"), None) + } + + context("filterSome") { + + val subscriber by memoized { + TestObserver().apply { + stream + .filterSome() + .subscribe(this) + } + } + + it("passes only Some values") { + subscriber.assertValues("a", "b", "c") + } + + it("completes stream") { + subscriber.assertComplete() + } + + it("does not emit error") { + subscriber.assertNoErrors() + } + } + + context("filterNone") { + + val subscriber by memoized { + TestObserver().apply { + stream + .filterNone() + .subscribe(this) + } + } + + it("passes only None values as Unit") { + subscriber.assertValues(Unit, Unit) + } + + it("completes stream") { + subscriber.assertComplete() + } + + it("does not emit error") { + subscriber.assertNoErrors() + } + } +}) diff --git a/koptional/build.gradle b/koptional/build.gradle index 7127ac3..b787b63 100644 --- a/koptional/build.gradle +++ b/koptional/build.gradle @@ -1,8 +1,6 @@ apply plugin: 'kotlin' apply plugin: 'org.junit.platform.gradle.plugin' -apply plugin: 'maven' -apply plugin: 'maven-publish' -apply plugin: 'com.jfrog.bintray' +apply from: '../gradle/publishing.gradle' dependencies { compile libraries.kotlinStd @@ -14,15 +12,6 @@ dependencies { testCompile libraries.assertJ } -jar { - // Build jar with dependencies. - from(configurations.compile.collect { it.isDirectory() ? it : zipTree(it) }) { - exclude 'META-INF/*.SF' - exclude 'META-INF/*.DSA' - exclude 'META-INF/*.RSA' - } -} - junitPlatform { platformVersion = versions.junitPlatform @@ -32,86 +21,3 @@ junitPlatform { } } } - -task sourcesJar(type: Jar, dependsOn: classes) { - classifier = 'sources' - from sourceSets.main.allSource -} - -task javadocJar(type: Jar, dependsOn: javadoc) { - classifier = 'javadoc' - from javadoc.destinationDir -} - -task validatePublishing { - doLast { - validateTagAndVersion() - } -} - -bintrayUpload.dependsOn validatePublishing - -def pomConfig = { - licenses { - license { - name 'The Apache Software License, Version 2.0' - url 'http://www.apache.org/licenses/LICENSE-2.0.txt' - distribution 'repo' - } - } - developers { - developer { - id 'gojuno' - name 'Juno Inc.' - email 'opensource@gojuno.com' - } - } -} - -publishing { - publications { - KoptionalPublication(MavenPublication) { - from components.java - - artifact sourcesJar - artifact javadocJar - - groupId 'com.gojuno.koptional' - artifactId 'koptional' - version projectVersion() - - pom.withXml { - def root = asNode() - root.appendNode('description', 'Minimalistic Optional type for Kotlin that tries to fit its null-safe type system as smooth as possible.') - root.appendNode('name', 'Koptional') - root.appendNode('url', 'https://github.com/gojuno/koptional') - root.children().last() + pomConfig - } - } - } -} - -bintray { - user = System.getenv('BINTRAY_USER') - key = System.getenv('BINTRAY_API_KEY') - publish = true - - pkg { - repo = 'maven' - name = 'koptional' - licenses = ['Apache-2.0'] - vcsUrl = 'https://github.com/gojuno/koptional.git' - issueTrackerUrl = 'https://github.com/gojuno/koptional/issues' - publications = ['KoptionalPublication'] - - version { - name = projectVersion() - vcsTag = gitTag() - - gpg { - sign = true - passphrase = System.getenv('BINTRAY_GPG_PASSPHRASE') - } - } - } -} diff --git a/koptional/gradle.properties b/koptional/gradle.properties new file mode 100644 index 0000000..2ee2d58 --- /dev/null +++ b/koptional/gradle.properties @@ -0,0 +1 @@ +description=Minimalistic Optional type for Kotlin. diff --git a/settings.gradle b/settings.gradle index ca1db9b..5710ed5 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1 +1,2 @@ include ':koptional' +include ':koptional-rxjava2-extensions'