From 88560776c6caea430420af665925611f5bc62697 Mon Sep 17 00:00:00 2001 From: samuelgruetter Date: Wed, 25 Sep 2013 12:08:20 +0200 Subject: [PATCH 01/33] add Documentation section to README --- language-adaptors/rxjava-scala/README.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/language-adaptors/rxjava-scala/README.md b/language-adaptors/rxjava-scala/README.md index c4ad66d0af..9cf23dde6e 100644 --- a/language-adaptors/rxjava-scala/README.md +++ b/language-adaptors/rxjava-scala/README.md @@ -65,6 +65,17 @@ Scala code using Rx should only import members from `rx.lang.scala` and below. Work on this adaptor is still in progress, and for the moment, the best source of documentation are the comments in the source code of [`rx.lang.scala.Observable`](https://github.com/Netflix/RxJava/blob/master/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/Observable.scala). +## Documentation + +You can build the documentation as follows: In the RxJava root directory, run + + ./gradlew :language-adaptors:rxjava-scala:scaladoc + +Then navigate to + + RxJava/language-adaptors/rxjava-scala/build/docs/scaladoc/index.html + + ## Binaries Binaries and dependency information for Maven, Ivy, Gradle and others can be found at [http://search.maven.org](http://search.maven.org/#search%7Cga%7C1%7Ca%3A%22rxjava-scala%22). From cc8b756cb46c4c997e0501ea35bf97bdaaa41d1d Mon Sep 17 00:00:00 2001 From: samuelgruetter Date: Wed, 25 Sep 2013 15:19:20 +0200 Subject: [PATCH 02/33] move examples from `src/main/scala` to `src/examples/scala` and tweak build.gradle to make this work --- language-adaptors/rxjava-scala/build.gradle | 16 ++++++++++++++++ .../scala/rx/lang/scala/examples/MovieLib.scala | 0 .../scala/rx/lang/scala/examples/Olympics.scala | 0 .../rx/lang/scala/examples/RxScalaDemo.scala | 0 .../main/scala/rx/lang/scala/Observable.scala | 3 ++- 5 files changed, 18 insertions(+), 1 deletion(-) rename language-adaptors/rxjava-scala/src/{main => examples}/scala/rx/lang/scala/examples/MovieLib.scala (100%) rename language-adaptors/rxjava-scala/src/{main => examples}/scala/rx/lang/scala/examples/Olympics.scala (100%) rename language-adaptors/rxjava-scala/src/{main => examples}/scala/rx/lang/scala/examples/RxScalaDemo.scala (100%) diff --git a/language-adaptors/rxjava-scala/build.gradle b/language-adaptors/rxjava-scala/build.gradle index 753c2749e1..8abd48dbaa 100644 --- a/language-adaptors/rxjava-scala/build.gradle +++ b/language-adaptors/rxjava-scala/build.gradle @@ -13,9 +13,21 @@ tasks.withType(ScalaCompile) { } sourceSets { + main { + scala { + srcDir 'src/main/scala' + } + } test { scala { srcDir 'src/main/scala' + srcDir 'src/test/scala' + srcDir 'src/examples/scala' + } + } + examples { + scala { + srcDir 'src/examples/scala' } } } @@ -34,6 +46,10 @@ tasks.compileScala { classpath = classpath + (configurations.compile + configurations.provided) } +tasks.compileExamplesScala { + classpath = classpath + files(compileScala.destinationDir) + (configurations.compile + configurations.provided) +} + task test(overwrite: true, dependsOn: testClasses) << { ant.taskdef(name: 'scalatest', classname: 'org.scalatest.tools.ScalaTestAntTask', diff --git a/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/examples/MovieLib.scala b/language-adaptors/rxjava-scala/src/examples/scala/rx/lang/scala/examples/MovieLib.scala similarity index 100% rename from language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/examples/MovieLib.scala rename to language-adaptors/rxjava-scala/src/examples/scala/rx/lang/scala/examples/MovieLib.scala diff --git a/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/examples/Olympics.scala b/language-adaptors/rxjava-scala/src/examples/scala/rx/lang/scala/examples/Olympics.scala similarity index 100% rename from language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/examples/Olympics.scala rename to language-adaptors/rxjava-scala/src/examples/scala/rx/lang/scala/examples/Olympics.scala diff --git a/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/examples/RxScalaDemo.scala b/language-adaptors/rxjava-scala/src/examples/scala/rx/lang/scala/examples/RxScalaDemo.scala similarity index 100% rename from language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/examples/RxScalaDemo.scala rename to language-adaptors/rxjava-scala/src/examples/scala/rx/lang/scala/examples/RxScalaDemo.scala diff --git a/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/Observable.scala b/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/Observable.scala index 8ff0ecd437..43a6288c86 100644 --- a/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/Observable.scala +++ b/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/Observable.scala @@ -2049,7 +2049,7 @@ class UnitTestSuite extends org.scalatest.junit.JUnitSuite { } @Test def testFirstOrElse() { - def mustNotBeCalled: String = error("this method should not be called") + def mustNotBeCalled: String = sys.error("this method should not be called") def mustBeCalled: String = "this is the default value" assertEquals("hello", Observable("hello").firstOrElse(mustNotBeCalled).toBlockingObservable.single) assertEquals("this is the default value", Observable().firstOrElse(mustBeCalled).toBlockingObservable.single) @@ -2069,6 +2069,7 @@ class UnitTestSuite extends org.scalatest.junit.JUnitSuite { @Test def testTest() = { val a: Observable[Int] = Observable() assertEquals(4, Observable(1, 2, 3, 4).toBlockingObservable.toIterable.last) + println("This UnitTestSuite.testTest() for rx.lang.scala.Observable") } } From 01634bc7b68b482972cf078d6eb0558572b8b5fa Mon Sep 17 00:00:00 2001 From: samuelgruetter Date: Wed, 25 Sep 2013 15:58:30 +0200 Subject: [PATCH 03/33] move MovieLibUsage.java from project rxjava-scala-java to project rxjava-scala and delete project rxjava-scala-java --- language-adaptors/rxjava-scala-java/README.md | 5 --- .../rxjava-scala-java/build.gradle | 32 ------------------- language-adaptors/rxjava-scala/build.gradle | 10 +++++- .../rx/lang/scala/examples/MovieLibUsage.java | 0 settings.gradle | 1 - 5 files changed, 9 insertions(+), 39 deletions(-) delete mode 100644 language-adaptors/rxjava-scala-java/README.md delete mode 100644 language-adaptors/rxjava-scala-java/build.gradle rename language-adaptors/{rxjava-scala-java/src/main => rxjava-scala/src/examples}/java/rx/lang/scala/examples/MovieLibUsage.java (100%) diff --git a/language-adaptors/rxjava-scala-java/README.md b/language-adaptors/rxjava-scala-java/README.md deleted file mode 100644 index 54d7086366..0000000000 --- a/language-adaptors/rxjava-scala-java/README.md +++ /dev/null @@ -1,5 +0,0 @@ - -rxjava-scala-java ------------------ - -Contains examples illustrating how RxScala code can be used from Java. diff --git a/language-adaptors/rxjava-scala-java/build.gradle b/language-adaptors/rxjava-scala-java/build.gradle deleted file mode 100644 index d6be5aaeb7..0000000000 --- a/language-adaptors/rxjava-scala-java/build.gradle +++ /dev/null @@ -1,32 +0,0 @@ - -apply plugin: 'osgi' - - -project(':language-adaptors:rxjava-scala-java') { - //sourceSets.test.java.srcDir 'src/examples/java' - sourceSets.main.java.srcDir 'src/main/java' -} - -dependencies { - compile 'org.scala-lang:scala-library:2.10.+' - - compile project(':rxjava-core') - - compile project(':language-adaptors:rxjava-scala') - - provided 'junit:junit-dep:4.10' - provided 'org.mockito:mockito-core:1.8.5' - provided 'org.scalatest:scalatest_2.10:1.9.1' -} - -jar { - manifest { - name = 'rxjava-scala-java' - instruction 'Bundle-Vendor', 'Netflix' - instruction 'Bundle-DocURL', 'https://github.com/Netflix/RxJava' - instruction 'Import-Package', '!org.junit,!junit.framework,!org.mockito.*,*' - instruction 'Fragment-Host', 'com.netflix.rxjava.core' - } -} - - diff --git a/language-adaptors/rxjava-scala/build.gradle b/language-adaptors/rxjava-scala/build.gradle index 8abd48dbaa..579a5a43b6 100644 --- a/language-adaptors/rxjava-scala/build.gradle +++ b/language-adaptors/rxjava-scala/build.gradle @@ -23,12 +23,20 @@ sourceSets { srcDir 'src/main/scala' srcDir 'src/test/scala' srcDir 'src/examples/scala' + srcDir 'src/examples/java' } + java.srcDirs = [] } - examples { + examples { + // It seems that in Gradle, the dependency "compileScala depends on compileJava" is hardcoded, + // or at least not meant to be removed. + // However, compileScala also runs javac at the very end, so we just add the Java sources to + // the scala source set: scala { srcDir 'src/examples/scala' + srcDir 'src/examples/java' } + java.srcDirs = [] } } diff --git a/language-adaptors/rxjava-scala-java/src/main/java/rx/lang/scala/examples/MovieLibUsage.java b/language-adaptors/rxjava-scala/src/examples/java/rx/lang/scala/examples/MovieLibUsage.java similarity index 100% rename from language-adaptors/rxjava-scala-java/src/main/java/rx/lang/scala/examples/MovieLibUsage.java rename to language-adaptors/rxjava-scala/src/examples/java/rx/lang/scala/examples/MovieLibUsage.java diff --git a/settings.gradle b/settings.gradle index 8750fab727..32cef40c9b 100644 --- a/settings.gradle +++ b/settings.gradle @@ -3,7 +3,6 @@ include 'rxjava-core', \ 'language-adaptors:rxjava-groovy', \ 'language-adaptors:rxjava-clojure', \ 'language-adaptors:rxjava-scala', \ -'language-adaptors:rxjava-scala-java', \ 'rxjava-contrib:rxjava-swing', \ 'rxjava-contrib:rxjava-android', \ 'rxjava-contrib:rxjava-apache-http' From 450be124584a29d1558323f3c84ab2995b037f49 Mon Sep 17 00:00:00 2001 From: samuelgruetter Date: Wed, 25 Sep 2013 19:04:48 +0200 Subject: [PATCH 04/33] how to add RxJava core to scaladoc input --- language-adaptors/rxjava-scala/build.gradle | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/language-adaptors/rxjava-scala/build.gradle b/language-adaptors/rxjava-scala/build.gradle index 579a5a43b6..db194a6d28 100644 --- a/language-adaptors/rxjava-scala/build.gradle +++ b/language-adaptors/rxjava-scala/build.gradle @@ -58,6 +58,11 @@ tasks.compileExamplesScala { classpath = classpath + files(compileScala.destinationDir) + (configurations.compile + configurations.provided) } +// Add RxJava core to Scaladoc input: +// tasks.scaladoc.source(project(':rxjava-core').tasks.getByPath(':rxjava-core:compileJava').source) +// println("-------") +// println(tasks.scaladoc.source.asPath) + task test(overwrite: true, dependsOn: testClasses) << { ant.taskdef(name: 'scalatest', classname: 'org.scalatest.tools.ScalaTestAntTask', From f20a8eb3855ce4306b67eaccaef75cd39b1568b5 Mon Sep 17 00:00:00 2001 From: samuelgruetter Date: Wed, 25 Sep 2013 19:06:09 +0200 Subject: [PATCH 05/33] make Subscription an implicit value class --- .../lang/scala/ImplicitFunctionConversions.scala | 4 ++-- .../src/main/scala/rx/lang/scala/package.scala | 14 +++++++++++++- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/ImplicitFunctionConversions.scala b/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/ImplicitFunctionConversions.scala index 80adb8d22a..1043231bbe 100644 --- a/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/ImplicitFunctionConversions.scala +++ b/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/ImplicitFunctionConversions.scala @@ -29,8 +29,8 @@ object ImplicitFunctionConversions { implicit def scalaFunction1ToOnSubscribeFunc[T](f: rx.lang.scala.Observer[T] => Subscription) = new rx.Observable.OnSubscribeFunc[T] { - def onSubscribe(obs: Observer[_ >: T]): Subscription = { - f(obs) + def onSubscribe(obs: Observer[_ >: T]): rx.Subscription = { + f(obs).asJava } } diff --git a/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/package.scala b/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/package.scala index 0f6ea79d34..81af61241a 100644 --- a/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/package.scala +++ b/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/package.scala @@ -35,8 +35,20 @@ package object scala { type Observer[-T] = rx.Observer[_ >: T] type Scheduler = rx.Scheduler - type Subscription = rx.Subscription + /** + * Subscriptions are returned from all Observable.subscribe methods to allow unsubscribing. + * + * This interface is the RxJava equivalent of IDisposable in Microsoft's Rx implementation. + */ + implicit class Subscription(val asJava: rx.Subscription) extends AnyVal { + /** + * Call this to stop receiving notifications on the Observer that was registered when + * this Subscription was received. + */ + def unsubscribe(): Unit = asJava.unsubscribe() + } + } /* From a5fe8dcf2622e5b32117d68f99738daeb39fcb25 Mon Sep 17 00:00:00 2001 From: samuelgruetter Date: Wed, 25 Sep 2013 20:09:21 +0200 Subject: [PATCH 06/33] Opening/Closing, Timestamped with unapply, BlockingObservable with WithFilter --- .../rx/lang/scala/examples/RxScalaDemo.scala | 8 ++++ .../main/scala/rx/lang/scala/Observable.scala | 2 +- .../observables/BlockingObservable.scala | 35 ++++++++++++-- .../scala/rx/lang/scala/util/package.scala | 48 ++++++++++++------- 4 files changed, 71 insertions(+), 22 deletions(-) diff --git a/language-adaptors/rxjava-scala/src/examples/scala/rx/lang/scala/examples/RxScalaDemo.scala b/language-adaptors/rxjava-scala/src/examples/scala/rx/lang/scala/examples/RxScalaDemo.scala index c01528fb7a..1653bd8b2b 100644 --- a/language-adaptors/rxjava-scala/src/examples/scala/rx/lang/scala/examples/RxScalaDemo.scala +++ b/language-adaptors/rxjava-scala/src/examples/scala/rx/lang/scala/examples/RxScalaDemo.scala @@ -22,6 +22,7 @@ import scala.concurrent.duration._ import org.junit.{Before, Test, Ignore} import org.junit.Assert._ import rx.lang.scala.concurrency.NewThreadScheduler +import rx.lang.scala.util.Timestamped @Ignore // Since this doesn't do automatic testing, don't increase build time unnecessarily class RxScalaDemo extends JUnitSuite { @@ -375,6 +376,13 @@ class RxScalaDemo extends JUnitSuite { assertEquals(Seq(10, 9, 8, 7), Observable(10, 7, 8, 9).toSeq.map(_.sortWith(f)).toBlockingObservable.single) } + @Test def timestampExample() { + val timestamped = Observable.interval(100 millis).take(3).timestamp.toBlockingObservable + for (Timestamped(millis, value) <- timestamped if value > 0) { + println(value + " at t = " + millis) + } + } + def output(s: String): Unit = println(s) // blocks until obs has completed diff --git a/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/Observable.scala b/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/Observable.scala index 43a6288c86..1dace17c59 100644 --- a/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/Observable.scala +++ b/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/Observable.scala @@ -199,7 +199,7 @@ class Observable[+T](val asJava: rx.Observable[_ <: T]) * @return an Observable that emits timestamped items from the source Observable */ def timestamp: Observable[Timestamped[T]] = { - Observable[Timestamped[T]](asJava.timestamp()) + Observable[rx.util.Timestamped[_ <: T]](asJava.timestamp()).map(Timestamped(_)) } /** diff --git a/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/observables/BlockingObservable.scala b/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/observables/BlockingObservable.scala index 5470f6f1cb..4be27d0ae0 100644 --- a/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/observables/BlockingObservable.scala +++ b/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/observables/BlockingObservable.scala @@ -18,6 +18,11 @@ package rx.lang.scala.observables import scala.collection.JavaConverters._ import rx.lang.scala.ImplicitFunctionConversions._ +/** + * An Observable that provides blocking operators. + * + * You can obtain a BlockingObservable from an Observable using [[Observable.toBlockingObservable]] + */ class BlockingObservable[+T](val asJava: rx.observables.BlockingObservable[_ <: T]) extends AnyVal { @@ -25,12 +30,12 @@ class BlockingObservable[+T](val asJava: rx.observables.BlockingObservable[_ <: /** * Invoke a method on each item emitted by the {@link Observable}; block until the Observable * completes. - *

+ * * NOTE: This will block even if the Observable is asynchronous. - *

+ * * This is similar to {@link Observable#subscribe(Observer)}, but it blocks. Because it blocks it does * not need the {@link Observer#onCompleted()} or {@link Observer#onError(Throwable)} methods. - *

+ * * * * @param onNext @@ -41,6 +46,10 @@ class BlockingObservable[+T](val asJava: rx.observables.BlockingObservable[_ <: def foreach(f: T => Unit): Unit = { asJava.forEach(f); } + + def withFilter(p: T => Boolean): WithFilter[T] = { + new WithFilter[T](p, asJava) + } // last -> use toIterable.last // lastOrDefault -> use toIterable.lastOption @@ -118,3 +127,23 @@ class BlockingObservable[+T](val asJava: rx.observables.BlockingObservable[_ <: } } + +// Cannot yet have inner class because of this error message: +// "implementation restriction: nested class is not allowed in value class. +// This restriction is planned to be removed in subsequent releases." +class WithFilter[+T] private[observables] (p: T => Boolean, asJava: rx.observables.BlockingObservable[_ <: T]) { + import rx.lang.scala.ImplicitFunctionConversions._ + + // there's no map and flatMap here, they're only available on Observable + + def withFilter(q: T => Boolean) = new WithFilter[T]((x: T) => p(x) && q(x), asJava) + + def foreach(f: T => Unit): Unit = { + asJava.forEach((e: T) => { + if (p(e)) f(e) + }) + } + +} + + diff --git a/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/util/package.scala b/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/util/package.scala index 6dced72f8e..bee0992981 100644 --- a/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/util/package.scala +++ b/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/util/package.scala @@ -16,33 +16,45 @@ package rx.lang.scala package object util { - type Closing = rx.util.Closing - - object Closings { - def create(): Closing = rx.util.Closings.create() - } - - type CompositeException = rx.util.CompositeException - - // TODO not sure if we need this in Scala - object Exceptions { - def propageate(ex: Throwable) = rx.util.Exceptions.propagate(ex) - } - - // rx.util.OnErrorNotImplementedException TODO what's this? + /** + * Tagging interface for objects which can open buffers. + * @see [[Observable.buffer]] + */ type Opening = rx.util.Opening - object Openings { - def create(): Opening = rx.util.Openings.create() - } + /** + * Creates an object which can open buffers. + * @see [[Observable.buffer]] + */ + def Opening() = rx.util.Openings.create() + + /** + * Tagging interface for objects which can close buffers. + * @see [[Observable.buffer]] + */ + type Closing = rx.util.Closing + /** + * Creates an object which can close buffers. + * @see [[Observable.buffer]] + */ + def Closing() = rx.util.Closings.create() + // rx.util.Range not needed because there's a standard Scala Range - type Timestamped[+T] = rx.util.Timestamped[_ <: T] + implicit class Timestamped[+T](val asJava: rx.util.Timestamped[_ <: T]) {} + object Timestamped { def apply[T](timestampMillis: Long, value: T): Timestamped[T] = { new rx.util.Timestamped(timestampMillis, value) } + + def unapply[T](v: Timestamped[T]): Option[(Long, T)] = unapply(v.asJava) + + def unapply[T](v: rx.util.Timestamped[_ <: T]): Option[(Long, T)] = { + Some((v.getTimestampMillis, v.getValue)) + } } + } \ No newline at end of file From 6f56788071b8e2efd0465f8cb29f0ca2cb0d44cf Mon Sep 17 00:00:00 2001 From: samuelgruetter Date: Wed, 25 Sep 2013 20:42:42 +0200 Subject: [PATCH 07/33] remove `implicit` from Timestamped --- .../src/main/scala/rx/lang/scala/util/package.scala | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/util/package.scala b/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/util/package.scala index bee0992981..d03f2bc58d 100644 --- a/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/util/package.scala +++ b/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/util/package.scala @@ -43,11 +43,15 @@ package object util { // rx.util.Range not needed because there's a standard Scala Range - implicit class Timestamped[+T](val asJava: rx.util.Timestamped[_ <: T]) {} + class Timestamped[+T](val asJava: rx.util.Timestamped[_ <: T]) {} object Timestamped { def apply[T](timestampMillis: Long, value: T): Timestamped[T] = { - new rx.util.Timestamped(timestampMillis, value) + new Timestamped(new rx.util.Timestamped(timestampMillis, value)) + } + + def apply[T](asJava: rx.util.Timestamped[_ <: T]): Timestamped[T] = { + new Timestamped(asJava) } def unapply[T](v: Timestamped[T]): Option[(Long, T)] = unapply(v.asJava) From de7ac4246e84ca5ee2e39ee8cd91c0afd966cdfa Mon Sep 17 00:00:00 2001 From: samuelgruetter Date: Wed, 25 Sep 2013 20:55:32 +0200 Subject: [PATCH 08/33] work around scalac bug by renaming companion object `Timestamped` to `TimestampedObject` --- .../examples/scala/rx/lang/scala/examples/RxScalaDemo.scala | 4 ++-- .../src/main/scala/rx/lang/scala/Observable.scala | 2 +- .../src/main/scala/rx/lang/scala/util/package.scala | 3 ++- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/language-adaptors/rxjava-scala/src/examples/scala/rx/lang/scala/examples/RxScalaDemo.scala b/language-adaptors/rxjava-scala/src/examples/scala/rx/lang/scala/examples/RxScalaDemo.scala index 1653bd8b2b..a8d728149a 100644 --- a/language-adaptors/rxjava-scala/src/examples/scala/rx/lang/scala/examples/RxScalaDemo.scala +++ b/language-adaptors/rxjava-scala/src/examples/scala/rx/lang/scala/examples/RxScalaDemo.scala @@ -22,7 +22,7 @@ import scala.concurrent.duration._ import org.junit.{Before, Test, Ignore} import org.junit.Assert._ import rx.lang.scala.concurrency.NewThreadScheduler -import rx.lang.scala.util.Timestamped +import rx.lang.scala.util.{Timestamped, TimestampedObject} @Ignore // Since this doesn't do automatic testing, don't increase build time unnecessarily class RxScalaDemo extends JUnitSuite { @@ -378,7 +378,7 @@ class RxScalaDemo extends JUnitSuite { @Test def timestampExample() { val timestamped = Observable.interval(100 millis).take(3).timestamp.toBlockingObservable - for (Timestamped(millis, value) <- timestamped if value > 0) { + for (TimestampedObject(millis, value) <- timestamped if value > 0) { println(value + " at t = " + millis) } } diff --git a/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/Observable.scala b/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/Observable.scala index 1dace17c59..74da23b137 100644 --- a/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/Observable.scala +++ b/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/Observable.scala @@ -199,7 +199,7 @@ class Observable[+T](val asJava: rx.Observable[_ <: T]) * @return an Observable that emits timestamped items from the source Observable */ def timestamp: Observable[Timestamped[T]] = { - Observable[rx.util.Timestamped[_ <: T]](asJava.timestamp()).map(Timestamped(_)) + Observable[rx.util.Timestamped[_ <: T]](asJava.timestamp()).map(TimestampedObject(_)) } /** diff --git a/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/util/package.scala b/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/util/package.scala index d03f2bc58d..aa900ed24a 100644 --- a/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/util/package.scala +++ b/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/util/package.scala @@ -45,7 +45,8 @@ package object util { class Timestamped[+T](val asJava: rx.util.Timestamped[_ <: T]) {} - object Timestamped { + // TODO rename this to Timestamped without making scalac crash + object TimestampedObject { def apply[T](timestampMillis: Long, value: T): Timestamped[T] = { new Timestamped(new rx.util.Timestamped(timestampMillis, value)) } From 14369fc7e4eaf98dac3df660f1cbabe8a0aa54fe Mon Sep 17 00:00:00 2001 From: samuelgruetter Date: Thu, 26 Sep 2013 10:07:32 +0200 Subject: [PATCH 09/33] Timestamped and its companion can now have the same name --- .../rx/lang/scala/examples/RxScalaDemo.scala | 4 +-- .../main/scala/rx/lang/scala/Observable.scala | 2 +- .../rx/lang/scala/util/Timestamped.scala | 30 +++++++++++++++++++ .../scala/rx/lang/scala/util/package.scala | 19 ------------ 4 files changed, 33 insertions(+), 22 deletions(-) create mode 100644 language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/util/Timestamped.scala diff --git a/language-adaptors/rxjava-scala/src/examples/scala/rx/lang/scala/examples/RxScalaDemo.scala b/language-adaptors/rxjava-scala/src/examples/scala/rx/lang/scala/examples/RxScalaDemo.scala index a8d728149a..1653bd8b2b 100644 --- a/language-adaptors/rxjava-scala/src/examples/scala/rx/lang/scala/examples/RxScalaDemo.scala +++ b/language-adaptors/rxjava-scala/src/examples/scala/rx/lang/scala/examples/RxScalaDemo.scala @@ -22,7 +22,7 @@ import scala.concurrent.duration._ import org.junit.{Before, Test, Ignore} import org.junit.Assert._ import rx.lang.scala.concurrency.NewThreadScheduler -import rx.lang.scala.util.{Timestamped, TimestampedObject} +import rx.lang.scala.util.Timestamped @Ignore // Since this doesn't do automatic testing, don't increase build time unnecessarily class RxScalaDemo extends JUnitSuite { @@ -378,7 +378,7 @@ class RxScalaDemo extends JUnitSuite { @Test def timestampExample() { val timestamped = Observable.interval(100 millis).take(3).timestamp.toBlockingObservable - for (TimestampedObject(millis, value) <- timestamped if value > 0) { + for (Timestamped(millis, value) <- timestamped if value > 0) { println(value + " at t = " + millis) } } diff --git a/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/Observable.scala b/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/Observable.scala index 74da23b137..1dace17c59 100644 --- a/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/Observable.scala +++ b/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/Observable.scala @@ -199,7 +199,7 @@ class Observable[+T](val asJava: rx.Observable[_ <: T]) * @return an Observable that emits timestamped items from the source Observable */ def timestamp: Observable[Timestamped[T]] = { - Observable[rx.util.Timestamped[_ <: T]](asJava.timestamp()).map(TimestampedObject(_)) + Observable[rx.util.Timestamped[_ <: T]](asJava.timestamp()).map(Timestamped(_)) } /** diff --git a/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/util/Timestamped.scala b/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/util/Timestamped.scala new file mode 100644 index 0000000000..93f2ef2089 --- /dev/null +++ b/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/util/Timestamped.scala @@ -0,0 +1,30 @@ +package rx.lang.scala.util + +/** + * Wraps a value and a timestamp. + */ +class Timestamped[+T](val asJava: rx.util.Timestamped[_ <: T]) extends AnyVal { + /** + * Returns the timestamp, in milliseconds. + */ + def millis: Long = asJava.getTimestampMillis + + /** + * Returns the value. + */ + def value: T = asJava.getValue : T +} + +object Timestamped { + def apply[T](timestampMillis: Long, value: T): Timestamped[T] = { + new Timestamped(new rx.util.Timestamped(timestampMillis, value)) + } + + def apply[T](asJava: rx.util.Timestamped[_ <: T]): Timestamped[T] = { + new Timestamped(asJava) + } + + def unapply[T](v: Timestamped[T]): Option[(Long, T)] = { + Some((v.millis, v.value)) + } +} diff --git a/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/util/package.scala b/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/util/package.scala index aa900ed24a..1a41f43643 100644 --- a/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/util/package.scala +++ b/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/util/package.scala @@ -42,24 +42,5 @@ package object util { def Closing() = rx.util.Closings.create() // rx.util.Range not needed because there's a standard Scala Range - - class Timestamped[+T](val asJava: rx.util.Timestamped[_ <: T]) {} - - // TODO rename this to Timestamped without making scalac crash - object TimestampedObject { - def apply[T](timestampMillis: Long, value: T): Timestamped[T] = { - new Timestamped(new rx.util.Timestamped(timestampMillis, value)) - } - - def apply[T](asJava: rx.util.Timestamped[_ <: T]): Timestamped[T] = { - new Timestamped(asJava) - } - - def unapply[T](v: Timestamped[T]): Option[(Long, T)] = unapply(v.asJava) - - def unapply[T](v: rx.util.Timestamped[_ <: T]): Option[(Long, T)] = { - Some((v.getTimestampMillis, v.getValue)) - } - } } \ No newline at end of file From f7ab0b39b951df5a5bfc25560e56205a57b4ac60 Mon Sep 17 00:00:00 2001 From: samuelgruetter Date: Thu, 26 Sep 2013 13:04:27 +0200 Subject: [PATCH 10/33] scaladoc for Observer, Subject, Scheduler, and new Notification class with unapply (scalac crashes) --- .../rx/lang/scala/examples/RxScalaDemo.scala | 13 +- .../scala/ImplicitFunctionConversions.scala | 4 +- .../scala/rx/lang/scala/Notification.scala | 42 ++++ .../main/scala/rx/lang/scala/Observable.scala | 15 +- .../rx/lang/scala/observables/package.scala | 12 + .../main/scala/rx/lang/scala/package.scala | 214 ++++++++++++++++-- .../rx/lang/scala/subjects/package.scala | 18 +- 7 files changed, 284 insertions(+), 34 deletions(-) create mode 100644 language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/Notification.scala create mode 100644 language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/observables/package.scala diff --git a/language-adaptors/rxjava-scala/src/examples/scala/rx/lang/scala/examples/RxScalaDemo.scala b/language-adaptors/rxjava-scala/src/examples/scala/rx/lang/scala/examples/RxScalaDemo.scala index 1653bd8b2b..1b4a8684ac 100644 --- a/language-adaptors/rxjava-scala/src/examples/scala/rx/lang/scala/examples/RxScalaDemo.scala +++ b/language-adaptors/rxjava-scala/src/examples/scala/rx/lang/scala/examples/RxScalaDemo.scala @@ -24,7 +24,7 @@ import org.junit.Assert._ import rx.lang.scala.concurrency.NewThreadScheduler import rx.lang.scala.util.Timestamped -@Ignore // Since this doesn't do automatic testing, don't increase build time unnecessarily +//@Ignore // Since this doesn't do automatic testing, don't increase build time unnecessarily class RxScalaDemo extends JUnitSuite { @Test def intervalExample() { @@ -383,6 +383,17 @@ class RxScalaDemo extends JUnitSuite { } } + @Test def materializeExample() { + def printObservable[T](o: Observable[T]): Unit = { + for (n <- o.materialize.toBlockingObservable) n match { + case Notification.OnNext[T](v) => println("Got value " + v) + case Notification.OnCompleted[T]() => println("Completed") + case Notification.OnError[T](err) => println("Error: ") + } + } + val mat = Observable.interval(100 millis).take(3).materialize + } + def output(s: String): Unit = println(s) // blocks until obs has completed diff --git a/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/ImplicitFunctionConversions.scala b/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/ImplicitFunctionConversions.scala index 1043231bbe..78b1d8d776 100644 --- a/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/ImplicitFunctionConversions.scala +++ b/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/ImplicitFunctionConversions.scala @@ -29,8 +29,8 @@ object ImplicitFunctionConversions { implicit def scalaFunction1ToOnSubscribeFunc[T](f: rx.lang.scala.Observer[T] => Subscription) = new rx.Observable.OnSubscribeFunc[T] { - def onSubscribe(obs: Observer[_ >: T]): rx.Subscription = { - f(obs).asJava + def onSubscribe(obs: rx.Observer[_ >: T]): rx.Subscription = { + f(obs) } } diff --git a/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/Notification.scala b/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/Notification.scala new file mode 100644 index 0000000000..30145f27f5 --- /dev/null +++ b/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/Notification.scala @@ -0,0 +1,42 @@ +package rx.lang.scala + +sealed trait Notification[+T] { + def asJava: rx.Notification[_ <: T] +} + +object Notification { + + def apply[T](n: rx.Notification[_ <: T]): Notification[T] = n.getKind match { + case rx.Notification.Kind.OnNext => new OnNext(n) + case rx.Notification.Kind.OnCompleted => new OnCompleted(n) + case rx.Notification.Kind.OnError => new OnError(n) + } + + // OnNext, OnError, OnCompleted are not case classes because we don't want pattern matching + // to extract the rx.Notification + + class OnNext[+T](val asJava: rx.Notification[_ <: T]) extends Notification[T] { + def value: T = asJava.getValue + def unapply[U](n: Notification[U]): Option[U] = n match { + case n2: OnNext[U] => Some(n.asJava.getValue) + case _ => None + } + } + + class OnError[+T](val asJava: rx.Notification[_ <: T]) extends Notification[T] { + def error: Throwable = asJava.getThrowable() + def unapply[U](n: Notification[U]): Option[Throwable] = n match { + case n2: OnError[U] => Some(n2.asJava.getThrowable) + case _ => None + } + } + + class OnCompleted[T](val asJava: rx.Notification[_ <: T]) extends Notification[T] { + def unapply[U](n: Notification[U]): Option[Unit] = n match { + case n2: OnCompleted[U] => Some() + case _ => None + } + } + +} + diff --git a/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/Observable.scala b/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/Observable.scala index 1dace17c59..afa0b59fcd 100644 --- a/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/Observable.scala +++ b/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/Observable.scala @@ -30,7 +30,6 @@ class Observable[+T](val asJava: rx.Observable[_ <: T]) import scala.concurrent.duration.{Duration, TimeUnit} import rx.{Observable => JObservable} import rx.util.functions._ - import rx.lang.scala.{Notification, Subscription, Scheduler, Observer} import rx.lang.scala.util._ import rx.lang.scala.subjects.Subject import rx.lang.scala.observables.BlockingObservable @@ -714,7 +713,7 @@ class Observable[+T](val asJava: rx.Observable[_ <: T]) * @see MSDN: Observable.materialize */ def materialize: Observable[Notification[T]] = { - Observable[Notification[T]](asJava.materialize()) + Observable[rx.Notification[_ <: T]](asJava.materialize()).map(Notification(_)) } /** @@ -755,9 +754,11 @@ class Observable[+T](val asJava: rx.Observable[_ <: T]) * @return an Observable that emits the items and notifications embedded in the {@link Notification} objects emitted by the source Observable */ // with =:= it does not work, why? - def dematerialize[U](implicit evidence: T <:< Notification[U]): Observable[U] = { - val o = asJava.dematerialize[U]() - Observable[U](o) + def dematerialize[U](implicit evidence: Observable[T] <:< Observable[Notification[U]]): Observable[U] = { + val o1: Observable[Notification[U]] = this + val o2: Observable[rx.Notification[_ <: U]] = o1.map(_.asJava) + val o3 = o2.asJava.dematerialize[U]() + Observable[U](o3) } /** @@ -1765,7 +1766,6 @@ object Observable { import scala.collection.immutable.Range import scala.concurrent.duration.Duration import rx.{Observable => JObservable} - import rx.lang.scala.{Notification, Subscription, Scheduler, Observer} import rx.lang.scala.util._ import rx.util.functions._ import rx.lang.scala.ImplicitFunctionConversions._ @@ -1923,7 +1923,8 @@ object Observable { } def apply[T](f: Future[T], scheduler: Scheduler): Observable[T] = { - Observable[T](rx.Observable.from(f, scheduler)) + val sched: rx.Scheduler = scheduler + Observable[T](rx.Observable.from(f, sched)) } def apply[T](f: Future[T], duration: Duration): Observable[T] = { diff --git a/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/observables/package.scala b/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/observables/package.scala new file mode 100644 index 0000000000..ae1181321f --- /dev/null +++ b/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/observables/package.scala @@ -0,0 +1,12 @@ +package rx.lang.scala + +/** + * Contains special Observables. + * + * In Scala, this package only contains [[rx.lang.scala.observables.BlockingObservable]]. + * In the corresponding Java package {{{rx.observables}}}, there is also a + * {{{GroupedObservable}}} and a {{{ConnectableObservable}}}, but these are not needed + * in Scala, because we use a pair {{{(key, observable)}}} instead of {{{GroupedObservable}}} + * and a pair {{{(startFunction, observable)}}} instead of {{{ConnectableObservable}}}. + */ +package object observables {} diff --git a/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/package.scala b/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/package.scala index 81af61241a..04ed0ce6af 100644 --- a/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/package.scala +++ b/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/package.scala @@ -16,50 +16,221 @@ package rx.lang -/* +/** * This object contains aliases to all types Scala users need to import. + * * Note that: * - Scala users cannot use Java's type with variance without always using writing * e.g. rx.Notification[_ <: T], so we create aliases fixing the variance * - For consistency, we create aliases for all types - * - Type aliases cannot be at top level, they have to be inside an object or class */ +import java.util.concurrent.TimeUnit +import java.util.Date package object scala { - type Notification[+T] = rx.Notification[_ <: T] - object Notification { - def apply[T](): Notification[T] = new rx.Notification() - def apply[T](value: T): Notification[T] = new rx.Notification(value) - def apply[T](t: Throwable): Notification[T] = new rx.Notification(t) + /* + * Here we're imitating C's preprocessor using Search & Replace. + * + * To activate the code needed to get nice Scaladoc, do the following replacements: + * /*//#ifdef SCALADOC --> //#ifdef SCALADOC + * *///#else --> /*//#else + * //#endif --> *///#endif + * + * To get back to the actual code, undo the above replacements. + * + */ + + /*//#ifdef SCALADOC + + /** + * Provides a mechanism for receiving push-based notifications. + * + * After an Observer calls an [[rx.lang.scala.Observable]]'s {{{subscribe}}} method, the Observable + * calls the Observer's {{{onNext}}} method to provide notifications. A well-behaved Observable will + * call an Observer's {{{onCompleted}}} method exactly once or the Observer's {{{onError}}} method exactly once. + */ + trait Observer[-T] { + + /** + * Notifies the Observer that the [[rx.lang.scala.Observable]] has finished sending push-based notifications. + * + * The [[rx.lang.scala.Observable]] will not call this method if it calls {{{onError}}}. + */ + def onCompleted(): Unit + + /** + * Notifies the Observer that the [[rx.lang.scala.Observable]] has experienced an error condition. + * + * If the [[rx.lang.scala.Observable]] calls this method, it will not thereafter call {{{onNext}}} or {{{onCompleted}}}. + */ + def onError(e: Throwable): Unit + + /** + * Provides the Observer with new data. + * + * The [[rx.lang.scala.Observable]] calls this closure 0 or more times. + * + * The [[rx.lang.scala.Observable]] will not call this method again after it calls either {{{onCompleted}}} or {{{onError}}}. + */ + def onNext(arg: T): Unit } - - type Observer[-T] = rx.Observer[_ >: T] - type Scheduler = rx.Scheduler + + /** + * Represents an object that schedules units of work. + */ + abstract class Scheduler { + + /** + * Schedules a cancelable action to be executed. + * + * @param state + * State to pass into the action. + * @param action + * Action to schedule. + * @return a subscription to be able to unsubscribe from action. + */ + def schedule[T](state: T, action: (Scheduler, T) => Subscription): Subscription + + /** + * Schedules a cancelable action to be executed in delayTime. + * + * @param state + * State to pass into the action. + * @param action + * Action to schedule. + * @param delayTime + * Time the action is to be delayed before executing. + * @param unit + * Time unit of the delay time. + * @return a subscription to be able to unsubscribe from action. + */ + def schedule[T](state: T, action: (Scheduler, T) => Subscription, delayTime: Long, unit: TimeUnit): Subscription + + /** + * Schedules a cancelable action to be executed periodically. + * This default implementation schedules recursively and waits for actions to complete (instead of potentially executing + * long-running actions concurrently). Each scheduler that can do periodic scheduling in a better way should override this. + * + * @param state + * State to pass into the action. + * @param action + * The action to execute periodically. + * @param initialDelay + * Time to wait before executing the action for the first time. + * @param period + * The time interval to wait each time in between executing the action. + * @param unit + * The time unit the interval above is given in. + * @return A subscription to be able to unsubscribe from action. + */ + def schedulePeriodically[T](state: T, action: (Scheduler, T) => Subscription, initialDelay: Long, period: Long, unit: TimeUnit): Subscription + + /** + * Schedules a cancelable action to be executed at dueTime. + * + * @param state + * State to pass into the action. + * @param action + * Action to schedule. + * @param dueTime + * Time the action is to be executed. If in the past it will be executed immediately. + * @return a subscription to be able to unsubscribe from action. + */ + def schedule[T](state: T, action: (Scheduler, T) => Subscription, dueTime: Date): Subscription + + /** + * Schedules an action to be executed. + * + * @param action + * action + * @return a subscription to be able to unsubscribe from action. + */ + def schedule(action: () => Unit): Subscription + + /** + * Schedules an action to be executed in delayTime. + * + * @param action + * action + * @return a subscription to be able to unsubscribe from action. + */ + def schedule(action: () => Unit, delayTime: Long, unit: TimeUnit): Subscription + + /** + * Schedules an action to be executed periodically. + * + * @param action + * The action to execute periodically. + * @param initialDelay + * Time to wait before executing the action for the first time. + * @param period + * The time interval to wait each time in between executing the action. + * @param unit + * The time unit the interval above is given in. + * @return A subscription to be able to unsubscribe from action. + */ + def schedulePeriodically(action: () => Unit, initialDelay: Long, period: Long, unit: TimeUnit): Subscription + + /** + * @return the scheduler's notion of current absolute time in milliseconds. + */ + def now(): Long + + /** + * Parallelism available to a Scheduler. + *

+ * This defaults to {@code Runtime.getRuntime().availableProcessors()} but can be overridden for use cases such as scheduling work on a computer cluster. + * + * @return the scheduler's available degree of parallelism. + */ + def degreeOfParallelism: Int + + } + /** * Subscriptions are returned from all Observable.subscribe methods to allow unsubscribing. * - * This interface is the RxJava equivalent of IDisposable in Microsoft's Rx implementation. + * This interface is the equivalent of IDisposable in the .NET Rx implementation. */ - implicit class Subscription(val asJava: rx.Subscription) extends AnyVal { + trait Subscription { /** - * Call this to stop receiving notifications on the Observer that was registered when + * Call this method to stop receiving notifications on the Observer that was registered when * this Subscription was received. */ - def unsubscribe(): Unit = asJava.unsubscribe() + def unsubscribe(): Unit } + + private[scala] implicit def fakeSubscription2RxSubscription(s: Subscription): rx.Subscription = + new rx.Subscription { + def unsubscribe() = s.unsubscribe() + } + private[scala] implicit def rxSubscription2FakeSubscription(s: rx.Subscription): Subscription = + new Subscription { + def unsubscribe() = s.unsubscribe() + } + + private[scala] implicit def fakeObserver2RxObserver[T](o: Observer[T]): rx.Observer[_ >: T] = ??? + private[scala] implicit def rxObserver2fakeObserver[T](o: rx.Observer[_ >: T]): Observer[T] = ??? + + private[scala] implicit def fakeScheduler2RxScheduler(s: Scheduler): rx.Scheduler = ??? + private[scala] implicit def rxScheduler2fakeScheduler(s: rx.Scheduler): Scheduler = ??? + + *///#else + + type Observer[-T] = rx.Observer[_ >: T] + + type Scheduler = rx.Scheduler + + type Subscription = rx.Subscription + + //#endif } /* -TODO make aliases for these types because: -* those which are covariant or contravariant do need an alias to get variance correct -* the others for consistency - -rx.observables.BlockingObservable -rx.observables.ConnectableObservable -rx.observables.GroupedObservable +These classes are considered unnecessary for Scala users, so we don't create aliases for them: rx.plugins.RxJavaErrorHandler rx.plugins.RxJavaObservableExecutionHook @@ -70,4 +241,3 @@ rx.subscriptions.CompositeSubscription rx.subscriptions.Subscriptions */ - diff --git a/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/subjects/package.scala b/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/subjects/package.scala index 8f99d02bf6..22c265aefc 100644 --- a/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/subjects/package.scala +++ b/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/subjects/package.scala @@ -2,10 +2,24 @@ package rx.lang.scala package object subjects { - // in Java: public abstract class Subject extends Observable implements Observer + /** + * A Subject is an Observable and an Observer at the same time. + * + * The Java Subject looks like this: + * {{{ + * public abstract class Subject extends Observable implements Observer + * }}} + */ type Subject[-T, +R] = rx.subjects.Subject[_ >: T, _ <: R] - // TODO (including static methods of these classes) + // For nicer scaladoc, we would like to present something like this: + /* + trait Observable[+R] {} + trait Observer[-T] {} + trait Subject[-T, +R] extends Observable[R] with Observer[T] { } + */ + + // We don't make aliases to these types, because they are considered internal/not needed by users: // rx.subjects.AsyncSubject // rx.subjects.BehaviorSubject // rx.subjects.PublishSubject From add46e615c3f3a690c33e4fb6082255d1ed97f32 Mon Sep 17 00:00:00 2001 From: samuelgruetter Date: Thu, 26 Sep 2013 14:35:01 +0200 Subject: [PATCH 11/33] put unapply of Notifications into companions no more scalac crash --- .../rx/lang/scala/examples/RxScalaDemo.scala | 17 +++++++++++------ .../main/scala/rx/lang/scala/Notification.scala | 10 +++++++++- 2 files changed, 20 insertions(+), 7 deletions(-) diff --git a/language-adaptors/rxjava-scala/src/examples/scala/rx/lang/scala/examples/RxScalaDemo.scala b/language-adaptors/rxjava-scala/src/examples/scala/rx/lang/scala/examples/RxScalaDemo.scala index 1b4a8684ac..66be4c51c1 100644 --- a/language-adaptors/rxjava-scala/src/examples/scala/rx/lang/scala/examples/RxScalaDemo.scala +++ b/language-adaptors/rxjava-scala/src/examples/scala/rx/lang/scala/examples/RxScalaDemo.scala @@ -23,8 +23,9 @@ import org.junit.{Before, Test, Ignore} import org.junit.Assert._ import rx.lang.scala.concurrency.NewThreadScheduler import rx.lang.scala.util.Timestamped +import java.io.IOException -//@Ignore // Since this doesn't do automatic testing, don't increase build time unnecessarily +@Ignore // Since this doesn't do automatic testing, don't increase build time unnecessarily class RxScalaDemo extends JUnitSuite { @Test def intervalExample() { @@ -385,13 +386,17 @@ class RxScalaDemo extends JUnitSuite { @Test def materializeExample() { def printObservable[T](o: Observable[T]): Unit = { + import Notification._ for (n <- o.materialize.toBlockingObservable) n match { - case Notification.OnNext[T](v) => println("Got value " + v) - case Notification.OnCompleted[T]() => println("Completed") - case Notification.OnError[T](err) => println("Error: ") - } + case OnNext(v) => println("Got value " + v) + case OnCompleted() => println("Completed") + case OnError(err) => println("Error: " + err.getMessage) + } } - val mat = Observable.interval(100 millis).take(3).materialize + val o1 = Observable.interval(100 millis).take(3) + val o2 = o1 ++ Observable(new IOException("Oops")) + printObservable(o1) + printObservable(o2) } def output(s: String): Unit = println(s) diff --git a/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/Notification.scala b/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/Notification.scala index 30145f27f5..e7789d13a3 100644 --- a/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/Notification.scala +++ b/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/Notification.scala @@ -17,6 +17,9 @@ object Notification { class OnNext[+T](val asJava: rx.Notification[_ <: T]) extends Notification[T] { def value: T = asJava.getValue + } + + object OnNext { def unapply[U](n: Notification[U]): Option[U] = n match { case n2: OnNext[U] => Some(n.asJava.getValue) case _ => None @@ -25,13 +28,18 @@ object Notification { class OnError[+T](val asJava: rx.Notification[_ <: T]) extends Notification[T] { def error: Throwable = asJava.getThrowable() + } + + object OnError { def unapply[U](n: Notification[U]): Option[Throwable] = n match { case n2: OnError[U] => Some(n2.asJava.getThrowable) case _ => None } } - class OnCompleted[T](val asJava: rx.Notification[_ <: T]) extends Notification[T] { + class OnCompleted[T](val asJava: rx.Notification[_ <: T]) extends Notification[T] {} + + object OnCompleted { def unapply[U](n: Notification[U]): Option[Unit] = n match { case n2: OnCompleted[U] => Some() case _ => None From f1a3fb27ee46fc48b4f574fefcf624e00bb8656f Mon Sep 17 00:00:00 2001 From: samuelgruetter Date: Thu, 26 Sep 2013 14:57:46 +0200 Subject: [PATCH 12/33] add rx.lang.scala.concurrency.Schedulers --- .../rx/lang/scala/examples/RxScalaDemo.scala | 6 +- .../lang/scala/concurrency/Schedulers.scala | 61 +++++++++++++++++++ .../rx/lang/scala/concurrency/package.scala | 18 ++---- 3 files changed, 70 insertions(+), 15 deletions(-) create mode 100644 language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/concurrency/Schedulers.scala diff --git a/language-adaptors/rxjava-scala/src/examples/scala/rx/lang/scala/examples/RxScalaDemo.scala b/language-adaptors/rxjava-scala/src/examples/scala/rx/lang/scala/examples/RxScalaDemo.scala index 66be4c51c1..e97e48af36 100644 --- a/language-adaptors/rxjava-scala/src/examples/scala/rx/lang/scala/examples/RxScalaDemo.scala +++ b/language-adaptors/rxjava-scala/src/examples/scala/rx/lang/scala/examples/RxScalaDemo.scala @@ -21,7 +21,7 @@ import rx.lang.scala._ import scala.concurrent.duration._ import org.junit.{Before, Test, Ignore} import org.junit.Assert._ -import rx.lang.scala.concurrency.NewThreadScheduler +import rx.lang.scala.concurrency.Schedulers import rx.lang.scala.util.Timestamped import java.io.IOException @@ -169,10 +169,10 @@ class RxScalaDemo extends JUnitSuite { @Test def schedulersExample() { val o = Observable.interval(100 millis).take(8) - o.observeOn(NewThreadScheduler).subscribe( + o.observeOn(Schedulers.newThread).subscribe( i => println(s"${i}a (on thread #${Thread.currentThread().getId()})") ) - o.observeOn(NewThreadScheduler).subscribe( + o.observeOn(Schedulers.newThread).subscribe( i => println(s"${i}b (on thread #${Thread.currentThread().getId()})") ) waitFor(o) diff --git a/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/concurrency/Schedulers.scala b/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/concurrency/Schedulers.scala new file mode 100644 index 0000000000..290dddfaf9 --- /dev/null +++ b/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/concurrency/Schedulers.scala @@ -0,0 +1,61 @@ +package rx.lang.scala.concurrency + +import rx.Scheduler +import java.util.concurrent.Executor +import java.util.concurrent.ScheduledExecutorService + +/** + * Factory methods for creating Schedulers. + */ +object Schedulers { + + /** + * Returns a [[rx.lang.scala.Scheduler]] that executes work immediately on the current thread. + */ + def immediate: Scheduler = rx.concurrency.Schedulers.immediate() + + /** + * Returns a [[rx.lang.scala.Scheduler]] that queues work on the current thread to be executed after the current work completes. + */ + def currentThread: Scheduler = rx.concurrency.Schedulers.currentThread() + + /** + * Returns a [[rx.lang.scala.Scheduler]] that creates a new {@link Thread} for each unit of work. + */ + def newThread: Scheduler = rx.concurrency.Schedulers.newThread + + /** + * Returns a [[rx.lang.scala.Scheduler]] that queues work on an [[java.util.concurrent.Executor]]. + * + * Note that this does not support scheduled actions with a delay. + */ + def executor(executor: Executor): Scheduler = rx.concurrency.Schedulers.executor(executor) + + /** + * Returns a [[rx.lang.scala.Scheduler]] that queues work on an [[java.util.concurrent.ScheduledExecutorService]]. + */ + def executor(executor: ScheduledExecutorService): Scheduler = rx.concurrency.Schedulers.executor(executor) + + /** + * Returns a [[rx.lang.scala.Scheduler]] intended for computational work. + * + * The implementation is backed by a [[java.util.concurrent.ScheduledExecutorService]] thread-pool sized to the number of CPU cores. + * + * This can be used for event-loops, processing callbacks and other computational work. + * + * Do not perform IO-bound work on this scheduler. Use [[rx.lang.scala.concurrency.Schedulers.threadPoolForIO]] instead. + */ + def threadPoolForComputation: Scheduler = rx.concurrency.Schedulers.threadPoolForComputation() + + /** + * [[rx.lang.scala.Scheduler]] intended for IO-bound work. + * + * The implementation is backed by an [[java.util.concurrent.Executor]] thread-pool that will grow as needed. + * + * This can be used for asynchronously performing blocking IO. + * + * Do not perform computational work on this scheduler. Use [[rx.lang.scala.concurrency.Schedulers.threadPoolForComputation]] instead. + */ + def threadPoolForIO: Scheduler = rx.concurrency.Schedulers.threadPoolForIO() + +} diff --git a/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/concurrency/package.scala b/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/concurrency/package.scala index 9dabd3356b..d787986a06 100644 --- a/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/concurrency/package.scala +++ b/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/concurrency/package.scala @@ -18,17 +18,11 @@ package rx.lang.scala import rx.concurrency.CurrentThreadScheduler package object concurrency { - /* - TODO - rx.concurrency.CurrentThreadScheduler - rx.concurrency.ExecutorScheduler - rx.concurrency.ImmediateScheduler - rx.concurrency.NewThreadScheduler - rx.concurrency.Schedulers - rx.concurrency.TestScheduler - */ + // These classes are not exposed to Scala users, but are accessible through + // rx.lang.scala.concurrency.Schedulers: - lazy val CurrentThreadScheduler = rx.concurrency.CurrentThreadScheduler.getInstance() - lazy val NewThreadScheduler = rx.concurrency.NewThreadScheduler.getInstance() - + // rx.concurrency.CurrentThreadScheduler + // rx.concurrency.ExecutorScheduler + // rx.concurrency.ImmediateScheduler + // rx.concurrency.NewThreadScheduler } \ No newline at end of file From d3f933c0f040b41424c3f3295bd3fa85275ba94c Mon Sep 17 00:00:00 2001 From: samuelgruetter Date: Thu, 26 Sep 2013 17:10:15 +0200 Subject: [PATCH 13/33] improve scaladoc --- language-adaptors/rxjava-scala/README.md | 10 ++---- .../rx/lang/scala/examples/RxScalaDemo.scala | 20 ++++++++--- .../scala/ImplicitFunctionConversions.scala | 8 ++--- .../scala/rx/lang/scala/Notification.scala | 16 +++++++++ .../main/scala/rx/lang/scala/Observable.scala | 14 +++++--- .../lang/scala/concurrency/Schedulers.scala | 8 ++--- .../rx/lang/scala/concurrency/package.scala | 3 ++ .../observables/BlockingObservable.scala | 4 +-- .../rx/lang/scala/observables/package.scala | 8 ++--- .../main/scala/rx/lang/scala/package.scala | 33 +++++++++++-------- .../rx/lang/scala/subjects/package.scala | 3 ++ .../rx/lang/scala/util/Timestamped.scala | 3 ++ .../scala/rx/lang/scala/util/package.scala | 5 ++- 13 files changed, 90 insertions(+), 45 deletions(-) diff --git a/language-adaptors/rxjava-scala/README.md b/language-adaptors/rxjava-scala/README.md index 9cf23dde6e..171e37a5a2 100644 --- a/language-adaptors/rxjava-scala/README.md +++ b/language-adaptors/rxjava-scala/README.md @@ -62,18 +62,12 @@ For more examples, see [RxScalaDemo.scala](https://github.com/Netflix/RxJava/blo Scala code using Rx should only import members from `rx.lang.scala` and below. -Work on this adaptor is still in progress, and for the moment, the best source of documentation are the comments in the source code of [`rx.lang.scala.Observable`](https://github.com/Netflix/RxJava/blob/master/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/Observable.scala). - ## Documentation -You can build the documentation as follows: In the RxJava root directory, run - - ./gradlew :language-adaptors:rxjava-scala:scaladoc - -Then navigate to +You can build the documentation by running `./gradlew scaladoc` in the RxJava root directory. - RxJava/language-adaptors/rxjava-scala/build/docs/scaladoc/index.html +Then navigate to `RxJava/language-adaptors/rxjava-scala/build/docs/scaladoc/index.html` to display it. ## Binaries diff --git a/language-adaptors/rxjava-scala/src/examples/scala/rx/lang/scala/examples/RxScalaDemo.scala b/language-adaptors/rxjava-scala/src/examples/scala/rx/lang/scala/examples/RxScalaDemo.scala index e97e48af36..b383681531 100644 --- a/language-adaptors/rxjava-scala/src/examples/scala/rx/lang/scala/examples/RxScalaDemo.scala +++ b/language-adaptors/rxjava-scala/src/examples/scala/rx/lang/scala/examples/RxScalaDemo.scala @@ -384,19 +384,31 @@ class RxScalaDemo extends JUnitSuite { } } - @Test def materializeExample() { + @Test def materializeExample1() { def printObservable[T](o: Observable[T]): Unit = { import Notification._ - for (n <- o.materialize.toBlockingObservable) n match { + o.materialize.subscribe(n => n match { case OnNext(v) => println("Got value " + v) case OnCompleted() => println("Completed") case OnError(err) => println("Error: " + err.getMessage) - } + }) } + val o1 = Observable.interval(100 millis).take(3) - val o2 = o1 ++ Observable(new IOException("Oops")) + val o2 = Observable(new IOException("Oops")) printObservable(o1) + waitFor(o1) printObservable(o2) + waitFor(o2) + } + + @Test def materializeExample2() { + import Notification._ + Observable(1, 2, 3).materialize.subscribe(n => n match { + case OnNext(v) => println("Got value " + v) + case OnCompleted() => println("Completed") + case OnError(err) => println("Error: " + err.getMessage) + }) } def output(s: String): Unit = println(s) diff --git a/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/ImplicitFunctionConversions.scala b/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/ImplicitFunctionConversions.scala index 78b1d8d776..f28ee5121a 100644 --- a/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/ImplicitFunctionConversions.scala +++ b/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/ImplicitFunctionConversions.scala @@ -19,10 +19,10 @@ import java.{ lang => jlang } import rx.util.functions._ /** - * These function conversions convert between Scala functions and Rx Funcs and Actions. - * Most users RxScala won't need them, but they might be useful if one wants to use - * the rx.Observable directly instead of using rx.lang.scala.Observable or if one wants - * to use a Java library taking/returning Funcs and Actions. + * These function conversions convert between Scala functions and Rx `Func`s and `Action`s. + * Most RxScala users won't need them, but they might be useful if one wants to use + * the `rx.Observable` directly instead of using `rx.lang.scala.Observable` or if one wants + * to use a Java library taking/returning `Func`s and `Action`s. */ object ImplicitFunctionConversions { import language.implicitConversions diff --git a/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/Notification.scala b/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/Notification.scala index e7789d13a3..c659ecdd6b 100644 --- a/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/Notification.scala +++ b/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/Notification.scala @@ -1,9 +1,25 @@ package rx.lang.scala +/** + * Emitted by Observables returned by [[rx.lang.scala.Observable.materialize]]. + */ sealed trait Notification[+T] { def asJava: rx.Notification[_ <: T] } +/** + * Provides pattern matching support for Notifications. + * + * Example: + * {{{ + * import Notification._ + * Observable(1, 2, 3).materialize.subscribe(n => n match { + * case OnNext(v) => println("Got value " + v) + * case OnCompleted() => println("Completed") + * case OnError(err) => println("Error: " + err.getMessage) + * }) + * }}} + */ object Notification { def apply[T](n: rx.Notification[_ <: T]): Notification[T] = n.getKind match { diff --git a/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/Observable.scala b/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/Observable.scala index afa0b59fcd..38a1f4cfd8 100644 --- a/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/Observable.scala +++ b/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/Observable.scala @@ -20,7 +20,7 @@ package rx.lang.scala /** * The Observable interface that implements the Reactive Pattern. */ -class Observable[+T](val asJava: rx.Observable[_ <: T]) +class Observable[+T] private[scala] (val asJava: rx.Observable[_ <: T]) // Uncommenting this line combined with `new Observable(...)` instead of `new Observable[T](...)` // makes the compiler crash extends AnyVal @@ -641,7 +641,8 @@ class Observable[+T](val asJava: rx.Observable[_ <: T]) } /** - *

+ * Returns an Observable which only emits those items for which a given predicate holds. + * * * * @param predicate @@ -1278,7 +1279,7 @@ class Observable[+T](val asJava: rx.Observable[_ <: T]) * @param that * an Observable to be merged * @return an Observable that emits items that are the result of flattening the items emitted by - * {$code this} and {$code that} + * {@code this} and {@code that} */ def mergeDelayError[U >: T](that: Observable[U]): Observable[U] = { Observable[U](rx.Observable.mergeDelayError[U](this.asJava, that.asJava)) @@ -1761,6 +1762,9 @@ class Observable[+T](val asJava: rx.Observable[_ <: T]) } +/** + * Provides various ways to construct new Observables. + */ object Observable { import scala.collection.JavaConverters._ import scala.collection.immutable.Range @@ -1982,7 +1986,7 @@ object Observable { // Cannot yet have inner class because of this error message: // "implementation restriction: nested class is not allowed in value class. // This restriction is planned to be removed in subsequent releases." -class WithFilter[+T] private[scala] (p: T => Boolean, asJava: rx.Observable[_ <: T]) { +private[scala] class WithFilter[+T] (p: T => Boolean, asJava: rx.Observable[_ <: T]) { import rx.lang.scala.ImplicitFunctionConversions._ def map[B](f: T => B): Observable[B] = { @@ -2000,7 +2004,7 @@ class WithFilter[+T] private[scala] (p: T => Boolean, asJava: rx.Observable[_ <: // there is no foreach here, that's only available on BlockingObservable } -class UnitTestSuite extends org.scalatest.junit.JUnitSuite { +private[scala] class UnitTestSuite extends org.scalatest.junit.JUnitSuite { import scala.concurrent.duration._ import org.junit.{Before, Test, Ignore} import org.junit.Assert._ diff --git a/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/concurrency/Schedulers.scala b/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/concurrency/Schedulers.scala index 290dddfaf9..33a77ed132 100644 --- a/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/concurrency/Schedulers.scala +++ b/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/concurrency/Schedulers.scala @@ -25,21 +25,21 @@ object Schedulers { def newThread: Scheduler = rx.concurrency.Schedulers.newThread /** - * Returns a [[rx.lang.scala.Scheduler]] that queues work on an [[java.util.concurrent.Executor]]. + * Returns a [[rx.lang.scala.Scheduler]] that queues work on an `java.util.concurrent.Executor`. * * Note that this does not support scheduled actions with a delay. */ def executor(executor: Executor): Scheduler = rx.concurrency.Schedulers.executor(executor) /** - * Returns a [[rx.lang.scala.Scheduler]] that queues work on an [[java.util.concurrent.ScheduledExecutorService]]. + * Returns a [[rx.lang.scala.Scheduler]] that queues work on an `java.util.concurrent.ScheduledExecutorService`. */ def executor(executor: ScheduledExecutorService): Scheduler = rx.concurrency.Schedulers.executor(executor) /** * Returns a [[rx.lang.scala.Scheduler]] intended for computational work. * - * The implementation is backed by a [[java.util.concurrent.ScheduledExecutorService]] thread-pool sized to the number of CPU cores. + * The implementation is backed by a `java.util.concurrent.ScheduledExecutorService` thread-pool sized to the number of CPU cores. * * This can be used for event-loops, processing callbacks and other computational work. * @@ -50,7 +50,7 @@ object Schedulers { /** * [[rx.lang.scala.Scheduler]] intended for IO-bound work. * - * The implementation is backed by an [[java.util.concurrent.Executor]] thread-pool that will grow as needed. + * The implementation is backed by an `java.util.concurrent.Executor` thread-pool that will grow as needed. * * This can be used for asynchronously performing blocking IO. * diff --git a/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/concurrency/package.scala b/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/concurrency/package.scala index d787986a06..507660c23f 100644 --- a/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/concurrency/package.scala +++ b/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/concurrency/package.scala @@ -17,6 +17,9 @@ package rx.lang.scala import rx.concurrency.CurrentThreadScheduler +/** + * Provides schedulers. + */ package object concurrency { // These classes are not exposed to Scala users, but are accessible through // rx.lang.scala.concurrency.Schedulers: diff --git a/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/observables/BlockingObservable.scala b/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/observables/BlockingObservable.scala index 4be27d0ae0..eb2bb3bf27 100644 --- a/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/observables/BlockingObservable.scala +++ b/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/observables/BlockingObservable.scala @@ -23,7 +23,7 @@ import rx.lang.scala.ImplicitFunctionConversions._ * * You can obtain a BlockingObservable from an Observable using [[Observable.toBlockingObservable]] */ -class BlockingObservable[+T](val asJava: rx.observables.BlockingObservable[_ <: T]) +class BlockingObservable[+T] private[scala] (val asJava: rx.observables.BlockingObservable[_ <: T]) extends AnyVal { @@ -131,7 +131,7 @@ class BlockingObservable[+T](val asJava: rx.observables.BlockingObservable[_ <: // Cannot yet have inner class because of this error message: // "implementation restriction: nested class is not allowed in value class. // This restriction is planned to be removed in subsequent releases." -class WithFilter[+T] private[observables] (p: T => Boolean, asJava: rx.observables.BlockingObservable[_ <: T]) { +private[observables] class WithFilter[+T] (p: T => Boolean, asJava: rx.observables.BlockingObservable[_ <: T]) { import rx.lang.scala.ImplicitFunctionConversions._ // there's no map and flatMap here, they're only available on Observable diff --git a/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/observables/package.scala b/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/observables/package.scala index ae1181321f..8a2241d086 100644 --- a/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/observables/package.scala +++ b/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/observables/package.scala @@ -4,9 +4,9 @@ package rx.lang.scala * Contains special Observables. * * In Scala, this package only contains [[rx.lang.scala.observables.BlockingObservable]]. - * In the corresponding Java package {{{rx.observables}}}, there is also a - * {{{GroupedObservable}}} and a {{{ConnectableObservable}}}, but these are not needed - * in Scala, because we use a pair {{{(key, observable)}}} instead of {{{GroupedObservable}}} - * and a pair {{{(startFunction, observable)}}} instead of {{{ConnectableObservable}}}. + * In the corresponding Java package `rx.observables`, there is also a + * `GroupedObservable` and a `ConnectableObservable`, but these are not needed + * in Scala, because we use a pair `(key, observable)` instead of `GroupedObservable` + * and a pair `(startFunction, observable)` instead of `ConnectableObservable`. */ package object observables {} diff --git a/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/package.scala b/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/package.scala index 04ed0ce6af..220f307961 100644 --- a/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/package.scala +++ b/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/package.scala @@ -15,17 +15,22 @@ */ package rx.lang +import java.util.concurrent.TimeUnit +import java.util.Date -/** - * This object contains aliases to all types Scala users need to import. - * +/* * Note that: - * - Scala users cannot use Java's type with variance without always using writing + * - Scala users cannot use Java's types with variance without always using writing * e.g. rx.Notification[_ <: T], so we create aliases fixing the variance - * - For consistency, we create aliases for all types + * - For consistency, we create aliases for all types which Scala users need + */ + +/** + * This package contains all classes that RxScala users need. + * + * It mirrors the structure of package `rx`, but implementation classes that RxScala users + * will not need are left out. */ -import java.util.concurrent.TimeUnit -import java.util.Date package object scala { /* @@ -45,23 +50,23 @@ package object scala { /** * Provides a mechanism for receiving push-based notifications. * - * After an Observer calls an [[rx.lang.scala.Observable]]'s {{{subscribe}}} method, the Observable - * calls the Observer's {{{onNext}}} method to provide notifications. A well-behaved Observable will - * call an Observer's {{{onCompleted}}} method exactly once or the Observer's {{{onError}}} method exactly once. + * After an Observer calls an [[rx.lang.scala.Observable]]'s `subscribe` method, the Observable + * calls the Observer's `onNext` method to provide notifications. A well-behaved Observable will + * call an Observer's `onCompleted` method exactly once or the Observer's `onError` method exactly once. */ trait Observer[-T] { /** * Notifies the Observer that the [[rx.lang.scala.Observable]] has finished sending push-based notifications. * - * The [[rx.lang.scala.Observable]] will not call this method if it calls {{{onError}}}. + * The [[rx.lang.scala.Observable]] will not call this method if it calls `onError`. */ def onCompleted(): Unit /** * Notifies the Observer that the [[rx.lang.scala.Observable]] has experienced an error condition. * - * If the [[rx.lang.scala.Observable]] calls this method, it will not thereafter call {{{onNext}}} or {{{onCompleted}}}. + * If the [[rx.lang.scala.Observable]] calls this method, it will not thereafter call `onNext` or `onCompleted`. */ def onError(e: Throwable): Unit @@ -70,7 +75,7 @@ package object scala { * * The [[rx.lang.scala.Observable]] calls this closure 0 or more times. * - * The [[rx.lang.scala.Observable]] will not call this method again after it calls either {{{onCompleted}}} or {{{onError}}}. + * The [[rx.lang.scala.Observable]] will not call this method again after it calls either `onCompleted` or `onError`. */ def onNext(arg: T): Unit } @@ -201,6 +206,8 @@ package object scala { def unsubscribe(): Unit } + import language.implicitConversions + private[scala] implicit def fakeSubscription2RxSubscription(s: Subscription): rx.Subscription = new rx.Subscription { def unsubscribe() = s.unsubscribe() diff --git a/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/subjects/package.scala b/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/subjects/package.scala index 22c265aefc..ec096e92eb 100644 --- a/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/subjects/package.scala +++ b/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/subjects/package.scala @@ -1,5 +1,8 @@ package rx.lang.scala +/** + * Provides the type `Subject`. + */ package object subjects { /** diff --git a/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/util/Timestamped.scala b/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/util/Timestamped.scala index 93f2ef2089..e40cc0599b 100644 --- a/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/util/Timestamped.scala +++ b/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/util/Timestamped.scala @@ -15,6 +15,9 @@ class Timestamped[+T](val asJava: rx.util.Timestamped[_ <: T]) extends AnyVal { def value: T = asJava.getValue : T } +/** + * Provides constructor and pattern matching functionality for `Timestamped`. + */ object Timestamped { def apply[T](timestampMillis: Long, value: T): Timestamped[T] = { new Timestamped(new rx.util.Timestamped(timestampMillis, value)) diff --git a/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/util/package.scala b/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/util/package.scala index 1a41f43643..07820f6ea1 100644 --- a/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/util/package.scala +++ b/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/util/package.scala @@ -15,6 +15,9 @@ */ package rx.lang.scala +/** + * Provides [[rx.lang.scala.util.Opening]]s, [[rx.lang.scala.util.Closing]]s, and [[rx.lang.scala.util.Timestamped]]. + */ package object util { /** @@ -43,4 +46,4 @@ package object util { // rx.util.Range not needed because there's a standard Scala Range -} \ No newline at end of file +} From 45d3523058212b24204495b8f2ff6ad10e05aecf Mon Sep 17 00:00:00 2001 From: samuelgruetter Date: Thu, 26 Sep 2013 18:37:20 +0200 Subject: [PATCH 14/33] update README and TODO --- language-adaptors/rxjava-scala/README.md | 4 +++- language-adaptors/rxjava-scala/TODO.md | 4 ---- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/language-adaptors/rxjava-scala/README.md b/language-adaptors/rxjava-scala/README.md index 171e37a5a2..05160e8ad9 100644 --- a/language-adaptors/rxjava-scala/README.md +++ b/language-adaptors/rxjava-scala/README.md @@ -65,7 +65,9 @@ Scala code using Rx should only import members from `rx.lang.scala` and below. ## Documentation -You can build the documentation by running `./gradlew scaladoc` in the RxJava root directory. +The API documentation can be found [here](http://rxscala.github.io/scaladoc/index.html#rx.lang.scala.Observable). + +You can build the API documentation yourself by running `./gradlew scaladoc` in the RxJava root directory. Then navigate to `RxJava/language-adaptors/rxjava-scala/build/docs/scaladoc/index.html` to display it. diff --git a/language-adaptors/rxjava-scala/TODO.md b/language-adaptors/rxjava-scala/TODO.md index d4136236da..4dcf7f2c40 100644 --- a/language-adaptors/rxjava-scala/TODO.md +++ b/language-adaptors/rxjava-scala/TODO.md @@ -4,13 +4,9 @@ TODOs for Scala Adapter This is a (probably incomplete) list of what still needs to be done in the Scala adaptor: -* mirror complete Java package structure in Scala -* objects for classes with static methods or singletons (e.g. Schedulers, Subscriptions) -* Notification as a case class * integrating Scala Futures, should there be a common base interface for Futures and Observables? * Add methods present in Scala collections library, but not in RxJava, e.g. aggregate à la Scala, collect, exists, tails, ... * combineLatest with arities > 2 -* decide where the MovieLib/MovieLibUsage (use Scala code from Java code) example should live and make sure gradle builds it in the right order * Avoid text duplication in scaladoc using templates, add examples, distinction between use case signature and full signature * other small TODOs From af7d056550d3045e59a0b630154fb8ac71f9c836 Mon Sep 17 00:00:00 2001 From: samuelgruetter Date: Fri, 27 Sep 2013 17:08:11 +0200 Subject: [PATCH 15/33] javadoc -> scaladoc translation with the following replacements: \{@link (\w+)#(\w+)\s+(\w+)\} [[$1.$2 $3]] \{@link (\w+)#(\w+)\((.*)\)\} [[$1.$2($3)]] \{@link #(\w+)\} [[Observable.$1]] \{@link (\w+)#(\w+)\} [[$1.$2]] ` ` \*\s*

\s*\n *\n \{@link (\w+)\} [[$1]] \{@link ((\w|\.)+)\} [[$1]] \[\[rx\. [[rx.lang.scala. \{@code\s*(([^}])+)\} `$1` @param <(\w+)> @tparam $1 <(\w+)> [$1] <(\w+)> [$1] "timespan" argument `timespan` argument "timeshift" argument `timeshift` argument \[\[Action0\]\] function plus some manual replacements --- .../main/scala/rx/lang/scala/Observable.scala | 810 +++++++++--------- 1 file changed, 403 insertions(+), 407 deletions(-) diff --git a/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/Observable.scala b/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/Observable.scala index 38a1f4cfd8..310fb78f76 100644 --- a/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/Observable.scala +++ b/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/Observable.scala @@ -36,59 +36,59 @@ class Observable[+T] private[scala] (val asJava: rx.Observable[_ <: T]) import rx.lang.scala.ImplicitFunctionConversions._ /** - * An {@link Observer} must call an Observable's {@code subscribe} method in order to + * An [[Observer]] must call an Observable's `subscribe` method in order to * receive items and notifications from the Observable. * - *

A typical implementation of {@code subscribe} does the following: - *

- * It stores a reference to the Observer in a collection object, such as a {@code List} object. - *

- * It returns a reference to the {@link Subscription} interface. This enables Observers to + * A typical implementation of `subscribe` does the following: + * + * It stores a reference to the Observer in a collection object, such as a `List[T]` object. + * + * It returns a reference to the [[Subscription]] interface. This enables Observers to * unsubscribe, that is, to stop receiving items and notifications before the Observable stops - * sending them, which also invokes the Observer's {@link Observer#onCompleted onCompleted} method. - *

- * An Observable<T> instance is responsible for accepting all subscriptions + * sending them, which also invokes the Observer's [[Observer.onCompleted onCompleted]] method. + * + * An `Observable[T]` instance is responsible for accepting all subscriptions * and notifying all Observers. Unless the documentation for a particular - * Observable<T> implementation indicates otherwise, Observers should make no + * `Observable[T]` implementation indicates otherwise, Observers should make no * assumptions about the order in which multiple Observers will receive their notifications. - *

+ * * * @param observer * the observer - * @return a {@link Subscription} reference with which the {@link Observer} can stop receiving items + * @return a [[Subscription]] reference with which the [[Observer]] can stop receiving items * before the Observable has finished sending them * @throws IllegalArgumentException - * if the {@link Observer} provided as the argument to {@code subscribe()} is {@code null} + * if the [[Observer]] provided as the argument to `subscribe()` is `null` */ def subscribe(observer: Observer[T]): Subscription = { asJava.subscribe(observer) } /** - * An {@link Observer} must call an Observable's {@code subscribe} method in order to + * An [[Observer]] must call an Observable's `subscribe` method in order to * receive items and notifications from the Observable. * - *

A typical implementation of {@code subscribe} does the following: - *

- * It stores a reference to the Observer in a collection object, such as a {@code List} object. - *

- * It returns a reference to the {@link Subscription} interface. This enables Observers to + * A typical implementation of `subscribe` does the following: + * + * It stores a reference to the Observer in a collection object, such as a `List[T]` object. + * + * It returns a reference to the [[Subscription]] interface. This enables Observers to * unsubscribe, that is, to stop receiving items and notifications before the Observable stops - * sending them, which also invokes the Observer's {@link Observer#onCompleted onCompleted} method. - *

- * An {@code Observable} instance is responsible for accepting all subscriptions - * and notifying all Observers. Unless the documentation for a particular {@code Observable} implementation indicates otherwise, Observers should make no + * sending them, which also invokes the Observer's [[Observer.onCompleted onCompleted]] method. + * + * An `Observable[T]` instance is responsible for accepting all subscriptions + * and notifying all Observers. Unless the documentation for a particular `Observable[T]` implementation indicates otherwise, Observers should make no * assumptions about the order in which multiple Observers will receive their notifications. - *

+ * * * @param observer * the observer * @param scheduler - * the {@link Scheduler} on which Observers subscribe to the Observable - * @return a {@link Subscription} reference with which Observers can stop receiving items and + * the [[Scheduler]] on which Observers subscribe to the Observable + * @return a [[Subscription]] reference with which Observers can stop receiving items and * notifications before the Observable has finished sending them * @throws IllegalArgumentException - * if an argument to {@code subscribe()} is {@code null} + * if an argument to `subscribe()` is `null` */ def subscribe(observer: Observer[T], scheduler: Scheduler): Subscription = { asJava.subscribe(observer, scheduler) @@ -119,16 +119,16 @@ class Observable[+T] private[scala] (val asJava: rx.Observable[_ <: T]) } /** - * Returns a {@link ConnectableObservable} that upon connection causes the source Observable to + * Returns a [[ConnectableObservable]] that upon connection causes the source Observable to * push results into the specified subject. * * @param subject - * the {@link Subject} for the {@link ConnectableObservable} to push source items + * the [[Subject]] for the [[ConnectableObservable]] to push source items * into - * @param + * @tparam R * result type - * @return a pair of a start function and an {@link Observable} such that when the start function - * is called, the Observable starts to push results into the specified {@link Subject} + * @return a pair of a start function and an [[Observable]] such that when the start function + * is called, the Observable starts to push results into the specified [[Subject]] */ def multicast[R](subject: Subject[T, R]): (() => Subscription, Observable[R]) = { val javaCO = asJava.multicast[R](subject) @@ -138,7 +138,7 @@ class Observable[+T] private[scala] (val asJava: rx.Observable[_ <: T]) /** * Returns an Observable that first emits the items emitted by this, and then the items emitted * by that. - *

+ * * * * @param that @@ -155,7 +155,7 @@ class Observable[+T] private[scala] (val asJava: rx.Observable[_ <: T]) /** * Returns an Observable that emits the items emitted by two or more Observables, one after the * other. - *

+ * * * * @return an Observable that emits items that are the result of combining the items emitted by @@ -172,27 +172,27 @@ class Observable[+T] private[scala] (val asJava: rx.Observable[_ <: T]) /** * Wraps this Observable in another Observable that ensures that the resulting * Observable is chronologically well-behaved. - *

+ * * - *

- * A well-behaved Observable does not interleave its invocations of the {@link Observer#onNext onNext}, {@link Observer#onCompleted onCompleted}, and {@link Observer#onError onError} methods of - * its {@link Observer}s; it invokes {@code onCompleted} or {@code onError} only once; and it never invokes {@code onNext} after invoking either {@code onCompleted} or {@code onError}. - * {@code synchronize} enforces this, and the Observable it returns invokes {@code onNext} and {@code onCompleted} or {@code onError} synchronously. + * + * A well-behaved Observable does not interleave its invocations of the [[Observer.onNext onNext]], [[Observer.onCompleted onCompleted]], and [[Observer.onError onError]] methods of + * its [[Observer]]s; it invokes `onCompleted` or `onError` only once; and it never invokes `onNext` after invoking either `onCompleted` or `onError`. + * `synchronize` enforces this, and the Observable it returns invokes `onNext` and `onCompleted` or `onError` synchronously. * * @param observable * the source Observable - * @param + * @tparam T * the type of item emitted by the source Observable * @return an Observable that is a chronologically well-behaved version of the source - * Observable, and that synchronously notifies its {@link Observer}s + * Observable, and that synchronously notifies its [[Observer]]s */ def synchronize: Observable[T] = { Observable[T](asJava.synchronize) } /** - * Wraps each item emitted by a source Observable in a {@link Timestamped} object. - *

+ * Wraps each item emitted by a source Observable in a [[Timestamped]] object. + * * * * @return an Observable that emits timestamped items from the source Observable @@ -204,14 +204,14 @@ class Observable[+T] private[scala] (val asJava: rx.Observable[_ <: T]) /** * Returns an Observable formed from this Observable and another Observable by combining * corresponding elements in pairs. - * The number of {@code onNext} invocations of the resulting {@code Observable[(T, U)]} - * is the minumum of the number of {@code onNext} invocations of {@code this} and {@code that}. + * The number of `onNext` invocations of the resulting `Observable[(T, U)]` + * is the minumum of the number of `onNext` invocations of `this` and `that`. */ def zip[U](that: Observable[U]): Observable[(T, U)] = { Observable[(T, U)](JObservable.zip[T, U, (T, U)](this.asJava, that.asJava, (t: T, u: U) => (t, u))) } - // public static Observable zip(Observable> ws, final FuncN zipFunction) { + // public static [R] Observable[R] zip(Observable> ws, final FuncN zipFunction) { /** * Zips this Observable with its indices. @@ -228,17 +228,17 @@ class Observable[+T] private[scala] (val asJava: rx.Observable[_ <: T]) /** * Creates an Observable which produces buffers of collected values. * - *

This Observable produces connected non-overlapping buffers. The current buffer is - * emitted and replaced with a new buffer when the Observable produced by the specified {@link Func0} produces a {@link rx.util.Closing} object. The * {@link Func0} will then + * This Observable produces connected non-overlapping buffers. The current buffer is + * emitted and replaced with a new buffer when the Observable produced by the specified [[Func0]] produces a [[rx.lang.scala.util.Closing]] object. The * [[Func0]] will then * be used to create a new Observable to listen for the end of the next buffer. * * @param bufferClosingSelector - * The {@link Func0} which is used to produce an {@link Observable} for every buffer created. - * When this {@link Observable} produces a {@link rx.util.Closing} object, the associated buffer + * The [[Func0]] which is used to produce an [[Observable]] for every buffer created. + * When this [[Observable]] produces a [[rx.lang.scala.util.Closing]] object, the associated buffer * is emitted and replaced with a new one. * @return - * An {@link Observable} which produces connected non-overlapping buffers, which are emitted - * when the current {@link Observable} created with the {@link Func0} argument produces a {@link rx.util.Closing} object. + * An [[Observable]] which produces connected non-overlapping buffers, which are emitted + * when the current [[Observable]] created with the [[Func0]] argument produces a [[rx.lang.scala.util.Closing]] object. */ def buffer(bufferClosingSelector: () => Observable[Closing]) : Observable[Seq[T]] = { val f: Func0[_ <: rx.Observable[_ <: Closing]] = bufferClosingSelector().asJava @@ -249,20 +249,20 @@ class Observable[+T] private[scala] (val asJava: rx.Observable[_ <: T]) /** * Creates an Observable which produces buffers of collected values. * - *

This Observable produces buffers. Buffers are created when the specified "bufferOpenings" - * Observable produces a {@link rx.util.Opening} object. Additionally the {@link Func0} argument - * is used to create an Observable which produces {@link rx.util.Closing} objects. When this + * This Observable produces buffers. Buffers are created when the specified "bufferOpenings" + * Observable produces a [[rx.lang.scala.util.Opening]] object. Additionally the [[Func0]] argument + * is used to create an Observable which produces [[rx.lang.scala.util.Closing]] objects. When this * Observable produces such an object, the associated buffer is emitted. * * @param bufferOpenings - * The {@link Observable} which, when it produces a {@link rx.util.Opening} object, will cause + * The [[Observable]] which, when it produces a [[rx.lang.scala.util.Opening]] object, will cause * another buffer to be created. * @param bufferClosingSelector - * The {@link Func0} which is used to produce an {@link Observable} for every buffer created. - * When this {@link Observable} produces a {@link rx.util.Closing} object, the associated buffer + * The [[Func0]] which is used to produce an [[Observable]] for every buffer created. + * When this [[Observable]] produces a [[rx.lang.scala.util.Closing]] object, the associated buffer * is emitted. * @return - * An {@link Observable} which produces buffers which are created and emitted when the specified {@link Observable}s publish certain objects. + * An [[Observable]] which produces buffers which are created and emitted when the specified [[Observable]]s publish certain objects. */ def buffer(bufferOpenings: Observable[Opening], bufferClosingSelector: Opening => Observable[Closing]): Observable[Seq[T]] = { val opening: rx.Observable[_ <: Opening] = bufferOpenings.asJava @@ -274,14 +274,14 @@ class Observable[+T] private[scala] (val asJava: rx.Observable[_ <: T]) /** * Creates an Observable which produces buffers of collected values. * - *

This Observable produces connected non-overlapping buffers, each containing "count" + * This Observable produces connected non-overlapping buffers, each containing "count" * elements. When the source Observable completes or encounters an error, the current * buffer is emitted, and the event is propagated. * * @param count * The maximum size of each buffer before it should be emitted. * @return - * An {@link Observable} which produces connected non-overlapping buffers containing at most + * An [[Observable]] which produces connected non-overlapping buffers containing at most * "count" produced values. */ def buffer(count: Int): Observable[Seq[T]] = { @@ -292,7 +292,7 @@ class Observable[+T] private[scala] (val asJava: rx.Observable[_ <: T]) /** * Creates an Observable which produces buffers of collected values. * - *

This Observable produces buffers every "skip" values, each containing "count" + * This Observable produces buffers every "skip" values, each containing "count" * elements. When the source Observable completes or encounters an error, the current * buffer is emitted, and the event is propagated. * @@ -300,9 +300,9 @@ class Observable[+T] private[scala] (val asJava: rx.Observable[_ <: T]) * The maximum size of each buffer before it should be emitted. * @param skip * How many produced values need to be skipped before starting a new buffer. Note that when "skip" and - * "count" are equals that this is the same operation as {@link Observable#buffer(int)}. + * "count" are equals that this is the same operation as [[Observable.buffer(int)]]. * @return - * An {@link Observable} which produces buffers every "skipped" values containing at most + * An [[Observable]] which produces buffers every "skipped" values containing at most * "count" produced values. */ def buffer(count: Int, skip: Int): Observable[Seq[T]] = { @@ -313,15 +313,15 @@ class Observable[+T] private[scala] (val asJava: rx.Observable[_ <: T]) /** * Creates an Observable which produces buffers of collected values. * - *

This Observable produces connected non-overlapping buffers, each of a fixed duration - * specified by the "timespan" argument. When the source Observable completes or encounters + * This Observable produces connected non-overlapping buffers, each of a fixed duration + * specified by the `timespan` argument. When the source Observable completes or encounters * an error, the current buffer is emitted and the event is propagated. * * @param timespan * The period of time each buffer is collecting values before it should be emitted, and * replaced with a new buffer. * @return - * An {@link Observable} which produces connected non-overlapping buffers with a fixed duration. + * An [[Observable]] which produces connected non-overlapping buffers with a fixed duration. */ def buffer(timespan: Duration): Observable[Seq[T]] = { val oJava: rx.Observable[_ <: java.util.List[_]] = asJava.buffer(timespan.length, timespan.unit) @@ -331,17 +331,17 @@ class Observable[+T] private[scala] (val asJava: rx.Observable[_ <: T]) /** * Creates an Observable which produces buffers of collected values. * - *

This Observable produces connected non-overlapping buffers, each of a fixed duration - * specified by the "timespan" argument. When the source Observable completes or encounters + * This Observable produces connected non-overlapping buffers, each of a fixed duration + * specified by the `timespan` argument. When the source Observable completes or encounters * an error, the current buffer is emitted and the event is propagated. * * @param timespan * The period of time each buffer is collecting values before it should be emitted, and * replaced with a new buffer. * @param scheduler - * The {@link Scheduler} to use when determining the end and start of a buffer. + * The [[Scheduler]] to use when determining the end and start of a buffer. * @return - * An {@link Observable} which produces connected non-overlapping buffers with a fixed duration. + * An [[Observable]] which produces connected non-overlapping buffers with a fixed duration. */ def buffer(timespan: Duration, scheduler: Scheduler): Observable[Seq[T]] = { val oJava: rx.Observable[_ <: java.util.List[_]] = asJava.buffer(timespan.length, timespan.unit, scheduler) @@ -350,7 +350,7 @@ class Observable[+T] private[scala] (val asJava: rx.Observable[_ <: T]) /** * Creates an Observable which produces buffers of collected values. This Observable produces connected - * non-overlapping buffers, each of a fixed duration specified by the "timespan" argument or a maximum size + * non-overlapping buffers, each of a fixed duration specified by the `timespan` argument or a maximum size * specified by the "count" argument (which ever is reached first). When the source Observable completes * or encounters an error, the current buffer is emitted and the event is propagated. * @@ -360,7 +360,7 @@ class Observable[+T] private[scala] (val asJava: rx.Observable[_ <: T]) * @param count * The maximum size of each buffer before it should be emitted. * @return - * An {@link Observable} which produces connected non-overlapping buffers which are emitted after + * An [[Observable]] which produces connected non-overlapping buffers which are emitted after * a fixed duration or when the buffer has reached maximum capacity (which ever occurs first). */ def buffer(timespan: Duration, count: Int): Observable[Seq[T]] = { @@ -370,7 +370,7 @@ class Observable[+T] private[scala] (val asJava: rx.Observable[_ <: T]) /** * Creates an Observable which produces buffers of collected values. This Observable produces connected - * non-overlapping buffers, each of a fixed duration specified by the "timespan" argument or a maximum size + * non-overlapping buffers, each of a fixed duration specified by the `timespan` argument or a maximum size * specified by the "count" argument (which ever is reached first). When the source Observable completes * or encounters an error, the current buffer is emitted and the event is propagated. * @@ -380,9 +380,9 @@ class Observable[+T] private[scala] (val asJava: rx.Observable[_ <: T]) * @param count * The maximum size of each buffer before it should be emitted. * @param scheduler - * The {@link Scheduler} to use when determining the end and start of a buffer. + * The [[Scheduler]] to use when determining the end and start of a buffer. * @return - * An {@link Observable} which produces connected non-overlapping buffers which are emitted after + * An [[Observable]] which produces connected non-overlapping buffers which are emitted after * a fixed duration or when the buffer has reached maximum capacity (which ever occurs first). */ def buffer(timespan: Duration, count: Int, scheduler: Scheduler): Observable[Seq[T]] = { @@ -392,8 +392,8 @@ class Observable[+T] private[scala] (val asJava: rx.Observable[_ <: T]) /** * Creates an Observable which produces buffers of collected values. This Observable starts a new buffer - * periodically, which is determined by the "timeshift" argument. Each buffer is emitted after a fixed timespan - * specified by the "timespan" argument. When the source Observable completes or encounters an error, the + * periodically, which is determined by the `timeshift` argument. Each buffer is emitted after a fixed timespan + * specified by the `timespan` argument. When the source Observable completes or encounters an error, the * current buffer is emitted and the event is propagated. * * @param timespan @@ -401,7 +401,7 @@ class Observable[+T] private[scala] (val asJava: rx.Observable[_ <: T]) * @param timeshift * The period of time after which a new buffer will be created. * @return - * An {@link Observable} which produces new buffers periodically, and these are emitted after + * An [[Observable]] which produces new buffers periodically, and these are emitted after * a fixed timespan has elapsed. */ def buffer(timespan: Duration, timeshift: Duration): Observable[Seq[T]] = { @@ -414,8 +414,8 @@ class Observable[+T] private[scala] (val asJava: rx.Observable[_ <: T]) /** * Creates an Observable which produces buffers of collected values. This Observable starts a new buffer - * periodically, which is determined by the "timeshift" argument. Each buffer is emitted after a fixed timespan - * specified by the "timespan" argument. When the source Observable completes or encounters an error, the + * periodically, which is determined by the `timeshift` argument. Each buffer is emitted after a fixed timespan + * specified by the `timespan` argument. When the source Observable completes or encounters an error, the * current buffer is emitted and the event is propagated. * * @param timespan @@ -423,9 +423,9 @@ class Observable[+T] private[scala] (val asJava: rx.Observable[_ <: T]) * @param timeshift * The period of time after which a new buffer will be created. * @param scheduler - * The {@link Scheduler} to use when determining the end and start of a buffer. + * The [[Scheduler]] to use when determining the end and start of a buffer. * @return - * An {@link Observable} which produces new buffers periodically, and these are emitted after + * An [[Observable]] which produces new buffers periodically, and these are emitted after * a fixed timespan has elapsed. */ def buffer(timespan: Duration, timeshift: Duration, scheduler: Scheduler): Observable[Seq[T]] = { @@ -439,16 +439,16 @@ class Observable[+T] private[scala] (val asJava: rx.Observable[_ <: T]) /** * Creates an Observable which produces windows of collected values. This Observable produces connected * non-overlapping windows. The current window is emitted and replaced with a new window when the - * Observable produced by the specified {@link Func0} produces a {@link rx.util.Closing} object. The {@link Func0} will then be used to create a new Observable to listen for the end of the next + * Observable produced by the specified [[Func0]] produces a [[rx.lang.scala.util.Closing]] object. The [[Func0]] will then be used to create a new Observable to listen for the end of the next * window. * * @param closingSelector - * The {@link Func0} which is used to produce an {@link Observable} for every window created. - * When this {@link Observable} produces a {@link rx.util.Closing} object, the associated window + * The [[Func0]] which is used to produce an [[Observable]] for every window created. + * When this [[Observable]] produces a [[rx.lang.scala.util.Closing]] object, the associated window * is emitted and replaced with a new one. * @return - * An {@link Observable} which produces connected non-overlapping windows, which are emitted - * when the current {@link Observable} created with the {@link Func0} argument produces a {@link rx.util.Closing} object. + * An [[Observable]] which produces connected non-overlapping windows, which are emitted + * when the current [[Observable]] created with the [[Func0]] argument produces a [[rx.lang.scala.util.Closing]] object. */ def window(closingSelector: () => Observable[Closing]): Observable[Observable[T]] = { val func : Func0[_ <: rx.Observable[_ <: Closing]] = closingSelector().asJava @@ -462,19 +462,19 @@ class Observable[+T] private[scala] (val asJava: rx.Observable[_ <: T]) /** * Creates an Observable which produces windows of collected values. This Observable produces windows. - * Chunks are created when the specified "windowOpenings" Observable produces a {@link rx.util.Opening} object. - * Additionally the {@link Func0} argument is used to create an Observable which produces {@link rx.util.Closing} objects. When this Observable produces such an object, the associated window is + * Chunks are created when the specified "windowOpenings" Observable produces a [[rx.lang.scala.util.Opening]] object. + * Additionally the [[Func0]] argument is used to create an Observable which produces [[rx.lang.scala.util.Closing]] objects. When this Observable produces such an object, the associated window is * emitted. * * @param windowOpenings - * The {@link Observable} which when it produces a {@link rx.util.Opening} object, will cause + * The [[Observable]] which when it produces a [[rx.lang.scala.util.Opening]] object, will cause * another window to be created. * @param closingSelector - * The {@link Func0} which is used to produce an {@link Observable} for every window created. - * When this {@link Observable} produces a {@link rx.util.Closing} object, the associated window + * The [[Func0]] which is used to produce an [[Observable]] for every window created. + * When this [[Observable]] produces a [[rx.lang.scala.util.Closing]] object, the associated window * is emitted. * @return - * An {@link Observable} which produces windows which are created and emitted when the specified {@link Observable}s publish certain objects. + * An [[Observable]] which produces windows which are created and emitted when the specified [[Observable]]s publish certain objects. */ def window(windowOpenings: Observable[Opening], closingSelector: Opening => Observable[Closing]) = { Observable.jObsOfJObsToScObsOfScObs( @@ -490,7 +490,7 @@ class Observable[+T] private[scala] (val asJava: rx.Observable[_ <: T]) * @param count * The maximum size of each window before it should be emitted. * @return - * An {@link Observable} which produces connected non-overlapping windows containing at most + * An [[Observable]] which produces connected non-overlapping windows containing at most * "count" produced values. */ def window(count: Int): Observable[Observable[T]] = { @@ -508,9 +508,9 @@ class Observable[+T] private[scala] (val asJava: rx.Observable[_ <: T]) * The maximum size of each window before it should be emitted. * @param skip * How many produced values need to be skipped before starting a new window. Note that when "skip" and - * "count" are equals that this is the same operation as {@link Observable#window(Observable, int)}. + * "count" are equals that this is the same operation as [[Observable.window(Observable, int)]]. * @return - * An {@link Observable} which produces windows every "skipped" values containing at most + * An [[Observable]] which produces windows every "skipped" values containing at most * "count" produced values. */ def window(count: Int, skip: Int): Observable[Observable[T]] = { @@ -520,14 +520,14 @@ class Observable[+T] private[scala] (val asJava: rx.Observable[_ <: T]) /** * Creates an Observable which produces windows of collected values. This Observable produces connected - * non-overlapping windows, each of a fixed duration specified by the "timespan" argument. When the source + * non-overlapping windows, each of a fixed duration specified by the `timespan` argument. When the source * Observable completes or encounters an error, the current window is emitted and the event is propagated. * * @param timespan * The period of time each window is collecting values before it should be emitted, and * replaced with a new window. * @return - * An {@link Observable} which produces connected non-overlapping windows with a fixed duration. + * An [[Observable]] which produces connected non-overlapping windows with a fixed duration. */ def window(timespan: Duration): Observable[Observable[T]] = { Observable.jObsOfJObsToScObsOfScObs(asJava.window(timespan.length, timespan.unit)) @@ -536,16 +536,16 @@ class Observable[+T] private[scala] (val asJava: rx.Observable[_ <: T]) /** * Creates an Observable which produces windows of collected values. This Observable produces connected - * non-overlapping windows, each of a fixed duration specified by the "timespan" argument. When the source + * non-overlapping windows, each of a fixed duration specified by the `timespan` argument. When the source * Observable completes or encounters an error, the current window is emitted and the event is propagated. * * @param timespan * The period of time each window is collecting values before it should be emitted, and * replaced with a new window. * @param scheduler - * The {@link Scheduler} to use when determining the end and start of a window. + * The [[Scheduler]] to use when determining the end and start of a window. * @return - * An {@link Observable} which produces connected non-overlapping windows with a fixed duration. + * An [[Observable]] which produces connected non-overlapping windows with a fixed duration. */ def window(timespan: Duration, scheduler: Scheduler): Observable[Observable[T]] = { Observable.jObsOfJObsToScObsOfScObs(asJava.window(timespan.length, timespan.unit, scheduler)) @@ -554,7 +554,7 @@ class Observable[+T] private[scala] (val asJava: rx.Observable[_ <: T]) /** * Creates an Observable which produces windows of collected values. This Observable produces connected - * non-overlapping windows, each of a fixed duration specified by the "timespan" argument or a maximum size + * non-overlapping windows, each of a fixed duration specified by the `timespan` argument or a maximum size * specified by the "count" argument (which ever is reached first). When the source Observable completes * or encounters an error, the current window is emitted and the event is propagated. * @@ -564,7 +564,7 @@ class Observable[+T] private[scala] (val asJava: rx.Observable[_ <: T]) * @param count * The maximum size of each window before it should be emitted. * @return - * An {@link Observable} which produces connected non-overlapping windows which are emitted after + * An [[Observable]] which produces connected non-overlapping windows which are emitted after * a fixed duration or when the window has reached maximum capacity (which ever occurs first). */ def window(timespan: Duration, count: Int): Observable[Observable[T]] = { @@ -574,7 +574,7 @@ class Observable[+T] private[scala] (val asJava: rx.Observable[_ <: T]) /** * Creates an Observable which produces windows of collected values. This Observable produces connected - * non-overlapping windows, each of a fixed duration specified by the "timespan" argument or a maximum size + * non-overlapping windows, each of a fixed duration specified by the `timespan` argument or a maximum size * specified by the "count" argument (which ever is reached first). When the source Observable completes * or encounters an error, the current window is emitted and the event is propagated. * @@ -584,9 +584,9 @@ class Observable[+T] private[scala] (val asJava: rx.Observable[_ <: T]) * @param count * The maximum size of each window before it should be emitted. * @param scheduler - * The {@link Scheduler} to use when determining the end and start of a window. + * The [[Scheduler]] to use when determining the end and start of a window. * @return - * An {@link Observable} which produces connected non-overlapping windows which are emitted after + * An [[Observable]] which produces connected non-overlapping windows which are emitted after * a fixed duration or when the window has reached maximum capacity (which ever occurs first). */ def window(timespan: Duration, count: Int, scheduler: Scheduler): Observable[Observable[T]] = { @@ -596,8 +596,8 @@ class Observable[+T] private[scala] (val asJava: rx.Observable[_ <: T]) /** * Creates an Observable which produces windows of collected values. This Observable starts a new window - * periodically, which is determined by the "timeshift" argument. Each window is emitted after a fixed timespan - * specified by the "timespan" argument. When the source Observable completes or encounters an error, the + * periodically, which is determined by the `timeshift` argument. Each window is emitted after a fixed timespan + * specified by the `timespan` argument. When the source Observable completes or encounters an error, the * current window is emitted and the event is propagated. * * @param timespan @@ -605,7 +605,7 @@ class Observable[+T] private[scala] (val asJava: rx.Observable[_ <: T]) * @param timeshift * The period of time after which a new window will be created. * @return - * An {@link Observable} which produces new windows periodically, and these are emitted after + * An [[Observable]] which produces new windows periodically, and these are emitted after * a fixed timespan has elapsed. */ def window(timespan: Duration, timeshift: Duration): Observable[Observable[T]] = { @@ -618,8 +618,8 @@ class Observable[+T] private[scala] (val asJava: rx.Observable[_ <: T]) /** * Creates an Observable which produces windows of collected values. This Observable starts a new window - * periodically, which is determined by the "timeshift" argument. Each window is emitted after a fixed timespan - * specified by the "timespan" argument. When the source Observable completes or encounters an error, the + * periodically, which is determined by the `timeshift` argument. Each window is emitted after a fixed timespan + * specified by the `timespan` argument. When the source Observable completes or encounters an error, the * current window is emitted and the event is propagated. * * @param timespan @@ -627,9 +627,9 @@ class Observable[+T] private[scala] (val asJava: rx.Observable[_ <: T]) * @param timeshift * The period of time after which a new window will be created. * @param scheduler - * The {@link Scheduler} to use when determining the end and start of a window. + * The [[Scheduler]] to use when determining the end and start of a window. * @return - * An {@link Observable} which produces new windows periodically, and these are emitted after + * An [[Observable]] which produces new windows periodically, and these are emitted after * a fixed timespan has elapsed. */ def window(timespan: Duration, timeshift: Duration, scheduler: Scheduler): Observable[Observable[T]] = { @@ -646,22 +646,22 @@ class Observable[+T] private[scala] (val asJava: rx.Observable[_ <: T]) * * * @param predicate - * a function that evaluates the items emitted by the source Observable, returning {@code true} if they pass the filter + * a function that evaluates the items emitted by the source Observable, returning `true` if they pass the filter * @return an Observable that emits only those items in the original Observable that the filter - * evaluates as {@code true} + * evaluates as `true` */ def filter(predicate: T => Boolean): Observable[T] = { Observable[T](asJava.filter(predicate)) } /** - * Registers an {@link Action0} to be called when this Observable invokes {@link Observer#onCompleted onCompleted} or {@link Observer#onError onError}. - *

+ * Registers an function to be called when this Observable invokes [[Observer.onCompleted onCompleted]] or [[Observer.onError onError]]. + * * * * @param action - * an {@link Action0} to be invoked when the source Observable finishes - * @return an Observable that emits the same items as the source Observable, then invokes the {@link Action0} + * an function to be invoked when the source Observable finishes + * @return an Observable that emits the same items as the source Observable, then invokes the function * @see MSDN: Observable.Finally Method */ def finallyDo(action: () => Unit): Observable[T] = { @@ -672,10 +672,8 @@ class Observable[+T] private[scala] (val asJava: rx.Observable[_ <: T]) * Creates a new Observable by applying a function that you supply to each item emitted by * the source Observable, where that function returns an Observable, and then merging those * resulting Observables and emitting the results of this merger. - *

+ * * - *

- * Note: {@code mapMany} and {@code flatMap} are equivalent. * * @param func * a function that, when applied to an item emitted by the source Observable, returns @@ -683,7 +681,6 @@ class Observable[+T] private[scala] (val asJava: rx.Observable[_ <: T]) * @return an Observable that emits the result of applying the transformation function to each * item emitted by the source Observable and merging the results of the Observables * obtained from this transformation. - * @see #mapMany(Func1) */ def flatMap[R](f: T => Observable[R]): Observable[R] = { Observable[R](asJava.flatMap[R]((t: T) => f(t).asJava)) @@ -692,7 +689,7 @@ class Observable[+T] private[scala] (val asJava: rx.Observable[_ <: T]) /** * Returns an Observable that applies the given function to each item emitted by an * Observable and emits the result. - *

+ * * * * @param func @@ -705,8 +702,8 @@ class Observable[+T] private[scala] (val asJava: rx.Observable[_ <: T]) } /** - * Turns all of the notifications from a source Observable into {@link Observer#onNext onNext} emissions, and marks them with their original notification types within {@link Notification} objects. - *

+ * Turns all of the notifications from a source Observable into [[Observer.onNext onNext]] emissions, and marks them with their original notification types within [[Notification]] objects. + * * * * @return an Observable whose items are the result of materializing the items and @@ -718,41 +715,41 @@ class Observable[+T] private[scala] (val asJava: rx.Observable[_ <: T]) } /** - * Asynchronously subscribes and unsubscribes Observers on the specified {@link Scheduler}. - *

+ * Asynchronously subscribes and unsubscribes Observers on the specified [[Scheduler]]. + * * * * @param scheduler - * the {@link Scheduler} to perform subscription and unsubscription actions on + * the [[Scheduler]] to perform subscription and unsubscription actions on * @return the source Observable modified so that its subscriptions and unsubscriptions happen - * on the specified {@link Scheduler} + * on the specified [[Scheduler]] */ def subscribeOn(scheduler: Scheduler): Observable[T] = { Observable[T](asJava.subscribeOn(scheduler)) } /** - * Asynchronously notify {@link Observer}s on the specified {@link Scheduler}. - *

+ * Asynchronously notify [[Observer]]s on the specified [[Scheduler]]. + * * * * @param scheduler - * the {@link Scheduler} to notify {@link Observer}s on - * @return the source Observable modified so that its {@link Observer}s are notified on the - * specified {@link Scheduler} + * the [[Scheduler]] to notify [[Observer]]s on + * @return the source Observable modified so that its [[Observer]]s are notified on the + * specified [[Scheduler]] */ def observeOn(scheduler: Scheduler): Observable[T] = { Observable[T](asJava.observeOn(scheduler)) } /** - * Returns an Observable that reverses the effect of {@link #materialize materialize} by - * transforming the {@link Notification} objects emitted by the source Observable into the items + * Returns an Observable that reverses the effect of [[Observable.materialize]] by + * transforming the [[Notification]] objects emitted by the source Observable into the items * or notifications they represent. - *

+ * * * - * @return an Observable that emits the items and notifications embedded in the {@link Notification} objects emitted by the source Observable + * @return an Observable that emits the items and notifications embedded in the [[Notification]] objects emitted by the source Observable */ // with =:= it does not work, why? def dematerialize[U](implicit evidence: Observable[T] <:< Observable[Notification[U]]): Observable[U] = { @@ -763,21 +760,21 @@ class Observable[+T] private[scala] (val asJava: rx.Observable[_ <: T]) } /** - * Instruct an Observable to pass control to another Observable rather than invoking {@link Observer#onError onError} if it encounters an error. - *

+ * Instruct an Observable to pass control to another Observable rather than invoking [[Observer.onError onError]] if it encounters an error. + * * - *

+ * * By default, when an Observable encounters an error that prevents it from emitting the - * expected item to its {@link Observer}, the Observable invokes its Observer's - * onError method, and then quits without invoking any more of its Observer's - * methods. The onErrorResumeNext method changes this behavior. If you pass a - * function that returns an Observable (resumeFunction) to - * onErrorResumeNext, if the original Observable encounters an error, instead of - * invoking its Observer's onError method, it will instead relinquish control to - * the Observable returned from resumeFunction, which will invoke the Observer's {@link Observer#onNext onNext} method if it is able to do so. In such a case, because no - * Observable necessarily invokes onError, the Observer may never know that an + * expected item to its [[Observer]], the Observable invokes its Observer's + * `onError` method, and then quits without invoking any more of its Observer's + * methods. The `onErrorResumeNext` method changes this behavior. If you pass a + * function that returns an Observable (`resumeFunction`) to + * `onErrorResumeNext`, if the original Observable encounters an error, instead of + * invoking its Observer's `onError` method, it will instead relinquish control to + * the Observable returned from `resumeFunction`, which will invoke the Observer's [[Observer.onNext onNext]] method if it is able to do so. In such a case, because no + * Observable necessarily invokes `onError`, the Observer may never know that an * error happened. - *

+ * * You can use this to prevent errors from propagating or to supply fallback data should errors * be encountered. * @@ -793,21 +790,21 @@ class Observable[+T] private[scala] (val asJava: rx.Observable[_ <: T]) } /** - * Instruct an Observable to pass control to another Observable rather than invoking {@link Observer#onError onError} if it encounters an error. - *

+ * Instruct an Observable to pass control to another Observable rather than invoking [[Observer.onError onError]] if it encounters an error. + * * - *

+ * * By default, when an Observable encounters an error that prevents it from emitting the - * expected item to its {@link Observer}, the Observable invokes its Observer's - * onError method, and then quits without invoking any more of its Observer's - * methods. The onErrorResumeNext method changes this behavior. If you pass - * another Observable (resumeSequence) to an Observable's - * onErrorResumeNext method, if the original Observable encounters an error, - * instead of invoking its Observer's onError method, it will instead relinquish - * control to resumeSequence which will invoke the Observer's {@link Observer#onNext onNext} method if it is able to do so. In such a case, because no - * Observable necessarily invokes onError, the Observer may never know that an + * expected item to its [[Observer]], the Observable invokes its Observer's + * `onError` method, and then quits without invoking any more of its Observer's + * methods. The `onErrorResumeNext` method changes this behavior. If you pass + * another Observable (`resumeSequence`) to an Observable's + * `onErrorResumeNext` method, if the original Observable encounters an error, + * instead of invoking its Observer's `onError` method, it will instead relinquish + * control to `resumeSequence` which will invoke the Observer's [[Observer.onNext onNext]] method if it is able to do so. In such a case, because no + * Observable necessarily invokes `onError`, the Observer may never know that an * error happened. - *

+ * * You can use this to prevent errors from propagating or to supply fallback data should errors * be encountered. * @@ -823,23 +820,23 @@ class Observable[+T] private[scala] (val asJava: rx.Observable[_ <: T]) } /** - * Instruct an Observable to pass control to another Observable rather than invoking {@link Observer#onError onError} if it encounters an error of type {@link java.lang.Exception}. - *

- * This differs from {@link #onErrorResumeNext} in that this one does not handle {@link java.lang.Throwable} or {@link java.lang.Error} but lets those continue through. - *

+ * Instruct an Observable to pass control to another Observable rather than invoking [[Observer.onError onError]] if it encounters an error of type [[java.lang.Exception]]. + * + * This differs from [[Observable.onErrorResumeNext]] in that this one does not handle [[java.lang.Throwable]] or [[java.lang.Error]] but lets those continue through. + * * - *

+ * * By default, when an Observable encounters an error that prevents it from emitting the - * expected item to its {@link Observer}, the Observable invokes its Observer's - * onError method, and then quits without invoking any more of its Observer's - * methods. The onErrorResumeNext method changes this behavior. If you pass - * another Observable (resumeSequence) to an Observable's - * onErrorResumeNext method, if the original Observable encounters an error, - * instead of invoking its Observer's onError method, it will instead relinquish - * control to resumeSequence which will invoke the Observer's {@link Observer#onNext onNext} method if it is able to do so. In such a case, because no - * Observable necessarily invokes onError, the Observer may never know that an + * expected item to its [[Observer]], the Observable invokes its Observer's + * `onError` method, and then quits without invoking any more of its Observer's + * methods. The `onErrorResumeNext` method changes this behavior. If you pass + * another Observable (`resumeSequence`) to an Observable's + * `onErrorResumeNext` method, if the original Observable encounters an error, + * instead of invoking its Observer's `onError` method, it will instead relinquish + * control to `resumeSequence` which will invoke the Observer's [[Observer.onNext onNext]] method if it is able to do so. In such a case, because no + * Observable necessarily invokes `onError`, the Observer may never know that an * error happened. - *

+ * * You can use this to prevent errors from propagating or to supply fallback data should errors * be encountered. * @@ -856,19 +853,19 @@ class Observable[+T] private[scala] (val asJava: rx.Observable[_ <: T]) /** * Instruct an Observable to emit an item (returned by a specified function) rather than - * invoking {@link Observer#onError onError} if it encounters an error. - *

+ * invoking [[Observer.onError onError]] if it encounters an error. + * * - *

+ * * By default, when an Observable encounters an error that prevents it from emitting the - * expected item to its {@link Observer}, the Observable invokes its Observer's - * onError method, and then quits without invoking any more of its Observer's - * methods. The onErrorReturn method changes this behavior. If you pass a function - * (resumeFunction) to an Observable's onErrorReturn method, if the + * expected item to its [[Observer]], the Observable invokes its Observer's + * `onError` method, and then quits without invoking any more of its Observer's + * methods. The `onErrorReturn` method changes this behavior. If you pass a function + * (`resumeFunction`) to an Observable's `onErrorReturn` method, if the * original Observable encounters an error, instead of invoking its Observer's - * onError method, it will instead pass the return value of - * resumeFunction to the Observer's {@link Observer#onNext onNext} method. - *

+ * `onError` method, it will instead pass the return value of + * `resumeFunction` to the Observer's [[Observer.onNext onNext]] method. + * * You can use this to prevent errors from propagating or to supply fallback data should errors * be encountered. * @@ -889,12 +886,12 @@ class Observable[+T] private[scala] (val asJava: rx.Observable[_ <: T]) * by the source Observable into the same function, and so on until all items have been emitted * by the source Observable, and emits the final result from the final call to your function as * its sole item. - *

+ * * - *

+ * * This technique, which is called "reduce" or "aggregate" here, is sometimes called "fold," * "accumulate," "compress," or "inject" in other programming contexts. Groovy, for instance, - * has an inject method that does a similar operation on lists. + * has an `inject` method that does a similar operation on lists. * * @param accumulator * An accumulator function to be invoked on each item emitted by the source @@ -911,13 +908,13 @@ class Observable[+T] private[scala] (val asJava: rx.Observable[_ <: T]) } /** - * Returns a {@link ConnectableObservable} that shares a single subscription to the underlying - * Observable that will replay all of its items and notifications to any future {@link Observer}. - *

+ * Returns a [[ConnectableObservable]] that shares a single subscription to the underlying + * Observable that will replay all of its items and notifications to any future [[Observer]]. + * * * - * @return a pair of a start function and an {@link Observable} such that when the start function - * is called, the Observable starts to emit items to its {@link Observer}s + * @return a pair of a start function and an [[Observable]] such that when the start function + * is called, the Observable starts to emit items to its [[Observer]]s */ def replay: (() => Subscription, Observable[T]) = { val javaCO = asJava.replay() @@ -925,16 +922,16 @@ class Observable[+T] private[scala] (val asJava: rx.Observable[_ <: T]) } /** - * This method has similar behavior to {@link #replay} except that this auto-subscribes to - * the source Observable rather than returning a {@link ConnectableObservable}. - *

+ * This method has similar behavior to [[Observable.replay]] except that this auto-subscribes to + * the source Observable rather than returning a [[ConnectableObservable]]. + * * - *

+ * * This is useful when you want an Observable to cache responses and you can't control the - * subscribe/unsubscribe behavior of all the {@link Observer}s. - *

+ * subscribe/unsubscribe behavior of all the [[Observer]]s. + * * NOTE: You sacrifice the ability to unsubscribe from the origin when you use the - * cache() operator so be careful not to use this operator on Observables that + * `cache()` operator so be careful not to use this operator on Observables that * emit an infinite or very large number of items that will use up memory. * * @return an Observable that when first subscribed to, caches all of its notifications for @@ -945,13 +942,13 @@ class Observable[+T] private[scala] (val asJava: rx.Observable[_ <: T]) } /** - * Returns a {@link ConnectableObservable}, which waits until its {@link ConnectableObservable#connect connect} method is called before it begins emitting - * items to those {@link Observer}s that have subscribed to it. - *

+ * Returns a [[ConnectableObservable]], which waits until its [[ConnectableObservable.connect connect]] method is called before it begins emitting + * items to those [[Observer]]s that have subscribed to it. + * * * - * @return a pair of a start function and an {@link Observable} such that when the start function - * is called, the Observable starts to emit items to its {@link Observer}s + * @return a pair of a start function and an [[Observable]] such that when the start function + * is called, the Observable starts to emit items to its [[Observer]]s */ def publish: (() => Subscription, Observable[T]) = { val javaCO = asJava.publish() @@ -966,12 +963,12 @@ class Observable[+T] private[scala] (val asJava: rx.Observable[_ <: T]) * by an Observable into the same function, and so on until all items have been emitted by the * source Observable, emitting the final result from the final call to your function as its sole * item. - *

+ * * - *

+ * * This technique, which is called "reduce" or "aggregate" here, is sometimes called "fold," * "accumulate," "compress," or "inject" in other programming contexts. Groovy, for instance, - * has an inject method that does a similar operation on lists. + * has an `inject` method that does a similar operation on lists. * * @param initialValue * the initial (seed) accumulator value @@ -990,13 +987,13 @@ class Observable[+T] private[scala] (val asJava: rx.Observable[_ <: T]) /** * Returns an Observable that emits the results of sampling the items emitted by the source * Observable at a specified time interval. - *

+ * * * * @param period * the sampling rate * @param unit - * the {@link TimeUnit} in which period is defined + * the [[TimeUnit]] in which `period` is defined * @return an Observable that emits the results of sampling the items emitted by the source * Observable at the specified time interval */ @@ -1007,15 +1004,15 @@ class Observable[+T] private[scala] (val asJava: rx.Observable[_ <: T]) /** * Returns an Observable that emits the results of sampling the items emitted by the source * Observable at a specified time interval. - *

+ * * * * @param period * the sampling rate * @param unit - * the {@link TimeUnit} in which period is defined + * the [[TimeUnit]] in which `period` is defined * @param scheduler - * the {@link Scheduler} to use when sampling + * the [[Scheduler]] to use when sampling * @return an Observable that emits the results of sampling the items emitted by the source * Observable at the specified time interval */ @@ -1028,19 +1025,19 @@ class Observable[+T] private[scala] (val asJava: rx.Observable[_ <: T]) * source Observable, then feeds the result of that function along with the second item emitted * by an Observable into the same function, and so on until all items have been emitted by the * source Observable, emitting the result of each of these iterations. - *

+ * * - *

+ * * This sort of function is sometimes called an accumulator. - *

- * Note that when you pass a seed to scan() the resulting Observable will emit + * + * Note that when you pass a seed to `scan()` the resulting Observable will emit * that seed as its first emitted item. * * @param initialValue * the initial (seed) accumulator value * @param accumulator * an accumulator function to be invoked on each item emitted by the source - * Observable, whose result will be emitted to {@link Observer}s via {@link Observer#onNext onNext} and used in the next accumulator call. + * Observable, whose result will be emitted to [[Observer]]s via [[Observer.onNext onNext]] and used in the next accumulator call. * @return an Observable that emits the results of each call to the accumulator function * @see MSDN: Observable.Scan */ @@ -1051,13 +1048,13 @@ class Observable[+T] private[scala] (val asJava: rx.Observable[_ <: T]) /** * Returns an Observable that emits a Boolean that indicates whether all of the items emitted by * the source Observable satisfy a condition. - *

+ * * * * @param predicate * a function that evaluates an item and returns a Boolean - * @return an Observable that emits true if all items emitted by the source - * Observable satisfy the predicate; otherwise, false + * @return an Observable that emits `true` if all items emitted by the source + * Observable satisfy the predicate; otherwise, `false` */ def forall(predicate: T => Boolean): Observable[Boolean] = { // type mismatch; found : rx.Observable[java.lang.Boolean] required: rx.Observable[_ <: scala.Boolean] @@ -1067,18 +1064,18 @@ class Observable[+T] private[scala] (val asJava: rx.Observable[_ <: T]) } /** - * Returns an Observable that skips the first num items emitted by the source + * Returns an Observable that skips the first `num` items emitted by the source * Observable and emits the remainder. - *

+ * * - *

- * You can ignore the first num items emitted by an Observable and attend only to - * those items that come after, by modifying the Observable with the skip method. + * + * You can ignore the first `num` items emitted by an Observable and attend only to + * those items that come after, by modifying the Observable with the `skip` method. * * @param num * the number of items to skip * @return an Observable that is identical to the source Observable except that it does not - * emit the first num items that the source emits + * emit the first `num` items that the source emits */ def drop(n: Int): Observable[T] = { Observable[T](asJava.skip(n)) @@ -1087,7 +1084,7 @@ class Observable[+T] private[scala] (val asJava: rx.Observable[_ <: T]) /** * Returns an Observable that bypasses all items from the source Observable as long as the specified * condition holds true. Emits all further source items as soon as the condition becomes false. - *

+ * * * * @param predicate @@ -1100,19 +1097,19 @@ class Observable[+T] private[scala] (val asJava: rx.Observable[_ <: T]) } /** - * Returns an Observable that emits only the first num items emitted by the source + * Returns an Observable that emits only the first `num` items emitted by the source * Observable. - *

+ * * - *

- * This method returns an Observable that will invoke a subscribing {@link Observer}'s {@link Observer#onNext onNext} function a maximum of num times before invoking - * {@link Observer#onCompleted onCompleted}. + * + * This method returns an Observable that will invoke a subscribing [[Observer]]'s [[Observer.onNext onNext]] function a maximum of `num` times before invoking + * [[Observer.onCompleted onCompleted]]. * * @param num * the number of items to take - * @return an Observable that emits only the first num items from the source + * @return an Observable that emits only the first `num` items from the source * Observable, or all of the items from the source Observable if that Observable emits - * fewer than num items + * fewer than `num` items */ def take(n: Int): Observable[T] = { Observable[T](asJava.take(n)) @@ -1121,14 +1118,14 @@ class Observable[+T] private[scala] (val asJava: rx.Observable[_ <: T]) /** * Returns an Observable that emits items emitted by the source Observable so long as a * specified condition is true. - *

+ * * * * @param predicate * a function that evaluates an item emitted by the source Observable and returns a * Boolean * @return an Observable that emits the items from the source Observable so long as each item - * satisfies the condition defined by predicate + * satisfies the condition defined by `predicate` */ def takeWhile(predicate: T => Boolean): Observable[T] = { Observable[T](asJava.takeWhile(predicate)) @@ -1138,29 +1135,29 @@ class Observable[+T] private[scala] (val asJava: rx.Observable[_ <: T]) * Returns an Observable that emits the items emitted by a source Observable so long as a given * predicate remains true, where the predicate can operate on both the item and its index * relative to the complete sequence. - *

+ * * * * @param predicate * a function to test each item emitted by the source Observable for a condition; * the second parameter of the function represents the index of the source item * @return an Observable that emits items from the source Observable so long as the predicate - * continues to return true for each item, then completes + * continues to return `true` for each item, then completes */ def takeWhileWithIndex(predicate: (T, Integer) => Boolean): Observable[T] = { Observable[T](asJava.takeWhileWithIndex(predicate)) } /** - * Returns an Observable that emits only the last count items emitted by the source + * Returns an Observable that emits only the last `count` items emitted by the source * Observable. - *

+ * * * * @param count * the number of items to emit from the end of the sequence emitted by the source * Observable - * @return an Observable that emits only the last count items emitted by the source + * @return an Observable that emits only the last `count` items emitted by the source * Observable */ def takeRight(n: Int): Observable[T] = { @@ -1169,17 +1166,17 @@ class Observable[+T] private[scala] (val asJava: rx.Observable[_ <: T]) /** * Returns an Observable that emits the items from the source Observable only until the - * other Observable emits an item. - *

+ * `other` Observable emits an item. + * * * * @param that - * the Observable whose first emitted item will cause takeUntil to stop + * the Observable whose first emitted item will cause `takeUntil` to stop * emitting items from the source Observable - * @param - * the type of items emitted by other + * @tparam E + * the type of items emitted by `other` * @return an Observable that emits the items of the source Observable until such time as - * other emits its first item + * `other` emits its first item */ def takeUntil[E](that: Observable[E]): Observable[T] = { Observable[T](asJava.takeUntil(that.asJava)) @@ -1188,14 +1185,14 @@ class Observable[+T] private[scala] (val asJava: rx.Observable[_ <: T]) /** * Returns an Observable that emits a single item, a list composed of all the items emitted by * the source Observable. - *

+ * * - *

- * Normally, an Observable that returns multiple items will do so by invoking its {@link Observer}'s {@link Observer#onNext onNext} method for each such item. You can change + * + * Normally, an Observable that returns multiple items will do so by invoking its [[Observer]]'s [[Observer.onNext onNext]] method for each such item. You can change * this behavior, instructing the Observable to compose a list of all of these items and then to - * invoke the Observer's onNext function once, passing it the entire list, by - * calling the Observable's toList method prior to calling its {@link #subscribe} method. - *

+ * invoke the Observer's `onNext` function once, passing it the entire list, by + * calling the Observable's `toList` method prior to calling its [[Observable.subscribe]] method. + * * Be careful not to use this operator on Observables that emit infinite or very large numbers * of items, as you do not have the option to unsubscribe. * @@ -1212,10 +1209,10 @@ class Observable[+T] private[scala] (val asJava: rx.Observable[_ <: T]) * * @param f * a function that extracts the key from an item - * @param + * @tparam K * the type of keys returned by the discriminator function. - * @return an Observable that emits {@code (key, observable)} pairs, where {@code observable} - * contains all items for which {@code f} returned {@code key}. + * @return an Observable that emits `(key, observable)` pairs, where `observable` + * contains all items for which `f` returned `key`. */ def groupBy[K](f: T => K): Observable[(K, Observable[T])] = { val o1 = asJava.groupBy[K](f) : rx.Observable[_ <: rx.observables.GroupedObservable[K, _ <: T]] @@ -1226,7 +1223,7 @@ class Observable[+T] private[scala] (val asJava: rx.Observable[_ <: T]) /** * Given an Observable that emits Observables, creates a single Observable that * emits the items emitted by the most recently published of those Observables. - *

+ * * * * @param sequenceOfSequences @@ -1245,16 +1242,16 @@ class Observable[+T] private[scala] (val asJava: rx.Observable[_ <: T]) /** * Flattens two Observables into one Observable, without any transformation. - *

+ * * - *

+ * * You can combine items emitted by two Observables so that they act like a single - * Observable by using the {@code merge} method. + * Observable by using the `merge` method. * * @param that * an Observable to be merged - * @return an Observable that emits items from {@code this} and {@code that} until - * {@code this} or {@code that} emits {@code onError} or {@code onComplete}. + * @return an Observable that emits items from `this` and `that` until + * `this` or `that` emits `onError` or `onComplete`. */ def merge[U >: T](that: Observable[U]): Observable[U] = { val thisJava: rx.Observable[_ <: U] = this.asJava @@ -1263,39 +1260,39 @@ class Observable[+T] private[scala] (val asJava: rx.Observable[_ <: T]) } /** - * This behaves like {@link #merge(Observable)} except that if any of the merged Observables - * notify of an error via {@link Observer#onError onError}, {@code mergeDelayError} will + * This behaves like [[Observable.merge]] except that if any of the merged Observables + * notify of an error via [[Observer.onError onError]], `mergeDelayError` will * refrain from propagating that error notification until all of the merged Observables have * finished emitting items. - *

+ * * - *

- * Even if multiple merged Observables send {@code onError} notifications, {@code mergeDelayError} will only invoke the {@code onError} method of its + * + * Even if multiple merged Observables send `onError` notifications, `mergeDelayError` will only invoke the `onError` method of its * Observers once. - *

+ * * This method allows an Observer to receive all successfully emitted items from all of the * source Observables without being interrupted by an error notification from one of them. * * @param that * an Observable to be merged * @return an Observable that emits items that are the result of flattening the items emitted by - * {@code this} and {@code that} + * `this` and `that` */ def mergeDelayError[U >: T](that: Observable[U]): Observable[U] = { Observable[U](rx.Observable.mergeDelayError[U](this.asJava, that.asJava)) } /** - * Flattens the sequence of Observables emitted by {@code this} into one Observable, without any + * Flattens the sequence of Observables emitted by `this` into one Observable, without any * transformation. - *

+ * * - *

+ * * You can combine the items emitted by multiple Observables so that they act like a single * Observable by using this method. * * @return an Observable that emits items that are the result of flattening the items emitted - * by the Observables emitted by {@code this} + * by the Observables emitted by `this` */ def flatten[U](implicit evidence: Observable[T] <:< Observable[Observable[U]]): Observable[U] = { val o2: Observable[Observable[U]] = this @@ -1306,16 +1303,16 @@ class Observable[+T] private[scala] (val asJava: rx.Observable[_ <: T]) } /** - * This behaves like {@link #flatten(<:<)} except that if any of the merged Observables - * notify of an error via {@link Observer#onError onError}, this method will + * This behaves like [[Observable.flatten]] except that if any of the merged Observables + * notify of an error via [[Observer.onError onError]], this method will * refrain from propagating that error notification until all of the merged Observables have * finished emitting items. - *

+ * * - *

- * Even if multiple merged Observables send {@code onError} notifications, this method will only invoke the {@code onError} method of its + * + * Even if multiple merged Observables send `onError` notifications, this method will only invoke the `onError` method of its * Observers once. - *

+ * * This method allows an Observer to receive all successfully emitted items from all of the * source Observables without being interrupted by an error notification from one of them. * @@ -1346,24 +1343,24 @@ class Observable[+T] private[scala] (val asJava: rx.Observable[_ <: T]) /** * Debounces by dropping all values that are followed by newer values before the timeout value expires. The timer resets on each `onNext` call. - *

+ * * NOTE: If events keep firing faster than the timeout then no data will be emitted. - *

+ * * - *

+ * * Information on debounce vs throttle: - *

- *

    - *
  • http://drupalmotion.com/article/debounce-and-throttle-visual-explanation
  • - *
  • http://unscriptable.com/2009/03/20/debouncing-javascript-methods/
  • - *
  • http://www.illyriad.co.uk/blog/index.php/2011/09/javascript-dont-spam-your-server-debounce-and-throttle/
  • + * + * [ul] + * [li]http://drupalmotion.com/article/debounce-and-throttle-visual-explanation + * [li]http://unscriptable.com/2009/03/20/debouncing-javascript-methods/ + * [li]http://www.illyriad.co.uk/blog/index.php/2011/09/javascript-dont-spam-your-server-debounce-and-throttle/ *
* * @param timeout - * The time each value has to be 'the most recent' of the {@link Observable} to ensure that it's not dropped. + * The time each value has to be 'the most recent' of the [[Observable]] to ensure that it's not dropped. * - * @return An {@link Observable} which filters out values which are too quickly followed up with newer values. - * @see {@link #debounce} + * @return An [[Observable]] which filters out values which are too quickly followed up with newer values. + * @see [[Observable.debounce]] */ def throttleWithTimeout(timeout: Duration): Observable[T] = { Observable[T](asJava.throttleWithTimeout(timeout.length, timeout.unit)) @@ -1371,24 +1368,24 @@ class Observable[+T] private[scala] (val asJava: rx.Observable[_ <: T]) /** * Debounces by dropping all values that are followed by newer values before the timeout value expires. The timer resets on each `onNext` call. - *

+ * * NOTE: If events keep firing faster than the timeout then no data will be emitted. - *

+ * * - *

+ * * Information on debounce vs throttle: - *

- *

    - *
  • http://drupalmotion.com/article/debounce-and-throttle-visual-explanation
  • - *
  • http://unscriptable.com/2009/03/20/debouncing-javascript-methods/
  • - *
  • http://www.illyriad.co.uk/blog/index.php/2011/09/javascript-dont-spam-your-server-debounce-and-throttle/
  • + * + * [ul] + * [li]http://drupalmotion.com/article/debounce-and-throttle-visual-explanation + * [li]http://unscriptable.com/2009/03/20/debouncing-javascript-methods/ + * [li]http://www.illyriad.co.uk/blog/index.php/2011/09/javascript-dont-spam-your-server-debounce-and-throttle/ *
* * @param timeout - * The time each value has to be 'the most recent' of the {@link Observable} to ensure that it's not dropped. + * The time each value has to be 'the most recent' of the [[Observable]] to ensure that it's not dropped. * - * @return An {@link Observable} which filters out values which are too quickly followed up with newer values. - * @see {@link #throttleWithTimeout}; + * @return An [[Observable]] which filters out values which are too quickly followed up with newer values. + * @see [[Observable.throttleWithTimeout]]; */ def debounce(timeout: Duration): Observable[T] = { Observable[T](asJava.debounce(timeout.length, timeout.unit)) @@ -1396,25 +1393,25 @@ class Observable[+T] private[scala] (val asJava: rx.Observable[_ <: T]) /** * Debounces by dropping all values that are followed by newer values before the timeout value expires. The timer resets on each `onNext` call. - *

+ * * NOTE: If events keep firing faster than the timeout then no data will be emitted. - *

+ * * - *

+ * * Information on debounce vs throttle: - *

- *

    - *
  • http://drupalmotion.com/article/debounce-and-throttle-visual-explanation
  • - *
  • http://unscriptable.com/2009/03/20/debouncing-javascript-methods/
  • - *
  • http://www.illyriad.co.uk/blog/index.php/2011/09/javascript-dont-spam-your-server-debounce-and-throttle/
  • + * + * [ul] + * [li]http://drupalmotion.com/article/debounce-and-throttle-visual-explanation + * [li]http://unscriptable.com/2009/03/20/debouncing-javascript-methods/ + * [li]http://www.illyriad.co.uk/blog/index.php/2011/09/javascript-dont-spam-your-server-debounce-and-throttle/ *
* * @param timeout - * The time each value has to be 'the most recent' of the {@link Observable} to ensure that it's not dropped. + * The time each value has to be 'the most recent' of the [[Observable]] to ensure that it's not dropped. * @param scheduler - * The {@link Scheduler} to use internally to manage the timers which handle timeout for each event. + * The [[Scheduler]] to use internally to manage the timers which handle timeout for each event. * @return Observable which performs the throttle operation. - * @see {@link #throttleWithTimeout}; + * @see [[Observable.throttleWithTimeout]]; */ def debounce(timeout: Duration, scheduler: Scheduler): Observable[T] = { Observable[T](asJava.debounce(timeout.length, timeout.unit, scheduler)) @@ -1422,17 +1419,17 @@ class Observable[+T] private[scala] (val asJava: rx.Observable[_ <: T]) /** * Debounces by dropping all values that are followed by newer values before the timeout value expires. The timer resets on each `onNext` call. - *

+ * * NOTE: If events keep firing faster than the timeout then no data will be emitted. - *

+ * * * * @param timeout - * The time each value has to be 'the most recent' of the {@link Observable} to ensure that it's not dropped. + * The time each value has to be 'the most recent' of the [[Observable]] to ensure that it's not dropped. * @param scheduler - * The {@link Scheduler} to use internally to manage the timers which handle timeout for each event. + * The [[Scheduler]] to use internally to manage the timers which handle timeout for each event. * @return Observable which performs the throttle operation. - * @see {@link #debounce} + * @see [[Observable.debounce]] */ def throttleWithTimeout(timeout: Duration, scheduler: Scheduler): Observable[T] = { Observable[T](asJava.throttleWithTimeout(timeout.length, timeout.unit, scheduler)) @@ -1440,15 +1437,15 @@ class Observable[+T] private[scala] (val asJava: rx.Observable[_ <: T]) /** * Throttles by skipping value until `skipDuration` passes and then emits the next received value. - *

- * This differs from {@link #throttleLast} in that this only tracks passage of time whereas {@link #throttleLast} ticks at scheduled intervals. - *

+ * + * This differs from [[Observable.throttleLast]] in that this only tracks passage of time whereas [[Observable.throttleLast]] ticks at scheduled intervals. + * * * * @param skipDuration * Time to wait before sending another value after emitting last value. * @param scheduler - * The {@link Scheduler} to use internally to manage the timers which handle timeout for each event. + * The [[Scheduler]] to use internally to manage the timers which handle timeout for each event. * @return Observable which performs the throttle operation. */ def throttleFirst(skipDuration: Duration, scheduler: Scheduler): Observable[T] = { @@ -1457,9 +1454,9 @@ class Observable[+T] private[scala] (val asJava: rx.Observable[_ <: T]) /** * Throttles by skipping value until `skipDuration` passes and then emits the next received value. - *

- * This differs from {@link #throttleLast} in that this only tracks passage of time whereas {@link #throttleLast} ticks at scheduled intervals. - *

+ * + * This differs from [[Observable.throttleLast]] in that this only tracks passage of time whereas [[Observable.throttleLast]] ticks at scheduled intervals. + * * * * @param skipDuration @@ -1472,15 +1469,14 @@ class Observable[+T] private[scala] (val asJava: rx.Observable[_ <: T]) /** * Throttles by returning the last value of each interval defined by 'intervalDuration'. - *

- * This differs from {@link #throttleFirst} in that this ticks along at a scheduled interval whereas {@link #throttleFirst} does not tick, it just tracks passage of time. - *

+ * + * This differs from [[Observable.throttleFirst]] in that this ticks along at a scheduled interval whereas [[Observable.throttleFirst]] does not tick, it just tracks passage of time. + * * * * @param intervalDuration * Duration of windows within with the last value will be chosen. * @return Observable which performs the throttle operation. - * @see {@link #sample(long, TimeUnit)} */ def throttleLast(intervalDuration: Duration): Observable[T] = { Observable[T](asJava.throttleLast(intervalDuration.length, intervalDuration.unit)) @@ -1488,15 +1484,14 @@ class Observable[+T] private[scala] (val asJava: rx.Observable[_ <: T]) /** * Throttles by returning the last value of each interval defined by 'intervalDuration'. - *

- * This differs from {@link #throttleFirst} in that this ticks along at a scheduled interval whereas {@link #throttleFirst} does not tick, it just tracks passage of time. - *

+ * + * This differs from [[Observable.throttleFirst]] in that this ticks along at a scheduled interval whereas [[Observable.throttleFirst]] does not tick, it just tracks passage of time. + * * * * @param intervalDuration * Duration of windows within with the last value will be chosen. * @return Observable which performs the throttle operation. - * @see {@link #sample(long, TimeUnit, Scheduler)} */ def throttleLast(intervalDuration: Duration, scheduler: Scheduler): Observable[T] = { Observable[T](asJava.throttleLast(intervalDuration.length, intervalDuration.unit, scheduler)) @@ -1525,7 +1520,7 @@ class Observable[+T] private[scala] (val asJava: rx.Observable[_ <: T]) /** * Returns an Observable that emits only the very first item emitted by the source Observable, or * a default value if the source Observable is empty. - *

+ * * * * @param defaultValue @@ -1543,8 +1538,8 @@ class Observable[+T] private[scala] (val asJava: rx.Observable[_ <: T]) /** * Returns an Observable that emits only the very first item emitted by the source Observable. - * This is just a shorthand for {@code take(1)}. - *

+ * This is just a shorthand for `take(1)`. + * * * * @return an Observable that emits only the very first item from the source, or none if the @@ -1556,7 +1551,7 @@ class Observable[+T] private[scala] (val asJava: rx.Observable[_ <: T]) /** * Returns an Observable that forwards all sequentially distinct items emitted from the source Observable. - *

+ * * * * @return an Observable of sequentially distinct items @@ -1568,7 +1563,7 @@ class Observable[+T] private[scala] (val asJava: rx.Observable[_ <: T]) /** * Returns an Observable that forwards all items emitted from the source Observable that are sequentially * distinct according to a key selector function. - *

+ * * * * @param keySelector @@ -1583,7 +1578,7 @@ class Observable[+T] private[scala] (val asJava: rx.Observable[_ <: T]) /** * Returns an Observable that forwards all items emitted from the source Observable that are sequentially * distinct according to an equality function. - *

+ * * * * @param equality @@ -1597,7 +1592,7 @@ class Observable[+T] private[scala] (val asJava: rx.Observable[_ <: T]) /** * Returns an Observable that forwards all items emitted from the source Observable that are sequentially * distinct according to a key selector function and a comparator. - *

+ * * * * @param keySelector @@ -1613,7 +1608,7 @@ class Observable[+T] private[scala] (val asJava: rx.Observable[_ <: T]) /** * Returns an Observable that forwards all distinct items emitted from the source Observable. - *

+ * * * * @return an Observable of distinct items @@ -1625,7 +1620,7 @@ class Observable[+T] private[scala] (val asJava: rx.Observable[_ <: T]) /** * Returns an Observable that forwards all items emitted from the source Observable that are distinct according * to a comparator. - *

+ * * * * @param equality @@ -1639,7 +1634,7 @@ class Observable[+T] private[scala] (val asJava: rx.Observable[_ <: T]) /** * Returns an Observable that forwards all items emitted from the source Observable that are distinct according * to a key selector function. - *

+ * * * * @param keySelector @@ -1654,7 +1649,7 @@ class Observable[+T] private[scala] (val asJava: rx.Observable[_ <: T]) /** * Returns an Observable that forwards all items emitted from the source Observable that are distinct according * to a key selector function and a comparator. - *

+ * * * * @param keySelector @@ -1671,7 +1666,7 @@ class Observable[+T] private[scala] (val asJava: rx.Observable[_ <: T]) /** * Returns an Observable that counts the total number of elements in the source Observable. - *

+ * * * * @return an Observable emitting the number of counted elements of the source Observable @@ -1683,13 +1678,13 @@ class Observable[+T] private[scala] (val asJava: rx.Observable[_ <: T]) /** * Retry subscription to origin Observable upto given retry count. - *

+ * * - *

- * If {@link Observer#onError} is invoked the source Observable will be re-subscribed to as many times as defined by retryCount. - *

- * Any {@link Observer#onNext} calls received on each attempt will be emitted and concatenated together. - *

+ * + * If [[Observer.onError]] is invoked the source Observable will be re-subscribed to as many times as defined by retryCount. + * + * Any [[Observer.onNext]] calls received on each attempt will be emitted and concatenated together. + * * For example, if an Observable fails on first time but emits [1, 2] then succeeds the second time and * emits [1, 2, 3, 4, 5] then the complete output would be [1, 2, 1, 2, 3, 4, 5, onCompleted]. * @@ -1703,13 +1698,13 @@ class Observable[+T] private[scala] (val asJava: rx.Observable[_ <: T]) /** * Retry subscription to origin Observable whenever onError is called (infinite retry count). - *

+ * * - *

- * If {@link Observer#onError} is invoked the source Observable will be re-subscribed to. - *

- * Any {@link Observer#onNext} calls received on each attempt will be emitted and concatenated together. - *

+ * + * If [[Observer.onError]] is invoked the source Observable will be re-subscribed to. + * + * Any [[Observer.onNext]] calls received on each attempt will be emitted and concatenated together. + * * For example, if an Observable fails on first time but emits [1, 2] then succeeds the second time and * emits [1, 2, 3, 4, 5] then the complete output would be [1, 2, 1, 2, 3, 4, 5, onCompleted]. * @return Observable with retry logic. @@ -1719,7 +1714,7 @@ class Observable[+T] private[scala] (val asJava: rx.Observable[_ <: T]) } /** - * Converts an Observable into a {@link BlockingObservable} (an Observable with blocking + * Converts an Observable into a [[BlockingObservable]] (an Observable with blocking * operators). * * @see Blocking Observable Operators @@ -1729,11 +1724,11 @@ class Observable[+T] private[scala] (val asJava: rx.Observable[_ <: T]) } /** - * Perform work in parallel by sharding an {@code Observable} on a {@link Schedulers#threadPoolForComputation()} {@link Scheduler} and return an {@code Observable} with the output. + * Perform work in parallel by sharding an `Observable[T]` on a [[Schedulers.threadPoolForComputation()]] [[Scheduler]] and return an `Observable[R]` with the output. * * @param f - * a {@link Func1} that applies Observable operators to {@code Observable} in parallel and returns an {@code Observable} - * @return an Observable with the output of the function executed on a {@link Scheduler} + * a [[Func1]] that applies Observable operators to `Observable[T]` in parallel and returns an `Observable[R]` + * @return an Observable with the output of the function executed on a [[Scheduler]] */ def parallel[R](f: Observable[T] => Observable[R]): Observable[R] = { val fJava: Func1[rx.Observable[T], rx.Observable[R]] = @@ -1742,13 +1737,13 @@ class Observable[+T] private[scala] (val asJava: rx.Observable[_ <: T]) } /** - * Perform work in parallel by sharding an {@code Observable} on a {@link Scheduler} and return an {@code Observable} with the output. + * Perform work in parallel by sharding an `Observable[T]` on a [[Scheduler]] and return an `Observable[R]` with the output. * * @param f - * a {@link Func1} that applies Observable operators to {@code Observable} in parallel and returns an {@code Observable} + * a [[Func1]] that applies Observable operators to `Observable[T]` in parallel and returns an `Observable[R]` * @param s - * a {@link Scheduler} to perform the work on. - * @return an Observable with the output of the {@link Func1} executed on a {@link Scheduler} + * a [[Scheduler]] to perform the work on. + * @return an Observable with the output of the [[Func1]] executed on a [[Scheduler]] */ def parallel[R](f: Observable[T] => Observable[R], scheduler: Scheduler): Observable[R] = { val fJava: Func1[rx.Observable[T], rx.Observable[R]] = @@ -1791,27 +1786,28 @@ object Observable { } /** - * Creates an Observable that will execute the given function when an {@link Observer} subscribes to it. - *

+ * Creates an Observable that will execute the given function when an [[Observer]] subscribes to it. + * * - *

- * Write the function you pass to create so that it behaves as an Observable: It - * should invoke the Observer's {@link Observer#onNext onNext}, {@link Observer#onError onError}, and {@link Observer#onCompleted onCompleted} methods + * + * Write the function you pass to `create` so that it behaves as an Observable: It + * should invoke the Observer's [[Observer.onNext onNext]], [[Observer.onError onError]], and [[Observer.onCompleted onCompleted]] methods * appropriately. - *

- * A well-formed Observable must invoke either the Observer's onCompleted method - * exactly once or its onError method exactly once. - *

+ * + * A well-formed Observable must invoke either the Observer's `onCompleted` method + * exactly once or its `onError` method exactly once. + * * See Rx Design Guidelines (PDF) * for detailed information. * - * @param + * + * @tparam T * the type of the items that this Observable emits * @param func - * a function that accepts an {@code Observer}, invokes its {@code onNext}, {@code onError}, and {@code onCompleted} methods - * as appropriate, and returns a {@link Subscription} to allow the Observer to + * a function that accepts an `Observer[T]`, invokes its `onNext`, `onError`, and `onCompleted` methods + * as appropriate, and returns a [[Subscription]] to allow the Observer to * canceling the subscription - * @return an Observable that, when an {@link Observer} subscribes to it, will execute the given + * @return an Observable that, when an [[Observer]] subscribes to it, will execute the given * function */ def apply[T](func: Observer[T] => Subscription): Observable[T] = { @@ -1819,15 +1815,15 @@ object Observable { } /** - * Returns an Observable that invokes an {@link Observer}'s {@link Observer#onError onError} method when the Observer subscribes to it - *

+ * Returns an Observable that invokes an [[Observer]]'s [[Observer.onError onError]] method when the Observer subscribes to it + * * * * @param exception * the particular error to report - * @param + * @tparam T * the type of the items (ostensibly) emitted by the Observable - * @return an Observable that invokes the {@link Observer}'s {@link Observer#onError onError} method when the Observer subscribes to it + * @return an Observable that invokes the [[Observer]]'s [[Observer.onError onError]] method when the Observer subscribes to it */ def apply[T](exception: Throwable): Observable[T] = { Observable[T](JObservable.error(exception)) @@ -1835,15 +1831,15 @@ object Observable { /** * Converts a sequence of values into an Observable. - *

+ * * * - *

Implementation note: the entire array will be immediately emitted each time an {@link Observer} subscribes. Since this occurs before the {@link Subscription} is returned, + * Implementation note: the entire array will be immediately emitted each time an [[Observer]] subscribes. Since this occurs before the [[Subscription]] is returned, * it in not possible to unsubscribe from the sequence before it completes. * * @param items * the source Array - * @param + * @tparam T * the type of items in the Array, and the type of items to be emitted by the * resulting Observable * @return an Observable that emits each item in the source Array @@ -1861,19 +1857,19 @@ object Observable { * new Observer that subscribes. That is, for each subscriber, the actuall Observable is determined * by the factory function. * - *

+ * * - *

+ * * The defer operator allows you to defer or delay emitting items from an Observable until such - * time as an Observer subscribes to the Observable. This allows an {@link Observer} to easily + * time as an Observer subscribes to the Observable. This allows an [[Observer]] to easily * obtain updates or a refreshed version of the sequence. * * @param observableFactory - * the Observable factory function to invoke for each {@link Observer} that + * the Observable factory function to invoke for each [[Observer]] that * subscribes to the resulting Observable - * @param + * @tparam T * the type of the items emitted by the Observable - * @return an Observable whose {@link Observer}s trigger an invocation of the given Observable + * @return an Observable whose [[Observer]]s trigger an invocation of the given Observable * factory function */ def defer[T](observable: => Observable[T]): Observable[T] = { @@ -1882,20 +1878,20 @@ object Observable { /** * Returns an Observable that emits a single item and then completes. - *

+ * * - *

+ * * To convert any object into an Observable that emits that object, pass that object into the - * just method. - *

- * This is similar to the {@link #apply(Iterable[T])} method, except that - * {@link #apply(Iterable[T])} will convert an {@link Iterable} object into an Observable that emits - * each of the items in the Iterable, one at a time, while the just() method + * `just` method. + * + * This is similar to the [[Observable.apply[T](T*)]] method, except that + * [[Observable.apply[T](T*)]] will convert an `Iterable` object into an Observable that emits + * each of the items in the Iterable, one at a time, while the `just()` method * converts an Iterable into an Observable that emits the entire Iterable as a single item. * * @param value - * the item to pass to the {@link Observer}'s {@link Observer#onNext onNext} method - * @param + * the item to pass to the [[Observer]]'s [[Observer.onNext onNext]] method + * @tparam T * the type of that item * @return an Observable that emits a single item and then completes */ @@ -1904,13 +1900,13 @@ object Observable { } /** - * Returns an Observable that never sends any items or notifications to an {@link Observer}. - *

+ * Returns an Observable that never sends any items or notifications to an [[Observer]]. + * * - *

+ * * This Observable is useful primarily for testing purposes. * - * @return an Observable that never sends any items or notifications to an {@link Observer} + * @return an Observable that never sends any items or notifications to an [[Observer]] */ def never: Observable[Nothing] = { Observable[Nothing](JObservable.never()) From 79ce193e717b76d6b4d99e11554657ad74f2c428 Mon Sep 17 00:00:00 2001 From: samuelgruetter Date: Fri, 27 Sep 2013 18:26:35 +0200 Subject: [PATCH 16/33] start TestScheduler --- .../scala/concurrency/TestScheduler.scala | 46 +++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/concurrency/TestScheduler.scala diff --git a/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/concurrency/TestScheduler.scala b/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/concurrency/TestScheduler.scala new file mode 100644 index 0000000000..a022d81838 --- /dev/null +++ b/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/concurrency/TestScheduler.scala @@ -0,0 +1,46 @@ +package rx.lang.scala.concurrency + +import scala.concurrent.duration.Duration +import rx.lang.scala.Subscription +import rx.lang.scala.Scheduler +import rx.lang.scala.ImplicitFunctionConversions._ +import rx.util.functions.Func2 +import java.util.concurrent.TimeUnit + +// TODO make a Scheduler interface in Java, and a DefaultScheduler Java and one for Scala + +class TestScheduler extends Scheduler { + + private val asJava = new rx.concurrency.TestScheduler + + override def now: Long = asJava.now + + def advanceTimeBy(time: Duration) { + asJava.advanceTimeBy(time.length, time.unit) + } + + def advanceTimeTo(time: Duration) { + asJava.advanceTimeTo(time.length, time.unit) + } + + def triggerActions() { + asJava.triggerActions() + } + + def schedule[T](state: T, action: (Scheduler, T) => Subscription): Subscription = { + asJava.schedule(state, action) + } + + def schedule[T](state: T, action: (Scheduler, T) => Subscription, delay: Duration): Subscription = { + asJava.schedule(state, action, delay.length, delay.unit) + } + + override def schedule[T](state: T, action: Func2[_ >: Scheduler, _ >: T, _ <: Subscription]): Subscription = { + asJava.schedule(state, action) + } + + override def schedule[T](state: T, action: Func2[_ >: Scheduler, _ >: T, _ <: Subscription], delayTime: Long, unit: TimeUnit): Subscription = { + asJava.schedule(state, action, delayTime, unit) + } + +} From 7c4d23a175385fa9e1ec08676da64f37deff54a8 Mon Sep 17 00:00:00 2001 From: samuelgruetter Date: Fri, 27 Sep 2013 19:48:47 +0200 Subject: [PATCH 17/33] work on Schedulers rx.lang.scala.concurrency.UnitTest.testInterval fails --- .../scala/ImplicitFunctionConversions.scala | 12 ++ .../scala/concurrency/GenericScheduler.scala | 179 ++++++++++++++++++ .../lang/scala/concurrency/Schedulers.scala | 3 +- .../scala/concurrency/TestScheduler.scala | 31 +-- .../rx/lang/scala/concurrency/package.scala | 8 +- .../main/scala/rx/lang/scala/package.scala | 3 +- 6 files changed, 209 insertions(+), 27 deletions(-) create mode 100644 language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/concurrency/GenericScheduler.scala diff --git a/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/ImplicitFunctionConversions.scala b/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/ImplicitFunctionConversions.scala index f28ee5121a..9410ce818a 100644 --- a/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/ImplicitFunctionConversions.scala +++ b/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/ImplicitFunctionConversions.scala @@ -17,6 +17,7 @@ package rx.lang.scala import java.{ lang => jlang } import rx.util.functions._ +import rx.lang.scala.concurrency.GenericScheduler /** * These function conversions convert between Scala functions and Rx `Func`s and `Action`s. @@ -27,6 +28,17 @@ import rx.util.functions._ object ImplicitFunctionConversions { import language.implicitConversions + implicit def schedulerActionToFunc2[T](action: (Scheduler, T) => Subscription) = + new Func2[rx.Scheduler, T, Subscription] { + def call(s: rx.Scheduler, t: T): Subscription = { + action(s, t) + } + } + + implicit def scalaSchedulerToJavaScheduler(s: Scheduler): rx.Scheduler = s.asJava + + implicit def javaSchedulerToScalaScheduler[S <: rx.Scheduler](s: S): GenericScheduler[S] = new GenericScheduler(s) + implicit def scalaFunction1ToOnSubscribeFunc[T](f: rx.lang.scala.Observer[T] => Subscription) = new rx.Observable.OnSubscribeFunc[T] { def onSubscribe(obs: rx.Observer[_ >: T]): rx.Subscription = { diff --git a/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/concurrency/GenericScheduler.scala b/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/concurrency/GenericScheduler.scala new file mode 100644 index 0000000000..c8230b4103 --- /dev/null +++ b/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/concurrency/GenericScheduler.scala @@ -0,0 +1,179 @@ +package rx.lang.scala.concurrency + +import rx.Subscription +import java.util.Date +import scala.concurrent.duration.Duration +import rx.lang.scala.ImplicitFunctionConversions._ +import rx.util.functions.Func2 +import rx.lang.scala.Scheduler +import rx.lang.scala.Observer +import org.scalatest.junit.JUnitSuite +import org.junit.Before +import rx.lang.scala.Observable + + +class GenericScheduler[+S <: rx.Scheduler](val asJava: S) extends AnyVal { + /** + * Schedules a cancelable action to be executed. + * + * @param state + * State to pass into the action. + * @param action + * Action to schedule. + * @return a subscription to be able to unsubscribe from action. + */ + def schedule[T](state: T, action: (Scheduler, T) => Subscription): Subscription = { + asJava.schedule(state, action) + } + + /** + * Schedules a cancelable action to be executed in delayTime. + * + * @param state + * State to pass into the action. + * @param action + * Action to schedule. + * @param delayTime + * Time the action is to be delayed before executing. + * @param unit + * Time unit of the delay time. + * @return a subscription to be able to unsubscribe from action. + */ + def schedule[T](state: T, action: (Scheduler, T) => Subscription, delayTime: Duration): Subscription = { + asJava.schedule(state, action, delayTime.length, delayTime.unit) + } + + /** + * Schedules a cancelable action to be executed periodically. + * This default implementation schedules recursively and waits for actions to complete (instead of potentially executing + * long-running actions concurrently). Each scheduler that can do periodic scheduling in a better way should override this. + * + * @param state + * State to pass into the action. + * @param action + * The action to execute periodically. + * @param initialDelay + * Time to wait before executing the action for the first time. + * @param period + * The time interval to wait each time in between executing the action. + * @return A subscription to be able to unsubscribe from action. + */ + def schedulePeriodically[T](state: T, action: (Scheduler, T) => Subscription, initialDelay: Duration, period: Duration): Subscription = { + asJava.schedulePeriodically(state, action, initialDelay.length, initialDelay.unit.convert(period.length, period.unit), initialDelay.unit) + } + + /** + * Schedules a cancelable action to be executed at dueTime. + * + * @param state + * State to pass into the action. + * @param action + * Action to schedule. + * @param dueTime + * Time the action is to be executed. If in the past it will be executed immediately. + * @return a subscription to be able to unsubscribe from action. + */ + def schedule[T](state: T, action: (Scheduler, T) => Subscription, dueTime: Date): Subscription = { + asJava.schedule(state, action, dueTime) + } + + /** + * Schedules an action to be executed. + * + * @param action + * action + * @return a subscription to be able to unsubscribe from action. + */ + def schedule(action: () => Unit): Subscription = { + asJava.schedule(action) + } + + /** + * Schedules an action to be executed in delayTime. + * + * @param action + * action + * @return a subscription to be able to unsubscribe from action. + */ + def schedule(action: () => Unit, delayTime: Duration): Subscription = { + asJava.schedule(action, delayTime.length, delayTime.unit) + } + + /** + * Schedules an action to be executed periodically. + * + * @param action + * The action to execute periodically. + * @param initialDelay + * Time to wait before executing the action for the first time. + * @param period + * The time interval to wait each time in between executing the action. + * @return A subscription to be able to unsubscribe from action. + */ + def schedulePeriodically(action: () => Unit, initialDelay: Duration, period: Duration): Subscription = { + asJava.schedulePeriodically(action, initialDelay.length, initialDelay.unit.convert(period.length, period.unit), initialDelay.unit) + } + + /** + * @return the scheduler's notion of current absolute time in milliseconds. + */ + def now: Long = { + asJava.now + } + + /** + * Parallelism available to a Scheduler. + * + * This defaults to {@code Runtime.getRuntime().availableProcessors()} but can be overridden for use cases such as scheduling work on a computer cluster. + * + * @return the scheduler's available degree of parallelism. + */ + def degreeOfParallelism: Int = { + asJava.degreeOfParallelism + } + +} + +class UnitTest extends JUnitSuite { + import org.mockito.Matchers._ + import org.mockito.Mockito._ + import org.junit.Test + import org.junit.Before + import scala.concurrent.duration._ + import scala.language.postfixOps + + var scheduler: TestScheduler = null + var observer: Observer[Long] = null + var observer2: Observer[Long] = null + + @Before def before() { + scheduler = TestScheduler() + observer = mock(classOf[rx.Observer[Long]]) + observer2 = mock(classOf[rx.Observer[Long]]) + } + + @Test def testInterval() { + val w = Observable.interval(1 seconds) + val sub = w.subscribe(observer) + + verify(observer, never()).onNext(0L) + verify(observer, never()).onCompleted() + verify(observer, never()).onError(any(classOf[Throwable])) + + scheduler.advanceTimeTo(2 seconds) + + val inOrdr = inOrder(observer); + inOrdr.verify(observer, times(1)).onNext(0L) + inOrdr.verify(observer, times(1)).onNext(1L) + inOrdr.verify(observer, never()).onNext(2L) + verify(observer, never()).onCompleted(); + verify(observer, never()).onError(any(classOf[Throwable])) + + sub.unsubscribe(); + scheduler.advanceTimeTo(4 seconds) + verify(observer, never()).onNext(2L) + verify(observer, times(1)).onCompleted() + verify(observer, never()).onError(any(classOf[Throwable])) + } +} + diff --git a/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/concurrency/Schedulers.scala b/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/concurrency/Schedulers.scala index 33a77ed132..8ba88ba2d0 100644 --- a/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/concurrency/Schedulers.scala +++ b/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/concurrency/Schedulers.scala @@ -1,8 +1,9 @@ package rx.lang.scala.concurrency -import rx.Scheduler import java.util.concurrent.Executor import java.util.concurrent.ScheduledExecutorService +import rx.lang.scala.Scheduler +import rx.lang.scala.ImplicitFunctionConversions._ /** * Factory methods for creating Schedulers. diff --git a/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/concurrency/TestScheduler.scala b/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/concurrency/TestScheduler.scala index a022d81838..41c5ff70ae 100644 --- a/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/concurrency/TestScheduler.scala +++ b/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/concurrency/TestScheduler.scala @@ -1,19 +1,14 @@ package rx.lang.scala.concurrency import scala.concurrent.duration.Duration -import rx.lang.scala.Subscription -import rx.lang.scala.Scheduler -import rx.lang.scala.ImplicitFunctionConversions._ -import rx.util.functions.Func2 -import java.util.concurrent.TimeUnit -// TODO make a Scheduler interface in Java, and a DefaultScheduler Java and one for Scala -class TestScheduler extends Scheduler { + +class TestScheduler { private val asJava = new rx.concurrency.TestScheduler - override def now: Long = asJava.now + /*override*/ def now: Long = asJava.now def advanceTimeBy(time: Duration) { asJava.advanceTimeBy(time.length, time.unit) @@ -26,21 +21,13 @@ class TestScheduler extends Scheduler { def triggerActions() { asJava.triggerActions() } +} - def schedule[T](state: T, action: (Scheduler, T) => Subscription): Subscription = { - asJava.schedule(state, action) - } - - def schedule[T](state: T, action: (Scheduler, T) => Subscription, delay: Duration): Subscription = { - asJava.schedule(state, action, delay.length, delay.unit) - } - - override def schedule[T](state: T, action: Func2[_ >: Scheduler, _ >: T, _ <: Subscription]): Subscription = { - asJava.schedule(state, action) - } - override def schedule[T](state: T, action: Func2[_ >: Scheduler, _ >: T, _ <: Subscription], delayTime: Long, unit: TimeUnit): Subscription = { - asJava.schedule(state, action, delayTime, unit) +object TestScheduler { + def apply(): TestScheduler = { + //rx.lang.scala.ImplicitFunctionConversions.javaSchedulerToScalaScheduler(new rx.concurrency.TestScheduler()) + new TestScheduler } - } + diff --git a/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/concurrency/package.scala b/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/concurrency/package.scala index 507660c23f..c32ef31f1a 100644 --- a/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/concurrency/package.scala +++ b/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/concurrency/package.scala @@ -21,11 +21,13 @@ import rx.concurrency.CurrentThreadScheduler * Provides schedulers. */ package object concurrency { - // These classes are not exposed to Scala users, but are accessible through - // rx.lang.scala.concurrency.Schedulers: + + //type TestScheduler = GenericScheduler[rx.concurrency.TestScheduler] + + // These classes are not exposed to Scala users, but are accessible through rx.lang.scala.concurrency.Schedulers: // rx.concurrency.CurrentThreadScheduler // rx.concurrency.ExecutorScheduler // rx.concurrency.ImmediateScheduler // rx.concurrency.NewThreadScheduler -} \ No newline at end of file +} diff --git a/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/package.scala b/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/package.scala index 220f307961..3dec7a43c9 100644 --- a/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/package.scala +++ b/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/package.scala @@ -17,6 +17,7 @@ package rx.lang import java.util.concurrent.TimeUnit import java.util.Date +import rx.lang.scala.concurrency.GenericScheduler /* * Note that: @@ -227,7 +228,7 @@ package object scala { type Observer[-T] = rx.Observer[_ >: T] - type Scheduler = rx.Scheduler + type Scheduler = GenericScheduler[rx.Scheduler] type Subscription = rx.Subscription From dcbae87e21e016c91d899e6baf9a2743bc0a2a01 Mon Sep 17 00:00:00 2001 From: samuelgruetter Date: Fri, 27 Sep 2013 22:50:22 +0200 Subject: [PATCH 18/33] Scheduler and TestScheduler --- .../scala/ImplicitFunctionConversions.scala | 3 +- .../main/scala/rx/lang/scala/Scheduler.scala | 161 ++++++++++++++++ .../scala/concurrency/GenericScheduler.scala | 179 ------------------ .../scala/concurrency/TestScheduler.scala | 61 +++++- .../rx/lang/scala/concurrency/package.scala | 4 +- .../main/scala/rx/lang/scala/package.scala | 119 ------------ 6 files changed, 215 insertions(+), 312 deletions(-) create mode 100644 language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/Scheduler.scala delete mode 100644 language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/concurrency/GenericScheduler.scala diff --git a/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/ImplicitFunctionConversions.scala b/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/ImplicitFunctionConversions.scala index 9410ce818a..7bdcdf6f36 100644 --- a/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/ImplicitFunctionConversions.scala +++ b/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/ImplicitFunctionConversions.scala @@ -17,7 +17,6 @@ package rx.lang.scala import java.{ lang => jlang } import rx.util.functions._ -import rx.lang.scala.concurrency.GenericScheduler /** * These function conversions convert between Scala functions and Rx `Func`s and `Action`s. @@ -37,7 +36,7 @@ object ImplicitFunctionConversions { implicit def scalaSchedulerToJavaScheduler(s: Scheduler): rx.Scheduler = s.asJava - implicit def javaSchedulerToScalaScheduler[S <: rx.Scheduler](s: S): GenericScheduler[S] = new GenericScheduler(s) + implicit def javaSchedulerToScalaScheduler(s: rx.Scheduler): Scheduler = Scheduler(s) implicit def scalaFunction1ToOnSubscribeFunc[T](f: rx.lang.scala.Observer[T] => Subscription) = new rx.Observable.OnSubscribeFunc[T] { diff --git a/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/Scheduler.scala b/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/Scheduler.scala new file mode 100644 index 0000000000..12f452db59 --- /dev/null +++ b/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/Scheduler.scala @@ -0,0 +1,161 @@ +package rx.lang.scala + +import java.util.Date + +import scala.concurrent.duration.Duration +import scala.concurrent.duration.DurationInt +import scala.language.postfixOps + +import org.junit.Before +import org.junit.Test +import org.mockito.Matchers.any +import org.mockito.Mockito.inOrder +import org.mockito.Mockito.mock +import org.mockito.Mockito.never +import org.mockito.Mockito.times +import org.mockito.Mockito.verify +import org.scalatest.junit.JUnitSuite + +import rx.lang.scala.ImplicitFunctionConversions.scalaFunction0ProducingUnitToAction0 +import rx.lang.scala.ImplicitFunctionConversions.schedulerActionToFunc2 +import rx.lang.scala.concurrency.TestScheduler + + +/** + * Represents an object that schedules units of work. + */ +trait Scheduler { + def asJava: rx.Scheduler + + /** + * Schedules a cancelable action to be executed. + * + * @param state + * State to pass into the action. + * @param action + * Action to schedule. + * @return a subscription to be able to unsubscribe from action. + */ + def schedule[T](state: T, action: (Scheduler, T) => Subscription): Subscription = { + asJava.schedule(state, action) + } + + /** + * Schedules a cancelable action to be executed in delayTime. + * + * @param state + * State to pass into the action. + * @param action + * Action to schedule. + * @param delayTime + * Time the action is to be delayed before executing. + * @param unit + * Time unit of the delay time. + * @return a subscription to be able to unsubscribe from action. + */ + def schedule[T](state: T, action: (Scheduler, T) => Subscription, delayTime: Duration): Subscription = { + asJava.schedule(state, action, delayTime.length, delayTime.unit) + } + + /** + * Schedules a cancelable action to be executed periodically. + * This default implementation schedules recursively and waits for actions to complete (instead of potentially executing + * long-running actions concurrently). Each scheduler that can do periodic scheduling in a better way should override this. + * + * @param state + * State to pass into the action. + * @param action + * The action to execute periodically. + * @param initialDelay + * Time to wait before executing the action for the first time. + * @param period + * The time interval to wait each time in between executing the action. + * @return A subscription to be able to unsubscribe from action. + */ + def schedulePeriodically[T](state: T, action: (Scheduler, T) => Subscription, initialDelay: Duration, period: Duration): Subscription = { + asJava.schedulePeriodically(state, action, initialDelay.length, initialDelay.unit.convert(period.length, period.unit), initialDelay.unit) + } + + /** + * Schedules a cancelable action to be executed at dueTime. + * + * @param state + * State to pass into the action. + * @param action + * Action to schedule. + * @param dueTime + * Time the action is to be executed. If in the past it will be executed immediately. + * @return a subscription to be able to unsubscribe from action. + */ + def schedule[T](state: T, action: (Scheduler, T) => Subscription, dueTime: Date): Subscription = { + asJava.schedule(state, action, dueTime) + } + + /** + * Schedules an action to be executed. + * + * @param action + * action + * @return a subscription to be able to unsubscribe from action. + */ + def schedule(action: () => Unit): Subscription = { + asJava.schedule(action) + } + + /** + * Schedules an action to be executed in delayTime. + * + * @param action + * action + * @return a subscription to be able to unsubscribe from action. + */ + def schedule(action: () => Unit, delayTime: Duration): Subscription = { + asJava.schedule(action, delayTime.length, delayTime.unit) + } + + /** + * Schedules an action to be executed periodically. + * + * @param action + * The action to execute periodically. + * @param initialDelay + * Time to wait before executing the action for the first time. + * @param period + * The time interval to wait each time in between executing the action. + * @return A subscription to be able to unsubscribe from action. + */ + def schedulePeriodically(action: () => Unit, initialDelay: Duration, period: Duration): Subscription = { + asJava.schedulePeriodically(action, initialDelay.length, initialDelay.unit.convert(period.length, period.unit), initialDelay.unit) + } + + /** + * @return the scheduler's notion of current absolute time in milliseconds. + */ + def now: Long = { + asJava.now + } + + /** + * Parallelism available to a Scheduler. + * + * This defaults to {@code Runtime.getRuntime().availableProcessors()} but can be overridden for use cases such as scheduling work on a computer cluster. + * + * @return the scheduler's available degree of parallelism. + */ + def degreeOfParallelism: Int = { + asJava.degreeOfParallelism + } + +} + +/** + * Provides constructors for Schedulers. + */ +object Scheduler { + private class WrapJavaScheduler(val asJava: rx.Scheduler) extends Scheduler + + /** + * Constructs a Scala Scheduler from a Java Scheduler. + */ + def apply(s: rx.Scheduler): Scheduler = new WrapJavaScheduler(s) +} diff --git a/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/concurrency/GenericScheduler.scala b/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/concurrency/GenericScheduler.scala deleted file mode 100644 index c8230b4103..0000000000 --- a/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/concurrency/GenericScheduler.scala +++ /dev/null @@ -1,179 +0,0 @@ -package rx.lang.scala.concurrency - -import rx.Subscription -import java.util.Date -import scala.concurrent.duration.Duration -import rx.lang.scala.ImplicitFunctionConversions._ -import rx.util.functions.Func2 -import rx.lang.scala.Scheduler -import rx.lang.scala.Observer -import org.scalatest.junit.JUnitSuite -import org.junit.Before -import rx.lang.scala.Observable - - -class GenericScheduler[+S <: rx.Scheduler](val asJava: S) extends AnyVal { - /** - * Schedules a cancelable action to be executed. - * - * @param state - * State to pass into the action. - * @param action - * Action to schedule. - * @return a subscription to be able to unsubscribe from action. - */ - def schedule[T](state: T, action: (Scheduler, T) => Subscription): Subscription = { - asJava.schedule(state, action) - } - - /** - * Schedules a cancelable action to be executed in delayTime. - * - * @param state - * State to pass into the action. - * @param action - * Action to schedule. - * @param delayTime - * Time the action is to be delayed before executing. - * @param unit - * Time unit of the delay time. - * @return a subscription to be able to unsubscribe from action. - */ - def schedule[T](state: T, action: (Scheduler, T) => Subscription, delayTime: Duration): Subscription = { - asJava.schedule(state, action, delayTime.length, delayTime.unit) - } - - /** - * Schedules a cancelable action to be executed periodically. - * This default implementation schedules recursively and waits for actions to complete (instead of potentially executing - * long-running actions concurrently). Each scheduler that can do periodic scheduling in a better way should override this. - * - * @param state - * State to pass into the action. - * @param action - * The action to execute periodically. - * @param initialDelay - * Time to wait before executing the action for the first time. - * @param period - * The time interval to wait each time in between executing the action. - * @return A subscription to be able to unsubscribe from action. - */ - def schedulePeriodically[T](state: T, action: (Scheduler, T) => Subscription, initialDelay: Duration, period: Duration): Subscription = { - asJava.schedulePeriodically(state, action, initialDelay.length, initialDelay.unit.convert(period.length, period.unit), initialDelay.unit) - } - - /** - * Schedules a cancelable action to be executed at dueTime. - * - * @param state - * State to pass into the action. - * @param action - * Action to schedule. - * @param dueTime - * Time the action is to be executed. If in the past it will be executed immediately. - * @return a subscription to be able to unsubscribe from action. - */ - def schedule[T](state: T, action: (Scheduler, T) => Subscription, dueTime: Date): Subscription = { - asJava.schedule(state, action, dueTime) - } - - /** - * Schedules an action to be executed. - * - * @param action - * action - * @return a subscription to be able to unsubscribe from action. - */ - def schedule(action: () => Unit): Subscription = { - asJava.schedule(action) - } - - /** - * Schedules an action to be executed in delayTime. - * - * @param action - * action - * @return a subscription to be able to unsubscribe from action. - */ - def schedule(action: () => Unit, delayTime: Duration): Subscription = { - asJava.schedule(action, delayTime.length, delayTime.unit) - } - - /** - * Schedules an action to be executed periodically. - * - * @param action - * The action to execute periodically. - * @param initialDelay - * Time to wait before executing the action for the first time. - * @param period - * The time interval to wait each time in between executing the action. - * @return A subscription to be able to unsubscribe from action. - */ - def schedulePeriodically(action: () => Unit, initialDelay: Duration, period: Duration): Subscription = { - asJava.schedulePeriodically(action, initialDelay.length, initialDelay.unit.convert(period.length, period.unit), initialDelay.unit) - } - - /** - * @return the scheduler's notion of current absolute time in milliseconds. - */ - def now: Long = { - asJava.now - } - - /** - * Parallelism available to a Scheduler. - * - * This defaults to {@code Runtime.getRuntime().availableProcessors()} but can be overridden for use cases such as scheduling work on a computer cluster. - * - * @return the scheduler's available degree of parallelism. - */ - def degreeOfParallelism: Int = { - asJava.degreeOfParallelism - } - -} - -class UnitTest extends JUnitSuite { - import org.mockito.Matchers._ - import org.mockito.Mockito._ - import org.junit.Test - import org.junit.Before - import scala.concurrent.duration._ - import scala.language.postfixOps - - var scheduler: TestScheduler = null - var observer: Observer[Long] = null - var observer2: Observer[Long] = null - - @Before def before() { - scheduler = TestScheduler() - observer = mock(classOf[rx.Observer[Long]]) - observer2 = mock(classOf[rx.Observer[Long]]) - } - - @Test def testInterval() { - val w = Observable.interval(1 seconds) - val sub = w.subscribe(observer) - - verify(observer, never()).onNext(0L) - verify(observer, never()).onCompleted() - verify(observer, never()).onError(any(classOf[Throwable])) - - scheduler.advanceTimeTo(2 seconds) - - val inOrdr = inOrder(observer); - inOrdr.verify(observer, times(1)).onNext(0L) - inOrdr.verify(observer, times(1)).onNext(1L) - inOrdr.verify(observer, never()).onNext(2L) - verify(observer, never()).onCompleted(); - verify(observer, never()).onError(any(classOf[Throwable])) - - sub.unsubscribe(); - scheduler.advanceTimeTo(4 seconds) - verify(observer, never()).onNext(2L) - verify(observer, times(1)).onCompleted() - verify(observer, never()).onError(any(classOf[Throwable])) - } -} - diff --git a/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/concurrency/TestScheduler.scala b/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/concurrency/TestScheduler.scala index 41c5ff70ae..0165a2d285 100644 --- a/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/concurrency/TestScheduler.scala +++ b/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/concurrency/TestScheduler.scala @@ -1,14 +1,14 @@ package rx.lang.scala.concurrency import scala.concurrent.duration.Duration +import rx.lang.scala.Scheduler +import org.scalatest.junit.JUnitSuite - - -class TestScheduler { - - private val asJava = new rx.concurrency.TestScheduler - - /*override*/ def now: Long = asJava.now +/** + * Scheduler with artificial time, useful for testing. + */ +class TestScheduler extends Scheduler { + val asJava = new rx.concurrency.TestScheduler def advanceTimeBy(time: Duration) { asJava.advanceTimeBy(time.length, time.unit) @@ -23,11 +23,54 @@ class TestScheduler { } } - +/** + * Provides constructors for `TestScheduler`. + */ object TestScheduler { def apply(): TestScheduler = { - //rx.lang.scala.ImplicitFunctionConversions.javaSchedulerToScalaScheduler(new rx.concurrency.TestScheduler()) new TestScheduler } } +private class UnitTest extends JUnitSuite { + import org.mockito.Matchers._ + import org.mockito.Mockito._ + import org.junit.{Test, Before} + import scala.concurrent.duration._ + import scala.language.postfixOps + import rx.lang.scala.{Observable, Observer} + + var scheduler: TestScheduler = null + var observer: Observer[Long] = null + var observer2: Observer[Long] = null + + @Before def before() { + scheduler = TestScheduler() + observer = mock(classOf[rx.Observer[Long]]) + } + + @Test def testInterval() { + val w = Observable.interval(1 second, scheduler) + val sub = w.subscribe(observer) + + verify(observer, never()).onNext(0L) + verify(observer, never()).onCompleted() + verify(observer, never()).onError(any(classOf[Throwable])) + + scheduler.advanceTimeTo(2 seconds) + + val inOrdr = inOrder(observer); + inOrdr.verify(observer, times(1)).onNext(0L) + inOrdr.verify(observer, times(1)).onNext(1L) + inOrdr.verify(observer, never()).onNext(2L) + verify(observer, never()).onCompleted() + verify(observer, never()).onError(any(classOf[Throwable])) + + sub.unsubscribe(); + scheduler.advanceTimeTo(4 seconds) + verify(observer, never()).onNext(2L) + verify(observer, times(1)).onCompleted() + verify(observer, never()).onError(any(classOf[Throwable])) + } +} + diff --git a/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/concurrency/package.scala b/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/concurrency/package.scala index c32ef31f1a..a3e61c0021 100644 --- a/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/concurrency/package.scala +++ b/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/concurrency/package.scala @@ -21,9 +21,7 @@ import rx.concurrency.CurrentThreadScheduler * Provides schedulers. */ package object concurrency { - - //type TestScheduler = GenericScheduler[rx.concurrency.TestScheduler] - + // These classes are not exposed to Scala users, but are accessible through rx.lang.scala.concurrency.Schedulers: // rx.concurrency.CurrentThreadScheduler diff --git a/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/package.scala b/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/package.scala index 3dec7a43c9..63e686250f 100644 --- a/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/package.scala +++ b/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/package.scala @@ -17,7 +17,6 @@ package rx.lang import java.util.concurrent.TimeUnit import java.util.Date -import rx.lang.scala.concurrency.GenericScheduler /* * Note that: @@ -81,119 +80,6 @@ package object scala { def onNext(arg: T): Unit } - - /** - * Represents an object that schedules units of work. - */ - abstract class Scheduler { - - /** - * Schedules a cancelable action to be executed. - * - * @param state - * State to pass into the action. - * @param action - * Action to schedule. - * @return a subscription to be able to unsubscribe from action. - */ - def schedule[T](state: T, action: (Scheduler, T) => Subscription): Subscription - - /** - * Schedules a cancelable action to be executed in delayTime. - * - * @param state - * State to pass into the action. - * @param action - * Action to schedule. - * @param delayTime - * Time the action is to be delayed before executing. - * @param unit - * Time unit of the delay time. - * @return a subscription to be able to unsubscribe from action. - */ - def schedule[T](state: T, action: (Scheduler, T) => Subscription, delayTime: Long, unit: TimeUnit): Subscription - - /** - * Schedules a cancelable action to be executed periodically. - * This default implementation schedules recursively and waits for actions to complete (instead of potentially executing - * long-running actions concurrently). Each scheduler that can do periodic scheduling in a better way should override this. - * - * @param state - * State to pass into the action. - * @param action - * The action to execute periodically. - * @param initialDelay - * Time to wait before executing the action for the first time. - * @param period - * The time interval to wait each time in between executing the action. - * @param unit - * The time unit the interval above is given in. - * @return A subscription to be able to unsubscribe from action. - */ - def schedulePeriodically[T](state: T, action: (Scheduler, T) => Subscription, initialDelay: Long, period: Long, unit: TimeUnit): Subscription - - /** - * Schedules a cancelable action to be executed at dueTime. - * - * @param state - * State to pass into the action. - * @param action - * Action to schedule. - * @param dueTime - * Time the action is to be executed. If in the past it will be executed immediately. - * @return a subscription to be able to unsubscribe from action. - */ - def schedule[T](state: T, action: (Scheduler, T) => Subscription, dueTime: Date): Subscription - - /** - * Schedules an action to be executed. - * - * @param action - * action - * @return a subscription to be able to unsubscribe from action. - */ - def schedule(action: () => Unit): Subscription - - /** - * Schedules an action to be executed in delayTime. - * - * @param action - * action - * @return a subscription to be able to unsubscribe from action. - */ - def schedule(action: () => Unit, delayTime: Long, unit: TimeUnit): Subscription - - /** - * Schedules an action to be executed periodically. - * - * @param action - * The action to execute periodically. - * @param initialDelay - * Time to wait before executing the action for the first time. - * @param period - * The time interval to wait each time in between executing the action. - * @param unit - * The time unit the interval above is given in. - * @return A subscription to be able to unsubscribe from action. - */ - def schedulePeriodically(action: () => Unit, initialDelay: Long, period: Long, unit: TimeUnit): Subscription - - /** - * @return the scheduler's notion of current absolute time in milliseconds. - */ - def now(): Long - - /** - * Parallelism available to a Scheduler. - *

- * This defaults to {@code Runtime.getRuntime().availableProcessors()} but can be overridden for use cases such as scheduling work on a computer cluster. - * - * @return the scheduler's available degree of parallelism. - */ - def degreeOfParallelism: Int - - } - /** * Subscriptions are returned from all Observable.subscribe methods to allow unsubscribing. * @@ -221,15 +107,10 @@ package object scala { private[scala] implicit def fakeObserver2RxObserver[T](o: Observer[T]): rx.Observer[_ >: T] = ??? private[scala] implicit def rxObserver2fakeObserver[T](o: rx.Observer[_ >: T]): Observer[T] = ??? - private[scala] implicit def fakeScheduler2RxScheduler(s: Scheduler): rx.Scheduler = ??? - private[scala] implicit def rxScheduler2fakeScheduler(s: rx.Scheduler): Scheduler = ??? - *///#else type Observer[-T] = rx.Observer[_ >: T] - type Scheduler = GenericScheduler[rx.Scheduler] - type Subscription = rx.Subscription //#endif From aae04c175938b7d5587ad279e265bc2f9120cfd8 Mon Sep 17 00:00:00 2001 From: samuelgruetter Date: Sun, 29 Sep 2013 20:40:06 +0200 Subject: [PATCH 19/33] add exists and isEmpty --- .../rx/lang/scala/examples/RxScalaDemo.scala | 9 ++++++++ .../main/scala/rx/lang/scala/Observable.scala | 21 ++++++++++++++++++- .../rx/lang/scala/CompletenessTest.scala | 4 +++- 3 files changed, 32 insertions(+), 2 deletions(-) diff --git a/language-adaptors/rxjava-scala/src/examples/scala/rx/lang/scala/examples/RxScalaDemo.scala b/language-adaptors/rxjava-scala/src/examples/scala/rx/lang/scala/examples/RxScalaDemo.scala index b383681531..c7856b4ea4 100644 --- a/language-adaptors/rxjava-scala/src/examples/scala/rx/lang/scala/examples/RxScalaDemo.scala +++ b/language-adaptors/rxjava-scala/src/examples/scala/rx/lang/scala/examples/RxScalaDemo.scala @@ -411,6 +411,15 @@ class RxScalaDemo extends JUnitSuite { }) } + @Test def elementAtReplacement() { + assertEquals("b", Observable("a", "b", "c").drop(1).first.toBlockingObservable.single) + } + + @Test def elementAtOrDefaultReplacement() { + assertEquals("b", Observable("a", "b", "c").drop(1).firstOrElse("!").toBlockingObservable.single) + assertEquals("!!", Observable("a", "b", "c").drop(10).firstOrElse("!!").toBlockingObservable.single) + } + def output(s: String): Unit = println(s) // blocks until obs has completed diff --git a/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/Observable.scala b/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/Observable.scala index 310fb78f76..0937c4e6a6 100644 --- a/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/Observable.scala +++ b/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/Observable.scala @@ -1749,7 +1749,26 @@ class Observable[+T] private[scala] (val asJava: rx.Observable[_ <: T]) val fJava: Func1[rx.Observable[T], rx.Observable[R]] = (jo: rx.Observable[T]) => f(Observable[T](jo)).asJava.asInstanceOf[rx.Observable[R]] Observable[R](asJava.asInstanceOf[rx.Observable[T]].parallel[R](fJava, scheduler)) - } + } + + /** Tests whether a predicate holds for some of the elements of this `Observable`. + * + * @param p the predicate used to test elements. + * @return an Observable emitting one single Boolean, which is `true` if the given predicate `p` + * holds for some of the elements of this Observable, and `false` otherwise. + */ + def exists(p: T => Boolean): Observable[Boolean] = { + Observable[java.lang.Boolean](asJava.exists(p)).map(_.booleanValue()) + } + + /** Tests whether this `Observable` emits no elements. + * + * @return an Observable emitting one single Boolean, which is `true` if this `Observable` + * emits no elements, and `false` otherwise. + */ + def isEmpty: Observable[Boolean] = { + Observable[java.lang.Boolean](asJava.isEmpty).map(_.booleanValue()) + } def withFilter(p: T => Boolean): WithFilter[T] = { new WithFilter[T](p, asJava) diff --git a/language-adaptors/rxjava-scala/src/test/scala/rx/lang/scala/CompletenessTest.scala b/language-adaptors/rxjava-scala/src/test/scala/rx/lang/scala/CompletenessTest.scala index abf0439b75..cf22630a3a 100644 --- a/language-adaptors/rxjava-scala/src/test/scala/rx/lang/scala/CompletenessTest.scala +++ b/language-adaptors/rxjava-scala/src/test/scala/rx/lang/scala/CompletenessTest.scala @@ -31,7 +31,9 @@ class CompletenessTest extends JUnitSuite { "buffer(Long, Long, TimeUnit)" -> "buffer(Duration, Duration)", "buffer(Long, Long, TimeUnit, Scheduler)" -> "buffer(Duration, Duration, Scheduler)", "count()" -> "length", - "dematerialize()" -> "dematerialize(<:<[T, Notification[U]])", + "dematerialize()" -> "dematerialize(<:<[Observable[T], Observable[Notification[U]]])", + "elementAt(Int)" -> "[use `.drop(index).first`]", + "elementAtOrDefault(Int, T)" -> "[use `.drop(index).firstOrElse(default)`]", "first(Func1[_ >: T, Boolean])" -> commentForFirstWithPredicate, "firstOrDefault(T)" -> "firstOrElse(=> U)", "firstOrDefault(Func1[_ >: T, Boolean], T)" -> "[use `.filter(condition).firstOrElse(default)`]", From 70c14a3424512c67db201f8ccca30d6a93307f8f Mon Sep 17 00:00:00 2001 From: samuelgruetter Date: Sun, 29 Sep 2013 20:49:46 +0200 Subject: [PATCH 20/33] TestScheduler example --- .../scala/concurrency/TestScheduler.scala | 73 +++++++++++++------ 1 file changed, 51 insertions(+), 22 deletions(-) diff --git a/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/concurrency/TestScheduler.scala b/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/concurrency/TestScheduler.scala index 0165a2d285..7023ca2f4e 100644 --- a/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/concurrency/TestScheduler.scala +++ b/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/concurrency/TestScheduler.scala @@ -6,6 +6,40 @@ import org.scalatest.junit.JUnitSuite /** * Scheduler with artificial time, useful for testing. + * + * For example, you could test the `Observable.interval` operation using a `TestScheduler` as follows: + * + * {{{ + * @Test def testInterval() { + * import org.mockito.Matchers._ + * import org.mockito.Mockito._ + * + * val scheduler = TestScheduler() + * val observer = mock(classOf[rx.Observer[Long]]) + * + * val o = Observable.interval(1 second, scheduler) + * val sub = o.subscribe(observer) + * + * verify(observer, never).onNext(0L) + * verify(observer, never).onCompleted() + * verify(observer, never).onError(any(classOf[Throwable])) + * + * scheduler.advanceTimeTo(2 seconds) + * + * val inOrdr = inOrder(observer); + * inOrdr.verify(observer, times(1)).onNext(0L) + * inOrdr.verify(observer, times(1)).onNext(1L) + * inOrdr.verify(observer, never).onNext(2L) + * verify(observer, never).onCompleted() + * verify(observer, never).onError(any(classOf[Throwable])) + * + * sub.unsubscribe(); + * scheduler.advanceTimeTo(4 seconds) + * verify(observer, never).onNext(2L) + * verify(observer, times(1)).onCompleted() + * verify(observer, never).onError(any(classOf[Throwable])) + * } + * }}} */ class TestScheduler extends Scheduler { val asJava = new rx.concurrency.TestScheduler @@ -33,44 +67,39 @@ object TestScheduler { } private class UnitTest extends JUnitSuite { - import org.mockito.Matchers._ - import org.mockito.Mockito._ - import org.junit.{Test, Before} + import org.junit.Test import scala.concurrent.duration._ import scala.language.postfixOps import rx.lang.scala.{Observable, Observer} - var scheduler: TestScheduler = null - var observer: Observer[Long] = null - var observer2: Observer[Long] = null - - @Before def before() { - scheduler = TestScheduler() - observer = mock(classOf[rx.Observer[Long]]) - } - @Test def testInterval() { - val w = Observable.interval(1 second, scheduler) - val sub = w.subscribe(observer) + import org.mockito.Matchers._ + import org.mockito.Mockito._ + + val scheduler = TestScheduler() + val observer = mock(classOf[rx.Observer[Long]]) + + val o = Observable.interval(1 second, scheduler) + val sub = o.subscribe(observer) - verify(observer, never()).onNext(0L) - verify(observer, never()).onCompleted() - verify(observer, never()).onError(any(classOf[Throwable])) + verify(observer, never).onNext(0L) + verify(observer, never).onCompleted() + verify(observer, never).onError(any(classOf[Throwable])) scheduler.advanceTimeTo(2 seconds) val inOrdr = inOrder(observer); inOrdr.verify(observer, times(1)).onNext(0L) inOrdr.verify(observer, times(1)).onNext(1L) - inOrdr.verify(observer, never()).onNext(2L) - verify(observer, never()).onCompleted() - verify(observer, never()).onError(any(classOf[Throwable])) + inOrdr.verify(observer, never).onNext(2L) + verify(observer, never).onCompleted() + verify(observer, never).onError(any(classOf[Throwable])) sub.unsubscribe(); scheduler.advanceTimeTo(4 seconds) - verify(observer, never()).onNext(2L) + verify(observer, never).onNext(2L) verify(observer, times(1)).onCompleted() - verify(observer, never()).onError(any(classOf[Throwable])) + verify(observer, never).onError(any(classOf[Throwable])) } } From 9e81debab3936ba31dd682a0ba95c6c3695393e5 Mon Sep 17 00:00:00 2001 From: samuelgruetter Date: Sun, 29 Sep 2013 20:58:08 +0200 Subject: [PATCH 21/33] make all constructors private --- .../src/main/scala/rx/lang/scala/Notification.scala | 2 +- .../rxjava-scala/src/main/scala/rx/lang/scala/Observable.scala | 1 + .../scala/rx/lang/scala/observables/BlockingObservable.scala | 1 + .../src/main/scala/rx/lang/scala/util/Timestamped.scala | 3 ++- 4 files changed, 5 insertions(+), 2 deletions(-) diff --git a/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/Notification.scala b/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/Notification.scala index c659ecdd6b..62ec5baf3b 100644 --- a/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/Notification.scala +++ b/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/Notification.scala @@ -8,7 +8,7 @@ sealed trait Notification[+T] { } /** - * Provides pattern matching support for Notifications. + * Provides pattern matching support and constructors for Notifications. * * Example: * {{{ diff --git a/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/Observable.scala b/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/Observable.scala index 0937c4e6a6..763a5f54f4 100644 --- a/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/Observable.scala +++ b/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/Observable.scala @@ -20,6 +20,7 @@ package rx.lang.scala /** * The Observable interface that implements the Reactive Pattern. */ +// constructor is private because users should use apply in companion class Observable[+T] private[scala] (val asJava: rx.Observable[_ <: T]) // Uncommenting this line combined with `new Observable(...)` instead of `new Observable[T](...)` // makes the compiler crash diff --git a/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/observables/BlockingObservable.scala b/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/observables/BlockingObservable.scala index eb2bb3bf27..8d9323ba32 100644 --- a/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/observables/BlockingObservable.scala +++ b/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/observables/BlockingObservable.scala @@ -23,6 +23,7 @@ import rx.lang.scala.ImplicitFunctionConversions._ * * You can obtain a BlockingObservable from an Observable using [[Observable.toBlockingObservable]] */ +// constructor is private because users should use Observable.toBlockingObservable class BlockingObservable[+T] private[scala] (val asJava: rx.observables.BlockingObservable[_ <: T]) extends AnyVal { diff --git a/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/util/Timestamped.scala b/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/util/Timestamped.scala index e40cc0599b..e00b9bb17e 100644 --- a/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/util/Timestamped.scala +++ b/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/util/Timestamped.scala @@ -3,7 +3,8 @@ package rx.lang.scala.util /** * Wraps a value and a timestamp. */ -class Timestamped[+T](val asJava: rx.util.Timestamped[_ <: T]) extends AnyVal { +// constructor is private because users should use apply from companion +class Timestamped[+T] private[util] (val asJava: rx.util.Timestamped[_ <: T]) extends AnyVal { /** * Returns the timestamp, in milliseconds. */ From 6635e613fcf29826f5273714c3bd5e2a69a39ef7 Mon Sep 17 00:00:00 2001 From: samuelgruetter Date: Mon, 30 Sep 2013 00:19:18 +0200 Subject: [PATCH 22/33] update TODO --- language-adaptors/rxjava-scala/TODO.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/language-adaptors/rxjava-scala/TODO.md b/language-adaptors/rxjava-scala/TODO.md index 4dcf7f2c40..abf88d06f3 100644 --- a/language-adaptors/rxjava-scala/TODO.md +++ b/language-adaptors/rxjava-scala/TODO.md @@ -4,8 +4,8 @@ TODOs for Scala Adapter This is a (probably incomplete) list of what still needs to be done in the Scala adaptor: -* integrating Scala Futures, should there be a common base interface for Futures and Observables? -* Add methods present in Scala collections library, but not in RxJava, e.g. aggregate à la Scala, collect, exists, tails, ... +* Integrating Scala Futures: Should there be a common base interface for Futures and Observables? And if all subscribers of an Observable wrapping a Future unsubscribe, the Future should be cancelled, but Futures do not support cancellation. +* Add methods present in Scala collections library, but not in RxJava, e.g. aggregate à la Scala, collect, tails, ... * combineLatest with arities > 2 * Avoid text duplication in scaladoc using templates, add examples, distinction between use case signature and full signature * other small TODOs From 67449fb8be018a9c6d82c1333d9f87dec913801c Mon Sep 17 00:00:00 2001 From: samuelgruetter Date: Mon, 30 Sep 2013 23:49:36 +0200 Subject: [PATCH 23/33] allow to construct Observables ina similar way as futures --- .../rx/lang/scala/examples/RxScalaDemo.scala | 34 +++++++++++++++++++ .../main/scala/rx/lang/scala/package.scala | 21 +++++++++++- 2 files changed, 54 insertions(+), 1 deletion(-) diff --git a/language-adaptors/rxjava-scala/src/examples/scala/rx/lang/scala/examples/RxScalaDemo.scala b/language-adaptors/rxjava-scala/src/examples/scala/rx/lang/scala/examples/RxScalaDemo.scala index c7856b4ea4..61726df33f 100644 --- a/language-adaptors/rxjava-scala/src/examples/scala/rx/lang/scala/examples/RxScalaDemo.scala +++ b/language-adaptors/rxjava-scala/src/examples/scala/rx/lang/scala/examples/RxScalaDemo.scala @@ -420,6 +420,40 @@ class RxScalaDemo extends JUnitSuite { assertEquals("!!", Observable("a", "b", "c").drop(10).firstOrElse("!!").toBlockingObservable.single) } + @Test def observableLikeFuture1() { + implicit val scheduler = Schedulers.threadPoolForIO + val o1 = observable { + Thread.sleep(1000) + 5 + } + val o2 = observable { + Thread.sleep(500) + 4 + } + Thread.sleep(500) + val t1 = System.currentTimeMillis + println((o1 merge o2).first.toBlockingObservable.single) + println(System.currentTimeMillis - t1) + } + + @Test def observableLikeFuture2() { + class Friend {} + val session = new Object { + def getFriends: List[Friend] = List(new Friend, new Friend) + } + + implicit val scheduler = Schedulers.threadPoolForIO + val o: Observable[List[Friend]] = observable { + session.getFriends + } + o.subscribe( + friendList => println(friendList), + err => println(err.getMessage) + ) + + Thread.sleep(1500) // or convert to BlockingObservable + } + def output(s: String): Unit = println(s) // blocks until obs has completed diff --git a/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/package.scala b/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/package.scala index 63e686250f..df1dd391fd 100644 --- a/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/package.scala +++ b/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/package.scala @@ -114,7 +114,26 @@ package object scala { type Subscription = rx.Subscription //#endif - + + /** + * Allows to construct observables in a similar way as futures. + * + * Example: + * + * {{{ + * implicit val scheduler = Schedulers.threadPoolForIO + * val o: Observable[List[Friend]] = observable { + * session.getFriends + * } + * o.subscribe( + * friendList => println(friendList), + * err => println(err.getMessage) + * ) + * }}} + */ + def observable[T](body: => T)(implicit scheduler: Scheduler): Observable[T] = { + Observable(1).observeOn(scheduler).map(_ => body) + } } /* From 866d0b3b1d734ce72c60a428784023dff17babdf Mon Sep 17 00:00:00 2001 From: samuelgruetter Date: Tue, 1 Oct 2013 11:26:51 +0200 Subject: [PATCH 24/33] implicit function conversion hack just for nicer scaladoc --- .../src/main/scala/rx/lang/scala/package.scala | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/package.scala b/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/package.scala index df1dd391fd..9356b08f6b 100644 --- a/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/package.scala +++ b/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/package.scala @@ -104,6 +104,13 @@ package object scala { def unsubscribe() = s.unsubscribe() } + private[scala] implicit def schedulerActionToFunc2[T](action: (Scheduler, T) => Subscription) = + new rx.util.functions.Func2[rx.Scheduler, T, rx.Subscription] { + def call(s: rx.Scheduler, t: T): rx.Subscription = { + action(ImplicitFunctionConversions.javaSchedulerToScalaScheduler(s), t) + } + } + private[scala] implicit def fakeObserver2RxObserver[T](o: Observer[T]): rx.Observer[_ >: T] = ??? private[scala] implicit def rxObserver2fakeObserver[T](o: rx.Observer[_ >: T]): Observer[T] = ??? From 06797f81262da4327a54d47ddff6c87e78a8d8ec Mon Sep 17 00:00:00 2001 From: samuelgruetter Date: Tue, 1 Oct 2013 11:29:18 +0200 Subject: [PATCH 25/33] make defer implementation more explicit --- .../rxjava-scala/src/main/scala/rx/lang/scala/Observable.scala | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/Observable.scala b/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/Observable.scala index 763a5f54f4..7bb6e34392 100644 --- a/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/Observable.scala +++ b/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/Observable.scala @@ -1893,7 +1893,7 @@ object Observable { * factory function */ def defer[T](observable: => Observable[T]): Observable[T] = { - Observable[T](JObservable.defer(observable.asJava)) + Observable[T](JObservable.defer[T](() => observable.asJava)) } /** @@ -2094,3 +2094,4 @@ private[scala] class UnitTestSuite extends org.scalatest.junit.JUnitSuite { } } + From 373f5b3834e9b0e299e734e29a9759c044efe13e Mon Sep 17 00:00:00 2001 From: samuelgruetter Date: Tue, 1 Oct 2013 11:42:20 +0200 Subject: [PATCH 26/33] apply review patch --- .../main/scala/rx/lang/scala/Observable.scala | 115 +++--------------- 1 file changed, 20 insertions(+), 95 deletions(-) diff --git a/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/Observable.scala b/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/Observable.scala index 7bb6e34392..321d29db10 100644 --- a/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/Observable.scala +++ b/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/Observable.scala @@ -1341,7 +1341,7 @@ class Observable[+T] private[scala] (val asJava: rx.Observable[_ <: T]) val f: Func2[_ >: T, _ >: U, _ <: (T, U)] = (t: T, u: U) => (t, u) Observable[(T, U)](rx.Observable.combineLatest[T, U, (T, U)](this.asJava, that.asJava, f)) } - +// Review completed till here!!! /** * Debounces by dropping all values that are followed by newer values before the timeout value expires. The timer resets on each `onNext` call. * @@ -1530,6 +1530,7 @@ class Observable[+T] private[scala] (val asJava: rx.Observable[_ <: T]) * @return an Observable that emits only the very first item from the source, or a default value * if the source Observable completes without emitting any item. */ + // TODO def headOrElse def firstOrElse[U >: T](default: => U): Observable[U] = { this.take(1).fold[Option[U]](None)((v: Option[U], e: U) => Some(e)).map({ case Some(element) => element @@ -1546,6 +1547,8 @@ class Observable[+T] private[scala] (val asJava: rx.Observable[_ <: T]) * @return an Observable that emits only the very first item from the source, or none if the * source Observable completes without emitting a single item. */ + // TODO def head + // TODO def tail def first: Observable[T] = { take(1) } @@ -1576,37 +1579,6 @@ class Observable[+T] private[scala] (val asJava: rx.Observable[_ <: T]) Observable[T](asJava.distinctUntilChanged[U](keySelector)) } - /** - * Returns an Observable that forwards all items emitted from the source Observable that are sequentially - * distinct according to an equality function. - * - * - * - * @param equality - * an equality function for deciding whether two emitted items are equal or not - * @return an Observable of sequentially distinct items - */ - // def distinctUntilChanged[U](equality: (T, T) => Boolean): Observable[T] = { - // TODO once https://github.com/Netflix/RxJava/issues/395 is fixed - // } - - /** - * Returns an Observable that forwards all items emitted from the source Observable that are sequentially - * distinct according to a key selector function and a comparator. - * - * - * - * @param keySelector - * a function that projects an emitted item to a key value which is used for deciding whether an item is sequentially - * distinct from another one or not - * @param equality - * an equality function for deciding whether two emitted item keys are equal or not - * @return an Observable of sequentially distinct items - */ - // def distinctUntilChanged[U](keySelector: T => U, equality: (T, T) => Boolean): Observable[T] = { - // TODO once https://github.com/Netflix/RxJava/issues/395 is fixed - // } - /** * Returns an Observable that forwards all distinct items emitted from the source Observable. * @@ -1618,20 +1590,6 @@ class Observable[+T] private[scala] (val asJava: rx.Observable[_ <: T]) Observable[T](asJava.distinct()) } - /** - * Returns an Observable that forwards all items emitted from the source Observable that are distinct according - * to a comparator. - * - * - * - * @param equality - * an equality function for deciding whether two emitted items are equal or not - * @return an Observable of distinct items - */ - // def distinct(equality: (T, T) => Boolean): Observable[T] = { - // TODO once https://github.com/Netflix/RxJava/issues/395 is fixed - // } - /** * Returns an Observable that forwards all items emitted from the source Observable that are distinct according * to a key selector function. @@ -1673,6 +1631,7 @@ class Observable[+T] private[scala] (val asJava: rx.Observable[_ <: T]) * @return an Observable emitting the number of counted elements of the source Observable * as its single item. */ + //TODO Both size and length def length: Observable[Int] = { Observable[Integer](asJava.count()).map(_.intValue()) } @@ -1868,6 +1827,7 @@ object Observable { Observable[T](JObservable.from(args.toIterable.asJava)) } + // TODO (SG) documentation def apply(range: Range): Observable[Int] = { Observable[Int](JObservable.from(range.toIterable.asJava)) } @@ -1895,29 +1855,6 @@ object Observable { def defer[T](observable: => Observable[T]): Observable[T] = { Observable[T](JObservable.defer[T](() => observable.asJava)) } - - /** - * Returns an Observable that emits a single item and then completes. - * - * - * - * To convert any object into an Observable that emits that object, pass that object into the - * `just` method. - * - * This is similar to the [[Observable.apply[T](T*)]] method, except that - * [[Observable.apply[T](T*)]] will convert an `Iterable` object into an Observable that emits - * each of the items in the Iterable, one at a time, while the `just()` method - * converts an Iterable into an Observable that emits the entire Iterable as a single item. - * - * @param value - * the item to pass to the [[Observer]]'s [[Observer.onNext onNext]] method - * @tparam T - * the type of that item - * @return an Observable that emits a single item and then completes - */ - def just[T](value: T): Observable[T] = { - Observable[T](JObservable.just(value)) - } /** * Returns an Observable that never sends any items or notifications to an [[Observer]]. @@ -1932,25 +1869,6 @@ object Observable { Observable[Nothing](JObservable.never()) } - // TODO also support Scala Futures, but think well before. Do we want to Future and Observable - // to share a common base interface? - - // private because it's not RxScala's responsability to provide this alias - private type Future[+T] = java.util.concurrent.Future[_ <: T] - - def apply[T](f: Future[T]): Observable[T] = { - Observable[T](rx.Observable.from(f)) - } - - def apply[T](f: Future[T], scheduler: Scheduler): Observable[T] = { - val sched: rx.Scheduler = scheduler - Observable[T](rx.Observable.from(f, sched)) - } - - def apply[T](f: Future[T], duration: Duration): Observable[T] = { - Observable[T](rx.Observable.from(f, duration.length, duration.unit)) - } - /** * Given a Seq of N observables, returns an observable that emits Seqs of N elements each. * The first emitted Seq will contain the first element of each source observable, @@ -1959,8 +1877,10 @@ object Observable { * @param observables * A Seq of source Observables * @return an Observable that emits the zipped Seqs - */ - def zip[T](observables: Seq[Observable[T]]): Observable[Seq[T]] = { + */ + def zip[A,B,C](obA: Observable[A], obB: Observable[B], obC: Observable[B]): Observable[(A, B, C)] + // TODO until 6 + def zip[T](observables: Observable[T]*): Observable[Seq[T]] = { val f: FuncN[Seq[T]] = (args: Seq[java.lang.Object]) => { val asSeq: Seq[Object] = args.toSeq asSeq.asInstanceOf[Seq[T]] @@ -1989,11 +1909,16 @@ object Observable { Observable[Seq[T]](o) } - def interval(duration: Duration): Observable[Long] = { - (new Observable[java.lang.Long](JObservable.interval(duration.length, duration.unit))).map(_.longValue()) - } - - def interval(duration: Duration, scheduler: Scheduler): Observable[Long] = { + /** + * TODO (SG) ScalaDoc + * TODO Provide implicit scheduler: + * + * def interval(duration: Duration)(implicit scheduler: Scheduler): Observable[Long] + * def interval(duration: Duration)(scheduler: Scheduler): Observable[Long] + * def interval(scheduler: Scheduler)(duration: Duration): Observable[Long] + * def interval(duration: Duration, scheduler: Scheduler): Observable[Long] && def interval(duration: Duration): Observable[Long] + */ + def interval(duration: Duration)(implicit scheduler: Scheduler): Observable[Long] = { (new Observable[java.lang.Long](JObservable.interval(duration.length, duration.unit, scheduler))).map(_.longValue()) } From 2654f60e05a24fc910f73284e32290403d5bffcf Mon Sep 17 00:00:00 2001 From: samuelgruetter Date: Tue, 1 Oct 2013 13:28:46 +0200 Subject: [PATCH 27/33] head, headOrElse, zip(3), zip(4) --- .../main/scala/rx/lang/scala/Observable.scala | 116 +++++++++++++----- 1 file changed, 82 insertions(+), 34 deletions(-) diff --git a/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/Observable.scala b/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/Observable.scala index 321d29db10..fa2f4d1404 100644 --- a/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/Observable.scala +++ b/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/Observable.scala @@ -1524,13 +1524,12 @@ class Observable[+T] private[scala] (val asJava: rx.Observable[_ <: T]) * * * - * @param defaultValue + * @param default * The default value to emit if the source Observable doesn't emit anything. * This is a by-name parameter, so it is only evaluated if the source Observable doesn't emit anything. * @return an Observable that emits only the very first item from the source, or a default value * if the source Observable completes without emitting any item. */ - // TODO def headOrElse def firstOrElse[U >: T](default: => U): Observable[U] = { this.take(1).fold[Option[U]](None)((v: Option[U], e: U) => Some(e)).map({ case Some(element) => element @@ -1538,6 +1537,20 @@ class Observable[+T] private[scala] (val asJava: rx.Observable[_ <: T]) }) } + /** + * Returns an Observable that emits only the very first item emitted by the source Observable, or + * a default value if the source Observable is empty. + * + * + * + * @param default + * The default value to emit if the source Observable doesn't emit anything. + * This is a by-name parameter, so it is only evaluated if the source Observable doesn't emit anything. + * @return an Observable that emits only the very first item from the source, or a default value + * if the source Observable completes without emitting any item. + */ + def headOrElse[U >: T](default: => U): Observable[U] = firstOrElse(default) + /** * Returns an Observable that emits only the very first item emitted by the source Observable. * This is just a shorthand for `take(1)`. @@ -1547,12 +1560,17 @@ class Observable[+T] private[scala] (val asJava: rx.Observable[_ <: T]) * @return an Observable that emits only the very first item from the source, or none if the * source Observable completes without emitting a single item. */ - // TODO def head - // TODO def tail - def first: Observable[T] = { - take(1) - } + def first: Observable[T] = take(1) + def head: Observable[T] = { + this.take(1).fold[Option[T]](None)((v: Option[T], e: T) => Some(e)).map({ + case Some(element) => element + case None => throw new NoSuchElementException("head of empty Observable") + }) + } + + // TODO def tail + /** * Returns an Observable that forwards all sequentially distinct items emitted from the source Observable. * @@ -1870,31 +1888,36 @@ object Observable { } /** - * Given a Seq of N observables, returns an observable that emits Seqs of N elements each. - * The first emitted Seq will contain the first element of each source observable, - * the second Seq the second element of each source observable, and so on. + * Given 3 observables, returns an observable that emits Tuples of 3 elements each. + * The first emitted Tuple will contain the first element of each source observable, + * the second Tuple the second element of each source observable, and so on. * - * @param observables - * A Seq of source Observables - * @return an Observable that emits the zipped Seqs - */ - def zip[A,B,C](obA: Observable[A], obB: Observable[B], obC: Observable[B]): Observable[(A, B, C)] - // TODO until 6 - def zip[T](observables: Observable[T]*): Observable[Seq[T]] = { - val f: FuncN[Seq[T]] = (args: Seq[java.lang.Object]) => { - val asSeq: Seq[Object] = args.toSeq - asSeq.asInstanceOf[Seq[T]] - } - val list = observables.map(_.asJava).asJava - val o = rx.Observable.zip(list, f) - Observable[Seq[T]](o) + * @return an Observable that emits the zipped Observables + */ + def zip[A, B, C](obA: Observable[A], obB: Observable[B], obC: Observable[C]): Observable[(A, B, C)] = { + Observable[(A, B, C)](rx.Observable.zip[A, B, C, (A, B, C)](obA.asJava, obB.asJava, obC.asJava, (a: A, b: B, c: C) => (a, b, c))) } /** - * Given an Observable emitting N source observables, returns an observable that emits Seqs of N elements each. + * Given 4 observables, returns an observable that emits Tuples of 4 elements each. + * The first emitted Tuple will contain the first element of each source observable, + * the second Tuple the second element of each source observable, and so on. + * + * @return an Observable that emits the zipped Observables + */ + def zip[A, B, C, D](obA: Observable[A], obB: Observable[B], obC: Observable[C], obD: Observable[D]): Observable[(A, B, C, D)] = { + Observable[(A, B, C, D)](rx.Observable.zip[A, B, C, D, (A, B, C, D)](obA.asJava, obB.asJava, obC.asJava, obD.asJava, (a: A, b: B, c: C, d: D) => (a, b, c, d))) + } + + /** + * Given an Observable emitting `N` source observables, returns an observable that + * emits Seqs of `N` elements each. * The first emitted Seq will contain the first element of each source observable, * the second Seq the second element of each source observable, and so on. * + * Note that the returned Observable will only start emitting items once the given + * `Observable[Observable[T]]` has completed, because otherwise it cannot know `N`. + * * @param observables * An Observable emitting N source Observables * @return an Observable that emits the zipped Seqs @@ -1908,17 +1931,32 @@ object Observable { val o = rx.Observable.zip(list, f) Observable[Seq[T]](o) } - + + /** + * Emits 0, 1, 2, ... with a delay of `duration` between consecutive numbers. + * + * + * + * @param duration + * duration between two consecutive numbers + * @return An Observable that emits a number each time interval. + */ + def interval(duration: Duration): Observable[Long] = { + (new Observable[java.lang.Long](JObservable.interval(duration.length, duration.unit))).map(_.longValue()) + } + /** - * TODO (SG) ScalaDoc - * TODO Provide implicit scheduler: + * Emits 0, 1, 2, ... with a delay of `duration` between consecutive numbers. * - * def interval(duration: Duration)(implicit scheduler: Scheduler): Observable[Long] - * def interval(duration: Duration)(scheduler: Scheduler): Observable[Long] - * def interval(scheduler: Scheduler)(duration: Duration): Observable[Long] - * def interval(duration: Duration, scheduler: Scheduler): Observable[Long] && def interval(duration: Duration): Observable[Long] + * + * + * @param duration + * duration between two consecutive numbers + * @param scheduler + * the scheduler to use + * @return An Observable that emits a number each time interval. */ - def interval(duration: Duration)(implicit scheduler: Scheduler): Observable[Long] = { + def interval(duration: Duration, scheduler: Scheduler): Observable[Long] = { (new Observable[java.lang.Long](JObservable.interval(duration.length, duration.unit, scheduler))).map(_.longValue()) } @@ -1949,7 +1987,7 @@ private[scala] class UnitTestSuite extends org.scalatest.junit.JUnitSuite { import scala.concurrent.duration._ import org.junit.{Before, Test, Ignore} import org.junit.Assert._ - import org.mockito.Matchers.any + import org.mockito.Matchers._ import org.mockito.Mockito._ import org.mockito.{ MockitoAnnotations, Mock } @@ -2012,6 +2050,16 @@ private[scala] class UnitTestSuite extends org.scalatest.junit.JUnitSuite { assertEquals(receivedMsg, msg) } + @Test def testHead() { + val observer = mock(classOf[Observer[Int]]) + val o = Observable().head + val sub = o.subscribe(observer) + + verify(observer, never).onNext(any(classOf[Int])) + verify(observer, never).onCompleted() + verify(observer, times(1)).onError(any(classOf[NoSuchElementException])) + } + @Test def testTest() = { val a: Observable[Int] = Observable() assertEquals(4, Observable(1, 2, 3, 4).toBlockingObservable.toIterable.last) From df0436c9293f05de2f00f9ef50b6be0b053d99fc Mon Sep 17 00:00:00 2001 From: samuelgruetter Date: Tue, 1 Oct 2013 17:39:56 +0200 Subject: [PATCH 28/33] changes from review + scaladoc improvements --- language-adaptors/rxjava-scala/TODO.md | 9 + .../rx/lang/scala/examples/RxScalaDemo.scala | 12 +- .../main/scala/rx/lang/scala/Observable.scala | 259 +++++++++--------- .../scala/rx/lang/scala/util/package.scala | 8 +- 4 files changed, 143 insertions(+), 145 deletions(-) diff --git a/language-adaptors/rxjava-scala/TODO.md b/language-adaptors/rxjava-scala/TODO.md index abf88d06f3..a3f4b8fd53 100644 --- a/language-adaptors/rxjava-scala/TODO.md +++ b/language-adaptors/rxjava-scala/TODO.md @@ -7,7 +7,16 @@ This is a (probably incomplete) list of what still needs to be done in the Scala * Integrating Scala Futures: Should there be a common base interface for Futures and Observables? And if all subscribers of an Observable wrapping a Future unsubscribe, the Future should be cancelled, but Futures do not support cancellation. * Add methods present in Scala collections library, but not in RxJava, e.g. aggregate à la Scala, collect, tails, ... * combineLatest with arities > 2 +* Implicit schedulers? * Avoid text duplication in scaladoc using templates, add examples, distinction between use case signature and full signature * other small TODOs +(Implicit) schedulers for interval: Options: + +```scala +def interval(duration: Duration)(implicit scheduler: Scheduler): Observable[Long] +def interval(duration: Duration)(scheduler: Scheduler): Observable[Long] +def interval(scheduler: Scheduler)(duration: Duration): Observable[Long] +def interval(duration: Duration, scheduler: Scheduler): Observable[Long] && def interval(duration: Duration): Observable[Long] +```` diff --git a/language-adaptors/rxjava-scala/src/examples/scala/rx/lang/scala/examples/RxScalaDemo.scala b/language-adaptors/rxjava-scala/src/examples/scala/rx/lang/scala/examples/RxScalaDemo.scala index 61726df33f..a449737acf 100644 --- a/language-adaptors/rxjava-scala/src/examples/scala/rx/lang/scala/examples/RxScalaDemo.scala +++ b/language-adaptors/rxjava-scala/src/examples/scala/rx/lang/scala/examples/RxScalaDemo.scala @@ -323,13 +323,13 @@ class RxScalaDemo extends JUnitSuite { .toBlockingObservable.foreach(println(_)) } - // source Observables are in a List: - @Test def zipManySeqExample() { - val observables = List(Observable(1, 2), Observable(10, 20), Observable(100, 200)) - (for (seq <- Observable.zip(observables)) yield seq.mkString("(", ", ", ")")) + // source Observables are all known: + @Test def zip3Example() { + val o = Observable.zip(Observable(1, 2), Observable(10, 20), Observable(100, 200)) + (for ((n1, n2, n3) <- o) yield s"$n1, $n2 and $n3") .toBlockingObservable.foreach(println(_)) } - + // source Observables are in an Observable: @Test def zipManyObservableExample() { val observables = Observable(Observable(1, 2), Observable(10, 20), Observable(100, 200)) @@ -453,7 +453,7 @@ class RxScalaDemo extends JUnitSuite { Thread.sleep(1500) // or convert to BlockingObservable } - + def output(s: String): Unit = println(s) // blocks until obs has completed diff --git a/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/Observable.scala b/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/Observable.scala index fa2f4d1404..1fc26ee3d8 100644 --- a/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/Observable.scala +++ b/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/Observable.scala @@ -1,12 +1,12 @@ /** * Copyright 2013 Netflix, Inc. - * + * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -14,11 +14,36 @@ * limitations under the License. */ - package rx.lang.scala /** * The Observable interface that implements the Reactive Pattern. + * + * @define subscribeObserver + * Call this method to subscribe an [[Observer]] for receiving + * items and notifications from the Observable. + * + * A typical implementation of `subscribe` does the following: + * + * It stores a reference to the Observer in a collection object, such as a `List[T]` object. + * + * It returns a reference to the [[Subscription]] interface. This enables Observers to + * unsubscribe, that is, to stop receiving items and notifications before the Observable stops + * sending them, which also invokes the Observer's [[Observer.onCompleted onCompleted]] method. + * + * An `Observable[T]` instance is responsible for accepting all subscriptions + * and notifying all Observers. Unless the documentation for a particular + * `Observable[T]` implementation indicates otherwise, Observers should make no + * assumptions about the order in which multiple Observers will receive their notifications. + * + * @param observer + * the observer + * @param scheduler + * the [[Scheduler]] on which Observers subscribe to the Observable + * @return a [[Subscription]] reference with which the [[Observer]] can stop receiving items + * before the Observable has finished sending them + * @throws IllegalArgumentException + * if the [[Observer]] provided as the argument to `subscribe()` is `null` */ // constructor is private because users should use apply in companion class Observable[+T] private[scala] (val asJava: rx.Observable[_ <: T]) @@ -35,65 +60,20 @@ class Observable[+T] private[scala] (val asJava: rx.Observable[_ <: T]) import rx.lang.scala.subjects.Subject import rx.lang.scala.observables.BlockingObservable import rx.lang.scala.ImplicitFunctionConversions._ - - /** - * An [[Observer]] must call an Observable's `subscribe` method in order to - * receive items and notifications from the Observable. - * - * A typical implementation of `subscribe` does the following: - * - * It stores a reference to the Observer in a collection object, such as a `List[T]` object. - * - * It returns a reference to the [[Subscription]] interface. This enables Observers to - * unsubscribe, that is, to stop receiving items and notifications before the Observable stops - * sending them, which also invokes the Observer's [[Observer.onCompleted onCompleted]] method. - * - * An `Observable[T]` instance is responsible for accepting all subscriptions - * and notifying all Observers. Unless the documentation for a particular - * `Observable[T]` implementation indicates otherwise, Observers should make no - * assumptions about the order in which multiple Observers will receive their notifications. - * - * - * @param observer - * the observer - * @return a [[Subscription]] reference with which the [[Observer]] can stop receiving items - * before the Observable has finished sending them - * @throws IllegalArgumentException - * if the [[Observer]] provided as the argument to `subscribe()` is `null` - */ - def subscribe(observer: Observer[T]): Subscription = { - asJava.subscribe(observer) - } /** - * An [[Observer]] must call an Observable's `subscribe` method in order to - * receive items and notifications from the Observable. - * - * A typical implementation of `subscribe` does the following: - * - * It stores a reference to the Observer in a collection object, such as a `List[T]` object. - * - * It returns a reference to the [[Subscription]] interface. This enables Observers to - * unsubscribe, that is, to stop receiving items and notifications before the Observable stops - * sending them, which also invokes the Observer's [[Observer.onCompleted onCompleted]] method. - * - * An `Observable[T]` instance is responsible for accepting all subscriptions - * and notifying all Observers. Unless the documentation for a particular `Observable[T]` implementation indicates otherwise, Observers should make no - * assumptions about the order in which multiple Observers will receive their notifications. - * - * - * @param observer - * the observer - * @param scheduler - * the [[Scheduler]] on which Observers subscribe to the Observable - * @return a [[Subscription]] reference with which Observers can stop receiving items and - * notifications before the Observable has finished sending them - * @throws IllegalArgumentException - * if an argument to `subscribe()` is `null` + * $subscribeObserver */ def subscribe(observer: Observer[T], scheduler: Scheduler): Subscription = { asJava.subscribe(observer, scheduler) } + + /** + * $subscribeObserver + */ + def subscribe(observer: Observer[T]): Subscription = { + asJava.subscribe(observer) + } def subscribe(onNext: T => Unit): Subscription = { asJava.subscribe(onNext) @@ -102,7 +82,7 @@ class Observable[+T] private[scala] (val asJava: rx.Observable[_ <: T]) def subscribe(onNext: T => Unit, onError: Throwable => Unit): Subscription = { asJava.subscribe(onNext, onError) } - + def subscribe(onNext: T => Unit, onError: Throwable => Unit, onComplete: () => Unit): Subscription = { asJava.subscribe(onNext, onError, onComplete) } @@ -120,16 +100,15 @@ class Observable[+T] private[scala] (val asJava: rx.Observable[_ <: T]) } /** - * Returns a [[ConnectableObservable]] that upon connection causes the source Observable to + * Returns a pair of a start function and an [[Observable]] that upon calling the start function causes the source Observable to * push results into the specified subject. * * @param subject - * the [[Subject]] for the [[ConnectableObservable]] to push source items - * into + * the `rx.lang.scala.subjects.Subject` to push source items into * @tparam R * result type * @return a pair of a start function and an [[Observable]] such that when the start function - * is called, the Observable starts to push results into the specified [[Subject]] + * is called, the Observable starts to push results into the specified Subject */ def multicast[R](subject: Subject[T, R]): (() => Subscription, Observable[R]) = { val javaCO = asJava.multicast[R](subject) @@ -192,7 +171,7 @@ class Observable[+T] private[scala] (val asJava: rx.Observable[_ <: T]) } /** - * Wraps each item emitted by a source Observable in a [[Timestamped]] object. + * Wraps each item emitted by a source Observable in a [[rx.lang.scala.util.Timestamped]] object. * * * @@ -230,16 +209,16 @@ class Observable[+T] private[scala] (val asJava: rx.Observable[_ <: T]) * Creates an Observable which produces buffers of collected values. * * This Observable produces connected non-overlapping buffers. The current buffer is - * emitted and replaced with a new buffer when the Observable produced by the specified [[Func0]] produces a [[rx.lang.scala.util.Closing]] object. The * [[Func0]] will then + * emitted and replaced with a new buffer when the Observable produced by the specified function produces a [[rx.lang.scala.util.Closing]] object. The function will then * be used to create a new Observable to listen for the end of the next buffer. * * @param bufferClosingSelector - * The [[Func0]] which is used to produce an [[Observable]] for every buffer created. + * The function which is used to produce an [[Observable]] for every buffer created. * When this [[Observable]] produces a [[rx.lang.scala.util.Closing]] object, the associated buffer * is emitted and replaced with a new one. * @return * An [[Observable]] which produces connected non-overlapping buffers, which are emitted - * when the current [[Observable]] created with the [[Func0]] argument produces a [[rx.lang.scala.util.Closing]] object. + * when the current [[Observable]] created with the function argument produces a [[rx.lang.scala.util.Closing]] object. */ def buffer(bufferClosingSelector: () => Observable[Closing]) : Observable[Seq[T]] = { val f: Func0[_ <: rx.Observable[_ <: Closing]] = bufferClosingSelector().asJava @@ -251,7 +230,7 @@ class Observable[+T] private[scala] (val asJava: rx.Observable[_ <: T]) * Creates an Observable which produces buffers of collected values. * * This Observable produces buffers. Buffers are created when the specified "bufferOpenings" - * Observable produces a [[rx.lang.scala.util.Opening]] object. Additionally the [[Func0]] argument + * Observable produces a [[rx.lang.scala.util.Opening]] object. Additionally the function argument * is used to create an Observable which produces [[rx.lang.scala.util.Closing]] objects. When this * Observable produces such an object, the associated buffer is emitted. * @@ -259,7 +238,7 @@ class Observable[+T] private[scala] (val asJava: rx.Observable[_ <: T]) * The [[Observable]] which, when it produces a [[rx.lang.scala.util.Opening]] object, will cause * another buffer to be created. * @param bufferClosingSelector - * The [[Func0]] which is used to produce an [[Observable]] for every buffer created. + * The function which is used to produce an [[Observable]] for every buffer created. * When this [[Observable]] produces a [[rx.lang.scala.util.Closing]] object, the associated buffer * is emitted. * @return @@ -301,7 +280,7 @@ class Observable[+T] private[scala] (val asJava: rx.Observable[_ <: T]) * The maximum size of each buffer before it should be emitted. * @param skip * How many produced values need to be skipped before starting a new buffer. Note that when "skip" and - * "count" are equals that this is the same operation as [[Observable.buffer(int)]]. + * "count" are equals that this is the same operation as `buffer(int)`. * @return * An [[Observable]] which produces buffers every "skipped" values containing at most * "count" produced values. @@ -440,16 +419,16 @@ class Observable[+T] private[scala] (val asJava: rx.Observable[_ <: T]) /** * Creates an Observable which produces windows of collected values. This Observable produces connected * non-overlapping windows. The current window is emitted and replaced with a new window when the - * Observable produced by the specified [[Func0]] produces a [[rx.lang.scala.util.Closing]] object. The [[Func0]] will then be used to create a new Observable to listen for the end of the next + * Observable produced by the specified function produces a [[rx.lang.scala.util.Closing]] object. The function will then be used to create a new Observable to listen for the end of the next * window. * * @param closingSelector - * The [[Func0]] which is used to produce an [[Observable]] for every window created. + * The function which is used to produce an [[Observable]] for every window created. * When this [[Observable]] produces a [[rx.lang.scala.util.Closing]] object, the associated window * is emitted and replaced with a new one. * @return * An [[Observable]] which produces connected non-overlapping windows, which are emitted - * when the current [[Observable]] created with the [[Func0]] argument produces a [[rx.lang.scala.util.Closing]] object. + * when the current [[Observable]] created with the function argument produces a [[rx.lang.scala.util.Closing]] object. */ def window(closingSelector: () => Observable[Closing]): Observable[Observable[T]] = { val func : Func0[_ <: rx.Observable[_ <: Closing]] = closingSelector().asJava @@ -464,14 +443,14 @@ class Observable[+T] private[scala] (val asJava: rx.Observable[_ <: T]) /** * Creates an Observable which produces windows of collected values. This Observable produces windows. * Chunks are created when the specified "windowOpenings" Observable produces a [[rx.lang.scala.util.Opening]] object. - * Additionally the [[Func0]] argument is used to create an Observable which produces [[rx.lang.scala.util.Closing]] objects. When this Observable produces such an object, the associated window is + * Additionally the `closingSelector` argument is used to create an Observable which produces [[rx.lang.scala.util.Closing]] objects. When this Observable produces such an object, the associated window is * emitted. * * @param windowOpenings * The [[Observable]] which when it produces a [[rx.lang.scala.util.Opening]] object, will cause * another window to be created. * @param closingSelector - * The [[Func0]] which is used to produce an [[Observable]] for every window created. + * The function which is used to produce an [[Observable]] for every window created. * When this [[Observable]] produces a [[rx.lang.scala.util.Closing]] object, the associated window * is emitted. * @return @@ -502,17 +481,17 @@ class Observable[+T] private[scala] (val asJava: rx.Observable[_ <: T]) /** * Creates an Observable which produces windows of collected values. This Observable produces windows every - * "skip" values, each containing "count" elements. When the source Observable completes or encounters an error, + * `skip` values, each containing `count` elements. When the source Observable completes or encounters an error, * the current window is emitted and the event is propagated. * * @param count * The maximum size of each window before it should be emitted. * @param skip - * How many produced values need to be skipped before starting a new window. Note that when "skip" and - * "count" are equals that this is the same operation as [[Observable.window(Observable, int)]]. + * How many produced values need to be skipped before starting a new window. Note that when `skip` and + * `count` are equal that this is the same operation as `window(int)`. * @return * An [[Observable]] which produces windows every "skipped" values containing at most - * "count" produced values. + * `count` produced values. */ def window(count: Int, skip: Int): Observable[Observable[T]] = { Observable.jObsOfJObsToScObsOfScObs(asJava.window(count, skip)) @@ -821,9 +800,9 @@ class Observable[+T] private[scala] (val asJava: rx.Observable[_ <: T]) } /** - * Instruct an Observable to pass control to another Observable rather than invoking [[Observer.onError onError]] if it encounters an error of type [[java.lang.Exception]]. + * Instruct an Observable to pass control to another Observable rather than invoking [[Observer.onError onError]] if it encounters an error of type `java.lang.Exception`. * - * This differs from [[Observable.onErrorResumeNext]] in that this one does not handle [[java.lang.Throwable]] or [[java.lang.Error]] but lets those continue through. + * This differs from `Observable.onErrorResumeNext` in that this one does not handle `java.lang.Throwable` or `java.lang.Error` but lets those continue through. * * * @@ -909,7 +888,7 @@ class Observable[+T] private[scala] (val asJava: rx.Observable[_ <: T]) } /** - * Returns a [[ConnectableObservable]] that shares a single subscription to the underlying + * Returns a pair of a start function and an [[Observable]] that shares a single subscription to the underlying * Observable that will replay all of its items and notifications to any future [[Observer]]. * * @@ -924,7 +903,7 @@ class Observable[+T] private[scala] (val asJava: rx.Observable[_ <: T]) /** * This method has similar behavior to [[Observable.replay]] except that this auto-subscribes to - * the source Observable rather than returning a [[ConnectableObservable]]. + * the source Observable rather than returning a start function and an Observable. * * * @@ -943,7 +922,7 @@ class Observable[+T] private[scala] (val asJava: rx.Observable[_ <: T]) } /** - * Returns a [[ConnectableObservable]], which waits until its [[ConnectableObservable.connect connect]] method is called before it begins emitting + * Returns a a pair of a start function and an [[Observable]], which waits until the start function is called before it begins emitting * items to those [[Observer]]s that have subscribed to it. * * @@ -1192,7 +1171,7 @@ class Observable[+T] private[scala] (val asJava: rx.Observable[_ <: T]) * Normally, an Observable that returns multiple items will do so by invoking its [[Observer]]'s [[Observer.onNext onNext]] method for each such item. You can change * this behavior, instructing the Observable to compose a list of all of these items and then to * invoke the Observer's `onNext` function once, passing it the entire list, by - * calling the Observable's `toList` method prior to calling its [[Observable.subscribe]] method. + * calling the Observable's `toList` method prior to calling its `Observable.subscribe` method. * * Be careful not to use this operator on Observables that emit infinite or very large numbers * of items, as you do not have the option to unsubscribe. @@ -1341,7 +1320,7 @@ class Observable[+T] private[scala] (val asJava: rx.Observable[_ <: T]) val f: Func2[_ >: T, _ >: U, _ <: (T, U)] = (t: T, u: U) => (t, u) Observable[(T, U)](rx.Observable.combineLatest[T, U, (T, U)](this.asJava, that.asJava, f)) } -// Review completed till here!!! + /** * Debounces by dropping all values that are followed by newer values before the timeout value expires. The timer resets on each `onNext` call. * @@ -1351,17 +1330,15 @@ class Observable[+T] private[scala] (val asJava: rx.Observable[_ <: T]) * * Information on debounce vs throttle: * - * [ul] - * [li]http://drupalmotion.com/article/debounce-and-throttle-visual-explanation - * [li]http://unscriptable.com/2009/03/20/debouncing-javascript-methods/ - * [li]http://www.illyriad.co.uk/blog/index.php/2011/09/javascript-dont-spam-your-server-debounce-and-throttle/ - * + * - http://drupalmotion.com/article/debounce-and-throttle-visual-explanation + * - http://unscriptable.com/2009/03/20/debouncing-javascript-methods/ + * - http://www.illyriad.co.uk/blog/index.php/2011/09/javascript-dont-spam-your-server-debounce-and-throttle/ * * @param timeout * The time each value has to be 'the most recent' of the [[Observable]] to ensure that it's not dropped. * * @return An [[Observable]] which filters out values which are too quickly followed up with newer values. - * @see [[Observable.debounce]] + * @see `Observable.debounce` */ def throttleWithTimeout(timeout: Duration): Observable[T] = { Observable[T](asJava.throttleWithTimeout(timeout.length, timeout.unit)) @@ -1376,17 +1353,15 @@ class Observable[+T] private[scala] (val asJava: rx.Observable[_ <: T]) * * Information on debounce vs throttle: * - * [ul] - * [li]http://drupalmotion.com/article/debounce-and-throttle-visual-explanation - * [li]http://unscriptable.com/2009/03/20/debouncing-javascript-methods/ - * [li]http://www.illyriad.co.uk/blog/index.php/2011/09/javascript-dont-spam-your-server-debounce-and-throttle/ - * + * - http://drupalmotion.com/article/debounce-and-throttle-visual-explanation + * - http://unscriptable.com/2009/03/20/debouncing-javascript-methods/ + * - http://www.illyriad.co.uk/blog/index.php/2011/09/javascript-dont-spam-your-server-debounce-and-throttle/ * * @param timeout * The time each value has to be 'the most recent' of the [[Observable]] to ensure that it's not dropped. * * @return An [[Observable]] which filters out values which are too quickly followed up with newer values. - * @see [[Observable.throttleWithTimeout]]; + * @see `Observable.throttleWithTimeout` */ def debounce(timeout: Duration): Observable[T] = { Observable[T](asJava.debounce(timeout.length, timeout.unit)) @@ -1401,18 +1376,16 @@ class Observable[+T] private[scala] (val asJava: rx.Observable[_ <: T]) * * Information on debounce vs throttle: * - * [ul] - * [li]http://drupalmotion.com/article/debounce-and-throttle-visual-explanation - * [li]http://unscriptable.com/2009/03/20/debouncing-javascript-methods/ - * [li]http://www.illyriad.co.uk/blog/index.php/2011/09/javascript-dont-spam-your-server-debounce-and-throttle/ - * + * - http://drupalmotion.com/article/debounce-and-throttle-visual-explanation + * - http://unscriptable.com/2009/03/20/debouncing-javascript-methods/ + * - http://www.illyriad.co.uk/blog/index.php/2011/09/javascript-dont-spam-your-server-debounce-and-throttle/ * * @param timeout * The time each value has to be 'the most recent' of the [[Observable]] to ensure that it's not dropped. * @param scheduler * The [[Scheduler]] to use internally to manage the timers which handle timeout for each event. * @return Observable which performs the throttle operation. - * @see [[Observable.throttleWithTimeout]]; + * @see `Observable.throttleWithTimeout` */ def debounce(timeout: Duration, scheduler: Scheduler): Observable[T] = { Observable[T](asJava.debounce(timeout.length, timeout.unit, scheduler)) @@ -1430,7 +1403,7 @@ class Observable[+T] private[scala] (val asJava: rx.Observable[_ <: T]) * @param scheduler * The [[Scheduler]] to use internally to manage the timers which handle timeout for each event. * @return Observable which performs the throttle operation. - * @see [[Observable.debounce]] + * @see `Observable.debounce` */ def throttleWithTimeout(timeout: Duration, scheduler: Scheduler): Observable[T] = { Observable[T](asJava.throttleWithTimeout(timeout.length, timeout.unit, scheduler)) @@ -1439,7 +1412,7 @@ class Observable[+T] private[scala] (val asJava: rx.Observable[_ <: T]) /** * Throttles by skipping value until `skipDuration` passes and then emits the next received value. * - * This differs from [[Observable.throttleLast]] in that this only tracks passage of time whereas [[Observable.throttleLast]] ticks at scheduled intervals. + * This differs from `Observable.throttleLast` in that this only tracks passage of time whereas `Observable.throttleLast` ticks at scheduled intervals. * * * @@ -1456,7 +1429,7 @@ class Observable[+T] private[scala] (val asJava: rx.Observable[_ <: T]) /** * Throttles by skipping value until `skipDuration` passes and then emits the next received value. * - * This differs from [[Observable.throttleLast]] in that this only tracks passage of time whereas [[Observable.throttleLast]] ticks at scheduled intervals. + * This differs from `Observable.throttleLast` in that this only tracks passage of time whereas `Observable.throttleLast` ticks at scheduled intervals. * * * @@ -1471,7 +1444,7 @@ class Observable[+T] private[scala] (val asJava: rx.Observable[_ <: T]) /** * Throttles by returning the last value of each interval defined by 'intervalDuration'. * - * This differs from [[Observable.throttleFirst]] in that this ticks along at a scheduled interval whereas [[Observable.throttleFirst]] does not tick, it just tracks passage of time. + * This differs from `Observable.throttleFirst` in that this ticks along at a scheduled interval whereas `Observable.throttleFirst` does not tick, it just tracks passage of time. * * * @@ -1486,7 +1459,7 @@ class Observable[+T] private[scala] (val asJava: rx.Observable[_ <: T]) /** * Throttles by returning the last value of each interval defined by 'intervalDuration'. * - * This differs from [[Observable.throttleFirst]] in that this ticks along at a scheduled interval whereas [[Observable.throttleFirst]] does not tick, it just tracks passage of time. + * This differs from `Observable.throttleFirst` in that this ticks along at a scheduled interval whereas `Observable.throttleFirst` does not tick, it just tracks passage of time. * * * @@ -1561,7 +1534,14 @@ class Observable[+T] private[scala] (val asJava: rx.Observable[_ <: T]) * source Observable completes without emitting a single item. */ def first: Observable[T] = take(1) - + + /* + + TODO once https://github.com/Netflix/RxJava/issues/417 is fixed, we can add head and tail methods + + /** + * emits NoSuchElementException("head of empty Observable") if empty + */ def head: Observable[T] = { this.take(1).fold[Option[T]](None)((v: Option[T], e: T) => Some(e)).map({ case Some(element) => element @@ -1569,7 +1549,12 @@ class Observable[+T] private[scala] (val asJava: rx.Observable[_ <: T]) }) } - // TODO def tail + /** + * emits an UnsupportedOperationException("tail of empty list") if empty + */ + def tail: Observable[T] = ??? + + */ /** * Returns an Observable that forwards all sequentially distinct items emitted from the source Observable. @@ -1624,23 +1609,17 @@ class Observable[+T] private[scala] (val asJava: rx.Observable[_ <: T]) } /** - * Returns an Observable that forwards all items emitted from the source Observable that are distinct according - * to a key selector function and a comparator. + * Returns an Observable that counts the total number of elements in the source Observable. * - * + * * - * @param keySelector - * a function that projects an emitted item to a key value which is used for deciding whether an item is - * distinct from another one or not - * @param equality - * an equality function for deciding whether two emitted item keys are equal or not - * @return an Observable of distinct items - * @see MSDN: Observable.distinct + * @return an Observable emitting the number of counted elements of the source Observable + * as its single item. */ - // def distinct[U](keySelector: T => U, equality: (T, T) => Boolean): Observable[T] = { - // TODO once https://github.com/Netflix/RxJava/issues/395 is fixed - //} - + def length: Observable[Int] = { + Observable[Integer](asJava.count()).map(_.intValue()) + } + /** * Returns an Observable that counts the total number of elements in the source Observable. * @@ -1649,10 +1628,7 @@ class Observable[+T] private[scala] (val asJava: rx.Observable[_ <: T]) * @return an Observable emitting the number of counted elements of the source Observable * as its single item. */ - //TODO Both size and length - def length: Observable[Int] = { - Observable[Integer](asJava.count()).map(_.intValue()) - } + def size: Observable[Int] = length /** * Retry subscription to origin Observable upto given retry count. @@ -1692,7 +1668,7 @@ class Observable[+T] private[scala] (val asJava: rx.Observable[_ <: T]) } /** - * Converts an Observable into a [[BlockingObservable]] (an Observable with blocking + * Converts an Observable into a [[rx.lang.scala.observables.BlockingObservable]] (an Observable with blocking * operators). * * @see Blocking Observable Operators @@ -1702,10 +1678,10 @@ class Observable[+T] private[scala] (val asJava: rx.Observable[_ <: T]) } /** - * Perform work in parallel by sharding an `Observable[T]` on a [[Schedulers.threadPoolForComputation()]] [[Scheduler]] and return an `Observable[R]` with the output. + * Perform work in parallel by sharding an `Observable[T]` on a [[rx.lang.scala.concurrency.Schedulers.threadPoolForComputation]] [[Scheduler]] and return an `Observable[R]` with the output. * * @param f - * a [[Func1]] that applies Observable operators to `Observable[T]` in parallel and returns an `Observable[R]` + * a function that applies Observable operators to `Observable[T]` in parallel and returns an `Observable[R]` * @return an Observable with the output of the function executed on a [[Scheduler]] */ def parallel[R](f: Observable[T] => Observable[R]): Observable[R] = { @@ -1718,10 +1694,10 @@ class Observable[+T] private[scala] (val asJava: rx.Observable[_ <: T]) * Perform work in parallel by sharding an `Observable[T]` on a [[Scheduler]] and return an `Observable[R]` with the output. * * @param f - * a [[Func1]] that applies Observable operators to `Observable[T]` in parallel and returns an `Observable[R]` + * a function that applies Observable operators to `Observable[T]` in parallel and returns an `Observable[R]` * @param s * a [[Scheduler]] to perform the work on. - * @return an Observable with the output of the [[Func1]] executed on a [[Scheduler]] + * @return an Observable with the output of the function executed on a [[Scheduler]] */ def parallel[R](f: Observable[T] => Observable[R], scheduler: Scheduler): Observable[R] = { val fJava: Func1[rx.Observable[T], rx.Observable[R]] = @@ -1844,8 +1820,19 @@ object Observable { def apply[T](args: T*): Observable[T] = { Observable[T](JObservable.from(args.toIterable.asJava)) } - - // TODO (SG) documentation + + /** + * Generates an Observable that emits a sequence of integers within a specified range. + * + * + * + * Implementation note: the entire range will be immediately emitted each time an [[Observer]] subscribes. + * Since this occurs before the [[Subscription]] is returned, + * it in not possible to unsubscribe from the sequence before it completes. + * + * @param range the range + * @return an Observable that emits a range of sequential integers + */ def apply(range: Range): Observable[Int] = { Observable[Int](JObservable.from(range.toIterable.asJava)) } @@ -2050,6 +2037,7 @@ private[scala] class UnitTestSuite extends org.scalatest.junit.JUnitSuite { assertEquals(receivedMsg, msg) } + /* @Test def testHead() { val observer = mock(classOf[Observer[Int]]) val o = Observable().head @@ -2059,6 +2047,7 @@ private[scala] class UnitTestSuite extends org.scalatest.junit.JUnitSuite { verify(observer, never).onCompleted() verify(observer, times(1)).onError(any(classOf[NoSuchElementException])) } + */ @Test def testTest() = { val a: Observable[Int] = Observable() diff --git a/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/util/package.scala b/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/util/package.scala index 07820f6ea1..7913808794 100644 --- a/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/util/package.scala +++ b/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/util/package.scala @@ -22,25 +22,25 @@ package object util { /** * Tagging interface for objects which can open buffers. - * @see [[Observable.buffer]] + * @see [[Observable `Observable.buffer(Observable[Opening], Opening => Observable[Closing])`]] */ type Opening = rx.util.Opening /** * Creates an object which can open buffers. - * @see [[Observable.buffer]] + * @see [[Observable `Observable.buffer(Observable[Opening], Opening => Observable[Closing])`]] */ def Opening() = rx.util.Openings.create() /** * Tagging interface for objects which can close buffers. - * @see [[Observable.buffer]] + * @see [[Observable `Observable.buffer(Observable[Opening], Opening => Observable[Closing])`]] */ type Closing = rx.util.Closing /** * Creates an object which can close buffers. - * @see [[Observable.buffer]] + * @see [[Observable `Observable.buffer(Observable[Opening], Opening => Observable[Closing])`]] */ def Closing() = rx.util.Closings.create() From b90634d94b9fe1669cb2f4cd9354dc200ab1b5dd Mon Sep 17 00:00:00 2001 From: samuelgruetter Date: Wed, 2 Oct 2013 13:40:49 +0200 Subject: [PATCH 29/33] improve scaladoc --- .../scala/ImplicitFunctionConversions.scala | 28 -- .../scala/rx/lang/scala/Notification.scala | 2 +- .../main/scala/rx/lang/scala/Observable.scala | 295 ++++++++++++------ .../main/scala/rx/lang/scala/Scheduler.scala | 2 +- .../rx/lang/scala/observables/package.scala | 2 +- .../main/scala/rx/lang/scala/package.scala | 24 +- .../scala/rx/lang/scala/util/package.scala | 2 +- 7 files changed, 213 insertions(+), 142 deletions(-) diff --git a/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/ImplicitFunctionConversions.scala b/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/ImplicitFunctionConversions.scala index 7bdcdf6f36..5db1c673f6 100644 --- a/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/ImplicitFunctionConversions.scala +++ b/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/ImplicitFunctionConversions.scala @@ -45,41 +45,26 @@ object ImplicitFunctionConversions { } } - /** - * Converts a by-name parameter to a Rx Func0 - */ implicit def scalaByNameParamToFunc0[B](param: => B): Func0[B] = new Func0[B] { def call(): B = param } - /** - * Converts 0-arg function to Rx Action0 - */ implicit def scalaFunction0ProducingUnitToAction0(f: (() => Unit)): Action0 = new Action0 { def call(): Unit = f() } - /** - * Converts 1-arg function to Rx Action1 - */ implicit def scalaFunction1ProducingUnitToAction1[A](f: (A => Unit)): Action1[A] = new Action1[A] { def call(a: A): Unit = f(a) } - /** - * Converts 1-arg predicate to Rx Func1[A, java.lang.Boolean] - */ implicit def scalaBooleanFunction1ToRxBooleanFunc1[A](f: (A => Boolean)): Func1[A, jlang.Boolean] = new Func1[A, jlang.Boolean] { def call(a: A): jlang.Boolean = f(a).booleanValue } - /** - * Converts 2-arg predicate to Rx Func2[A, B, java.lang.Boolean] - */ implicit def scalaBooleanFunction2ToRxBooleanFunc1[A, B](f: ((A, B) => Boolean)): Func2[A, B, jlang.Boolean] = new Func2[A, B, jlang.Boolean] { def call(a: A, b: B): jlang.Boolean = f(a, b).booleanValue @@ -90,34 +75,21 @@ object ImplicitFunctionConversions { def call(args: java.lang.Object*): R = f(args) } - /** - * Converts a specific function shape (used in takeWhile) to the equivalent Java types with an Rx Func2 - */ implicit def convertTakeWhileFuncToRxFunc2[A](f: (A, Int) => Boolean): Func2[A, jlang.Integer, jlang.Boolean] = new Func2[A, jlang.Integer, jlang.Boolean] { def call(a: A, b: jlang.Integer): jlang.Boolean = f(a, b).booleanValue } - /** - * Converts a function shaped ilke compareTo into the equivalent Rx Func2 - */ implicit def convertComparisonFuncToRxFunc2[A](f: (A, A) => Int): Func2[A, A, jlang.Integer] = new Func2[A, A, jlang.Integer] { def call(a1: A, a2: A): jlang.Integer = f(a1, a2).intValue } - /** - * This implicit allows Scala code to use any exception type and still work - * with invariant Func1 interface - */ implicit def exceptionFunction1ToRxExceptionFunc1[A <: Exception, B](f: (A => B)): Func1[Exception, B] = new Func1[Exception, B] { def call(ex: Exception): B = f(ex.asInstanceOf[A]) } - /** - * The following implicits convert functions of different arities into the Rx equivalents - */ implicit def scalaFunction0ToRxFunc0[A](f: () => A): Func0[A] = new Func0[A] { def call(): A = f() diff --git a/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/Notification.scala b/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/Notification.scala index 62ec5baf3b..27fb82a69e 100644 --- a/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/Notification.scala +++ b/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/Notification.scala @@ -1,7 +1,7 @@ package rx.lang.scala /** - * Emitted by Observables returned by [[rx.lang.scala.Observable.materialize]]. + * Emitted by Observables returned by [[Observable.materialize]]. */ sealed trait Notification[+T] { def asJava: rx.Notification[_ <: T] diff --git a/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/Observable.scala b/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/Observable.scala index 1fc26ee3d8..cbbac22aa0 100644 --- a/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/Observable.scala +++ b/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/Observable.scala @@ -19,7 +19,9 @@ package rx.lang.scala /** * The Observable interface that implements the Reactive Pattern. * - * @define subscribeObserver + * @param asJava the underlying Java observable + * + * @define subscribeObserverMain * Call this method to subscribe an [[Observer]] for receiving * items and notifications from the Observable. * @@ -36,14 +38,36 @@ package rx.lang.scala * `Observable[T]` implementation indicates otherwise, Observers should make no * assumptions about the order in which multiple Observers will receive their notifications. * - * @param observer - * the observer - * @param scheduler - * the [[Scheduler]] on which Observers subscribe to the Observable - * @return a [[Subscription]] reference with which the [[Observer]] can stop receiving items + * @define subscribeObserverParamObserver + * the observer + * @define subscribeObserverParamScheduler + * the [[Scheduler]] on which Observers subscribe to the Observable + * @define subscribeAllReturn + * a [[Subscription]] reference whose `unsubscribe` method can be called to stop receiving items * before the Observable has finished sending them - * @throws IllegalArgumentException - * if the [[Observer]] provided as the argument to `subscribe()` is `null` + * + * @define subscribeCallbacksMainWithNotifications + * Call this method to receive items and notifications from this observable. + * + * @define subscribeCallbacksMainNoNotifications + * Call this method to receive items from this observable. + * + * @define subscribeCallbacksParamOnNext + * this function will be called whenever the Observable emits an item + * @define subscribeCallbacksParamOnError + * this function will be called if an error occurs + * @define subscribeCallbacksParamOnComplete + * this function will be called when this Observable has finished emitting items + * @define subscribeCallbacksParamScheduler + * the scheduler to use + * + * @define debounceVsThrottle + * Information on debounce vs throttle: + * - [[http://drupalmotion.com/article/debounce-and-throttle-visual-explanation]] + * - [[http://unscriptable.com/2009/03/20/debouncing-javascript-methods/]] + * - [[http://www.illyriad.co.uk/blog/index.php/2011/09/javascript-dont-spam-your-server-debounce-and-throttle/]] + * + * */ // constructor is private because users should use apply in companion class Observable[+T] private[scala] (val asJava: rx.Observable[_ <: T]) @@ -62,39 +86,91 @@ class Observable[+T] private[scala] (val asJava: rx.Observable[_ <: T]) import rx.lang.scala.ImplicitFunctionConversions._ /** - * $subscribeObserver + * $subscribeObserverMain + * + * @param observer $subscribeObserverParamObserver + * @param scheduler $subscribeObserverParamScheduler + * @return $subscribeAllReturn */ def subscribe(observer: Observer[T], scheduler: Scheduler): Subscription = { asJava.subscribe(observer, scheduler) } /** - * $subscribeObserver + * $subscribeObserverMain + * + * @param observer $subscribeObserverParamObserver + * @return $subscribeAllReturn */ def subscribe(observer: Observer[T]): Subscription = { asJava.subscribe(observer) } - + + /** + * $subscribeCallbacksMainNoNotifications + * + * @param onNext $subscribeCallbacksParamOnNext + * @return $subscribeAllReturn + */ def subscribe(onNext: T => Unit): Subscription = { asJava.subscribe(onNext) } + /** + * $subscribeCallbacksMainWithNotifications + * + * @param onNext $subscribeCallbacksParamOnNext + * @param onError $subscribeCallbacksParamOnError + * @return $subscribeAllReturn + */ def subscribe(onNext: T => Unit, onError: Throwable => Unit): Subscription = { asJava.subscribe(onNext, onError) } + /** + * $subscribeCallbacksMainWithNotifications + * + * @param onNext $subscribeCallbacksParamOnNext + * @param onError $subscribeCallbacksParamOnError + * @param onComplete $subscribeCallbacksParamOnComplete + * @return $subscribeAllReturn + */ def subscribe(onNext: T => Unit, onError: Throwable => Unit, onComplete: () => Unit): Subscription = { asJava.subscribe(onNext, onError, onComplete) } - + + /** + * $subscribeCallbacksMainWithNotifications + * + * @param onNext $subscribeCallbacksParamOnNext + * @param onError $subscribeCallbacksParamOnError + * @param onComplete $subscribeCallbacksParamOnComplete + * @param scheduler $subscribeCallbacksParamScheduler + * @return $subscribeAllReturn + */ def subscribe(onNext: T => Unit, onError: Throwable => Unit, onComplete: () => Unit, scheduler: Scheduler): Subscription = { asJava.subscribe(onNext, onError, onComplete, scheduler) } + /** + * $subscribeCallbacksMainWithNotifications + * + * @param onNext $subscribeCallbacksParamOnNext + * @param onError $subscribeCallbacksParamOnError + * @param scheduler $subscribeCallbacksParamScheduler + * @return $subscribeAllReturn + */ def subscribe(onNext: T => Unit, onError: Throwable => Unit, scheduler: Scheduler): Subscription = { asJava.subscribe(onNext, onError, scheduler) } - + + /** + * $subscribeCallbacksMainNoNotifications + * + * @param onNext $subscribeCallbacksParamOnNext + * @param scheduler $subscribeCallbacksParamScheduler + * @return $subscribeAllReturn + */ def subscribe(onNext: T => Unit, scheduler: Scheduler): Subscription = { asJava.subscribe(onNext, scheduler) } @@ -116,8 +192,8 @@ class Observable[+T] private[scala] (val asJava: rx.Observable[_ <: T]) } /** - * Returns an Observable that first emits the items emitted by this, and then the items emitted - * by that. + * Returns an Observable that first emits the items emitted by `this`, and then the items emitted + * by `that`. * * * @@ -133,13 +209,14 @@ class Observable[+T] private[scala] (val asJava: rx.Observable[_ <: T]) } /** - * Returns an Observable that emits the items emitted by two or more Observables, one after the + * Returns an Observable that emits the items emitted by several Observables, one after the * other. - * - * - * - * @return an Observable that emits items that are the result of combining the items emitted by - * the source Observables, one after the other + * + * This operation is only available if `this` is of type `Observable[Observable[U]]` for some `U`, + * otherwise you'll get a compilation error. + * + * @usecase def concat[U]: Observable[U] + * @inheritdoc */ def concat[U](implicit evidence: Observable[T] <:< Observable[Observable[U]]): Observable[U] = { val o2: Observable[Observable[U]] = this @@ -161,8 +238,6 @@ class Observable[+T] private[scala] (val asJava: rx.Observable[_ <: T]) * * @param observable * the source Observable - * @tparam T - * the type of item emitted by the source Observable * @return an Observable that is a chronologically well-behaved version of the source * Observable, and that synchronously notifies its [[Observer]]s */ @@ -190,9 +265,7 @@ class Observable[+T] private[scala] (val asJava: rx.Observable[_ <: T]) def zip[U](that: Observable[U]): Observable[(T, U)] = { Observable[(T, U)](JObservable.zip[T, U, (T, U)](this.asJava, that.asJava, (t: T, u: U) => (t, u))) } - - // public static [R] Observable[R] zip(Observable> ws, final FuncN zipFunction) { - + /** * Zips this Observable with its indices. * @@ -212,7 +285,7 @@ class Observable[+T] private[scala] (val asJava: rx.Observable[_ <: T]) * emitted and replaced with a new buffer when the Observable produced by the specified function produces a [[rx.lang.scala.util.Closing]] object. The function will then * be used to create a new Observable to listen for the end of the next buffer. * - * @param bufferClosingSelector + * @param closings * The function which is used to produce an [[Observable]] for every buffer created. * When this [[Observable]] produces a [[rx.lang.scala.util.Closing]] object, the associated buffer * is emitted and replaced with a new one. @@ -220,8 +293,8 @@ class Observable[+T] private[scala] (val asJava: rx.Observable[_ <: T]) * An [[Observable]] which produces connected non-overlapping buffers, which are emitted * when the current [[Observable]] created with the function argument produces a [[rx.lang.scala.util.Closing]] object. */ - def buffer(bufferClosingSelector: () => Observable[Closing]) : Observable[Seq[T]] = { - val f: Func0[_ <: rx.Observable[_ <: Closing]] = bufferClosingSelector().asJava + def buffer(closings: () => Observable[Closing]) : Observable[Seq[T]] = { + val f: Func0[_ <: rx.Observable[_ <: Closing]] = closings().asJava val jObs: rx.Observable[_ <: java.util.List[_]] = asJava.buffer(f) Observable.jObsOfListToScObsOfSeq(jObs.asInstanceOf[rx.Observable[_ <: java.util.List[T]]]) } @@ -229,24 +302,24 @@ class Observable[+T] private[scala] (val asJava: rx.Observable[_ <: T]) /** * Creates an Observable which produces buffers of collected values. * - * This Observable produces buffers. Buffers are created when the specified "bufferOpenings" + * This Observable produces buffers. Buffers are created when the specified `openings` * Observable produces a [[rx.lang.scala.util.Opening]] object. Additionally the function argument * is used to create an Observable which produces [[rx.lang.scala.util.Closing]] objects. When this * Observable produces such an object, the associated buffer is emitted. * - * @param bufferOpenings + * @param openings * The [[Observable]] which, when it produces a [[rx.lang.scala.util.Opening]] object, will cause * another buffer to be created. - * @param bufferClosingSelector + * @param closings * The function which is used to produce an [[Observable]] for every buffer created. * When this [[Observable]] produces a [[rx.lang.scala.util.Closing]] object, the associated buffer * is emitted. * @return * An [[Observable]] which produces buffers which are created and emitted when the specified [[Observable]]s publish certain objects. */ - def buffer(bufferOpenings: Observable[Opening], bufferClosingSelector: Opening => Observable[Closing]): Observable[Seq[T]] = { - val opening: rx.Observable[_ <: Opening] = bufferOpenings.asJava - val closing: Func1[Opening, _ <: rx.Observable[_ <: Closing]] = (o: Opening) => bufferClosingSelector(o).asJava + def buffer(openings: Observable[Opening], closings: Opening => Observable[Closing]): Observable[Seq[T]] = { + val opening: rx.Observable[_ <: Opening] = openings.asJava + val closing: Func1[Opening, _ <: rx.Observable[_ <: Closing]] = (o: Opening) => closings(o).asJava val jObs: rx.Observable[_ <: java.util.List[_]] = asJava.buffer(opening, closing) Observable.jObsOfListToScObsOfSeq(jObs.asInstanceOf[rx.Observable[_ <: java.util.List[T]]]) } @@ -254,7 +327,7 @@ class Observable[+T] private[scala] (val asJava: rx.Observable[_ <: T]) /** * Creates an Observable which produces buffers of collected values. * - * This Observable produces connected non-overlapping buffers, each containing "count" + * This Observable produces connected non-overlapping buffers, each containing `count` * elements. When the source Observable completes or encounters an error, the current * buffer is emitted, and the event is propagated. * @@ -262,7 +335,7 @@ class Observable[+T] private[scala] (val asJava: rx.Observable[_ <: T]) * The maximum size of each buffer before it should be emitted. * @return * An [[Observable]] which produces connected non-overlapping buffers containing at most - * "count" produced values. + * `count` produced values. */ def buffer(count: Int): Observable[Seq[T]] = { val oJava: rx.Observable[_ <: java.util.List[_]] = asJava.buffer(count) @@ -272,18 +345,18 @@ class Observable[+T] private[scala] (val asJava: rx.Observable[_ <: T]) /** * Creates an Observable which produces buffers of collected values. * - * This Observable produces buffers every "skip" values, each containing "count" + * This Observable produces buffers every `skip` values, each containing `count` * elements. When the source Observable completes or encounters an error, the current * buffer is emitted, and the event is propagated. * * @param count * The maximum size of each buffer before it should be emitted. * @param skip - * How many produced values need to be skipped before starting a new buffer. Note that when "skip" and - * "count" are equals that this is the same operation as `buffer(int)`. + * How many produced values need to be skipped before starting a new buffer. Note that when `skip` and + * `count` are equals that this is the same operation as `buffer(int)`. * @return - * An [[Observable]] which produces buffers every "skipped" values containing at most - * "count" produced values. + * An [[Observable]] which produces buffers every `skip` values containing at most + * `count` produced values. */ def buffer(count: Int, skip: Int): Observable[Seq[T]] = { val oJava: rx.Observable[_ <: java.util.List[_]] = asJava.buffer(count, skip) @@ -331,7 +404,7 @@ class Observable[+T] private[scala] (val asJava: rx.Observable[_ <: T]) /** * Creates an Observable which produces buffers of collected values. This Observable produces connected * non-overlapping buffers, each of a fixed duration specified by the `timespan` argument or a maximum size - * specified by the "count" argument (which ever is reached first). When the source Observable completes + * specified by the `count` argument (which ever is reached first). When the source Observable completes * or encounters an error, the current buffer is emitted and the event is propagated. * * @param timespan @@ -351,7 +424,7 @@ class Observable[+T] private[scala] (val asJava: rx.Observable[_ <: T]) /** * Creates an Observable which produces buffers of collected values. This Observable produces connected * non-overlapping buffers, each of a fixed duration specified by the `timespan` argument or a maximum size - * specified by the "count" argument (which ever is reached first). When the source Observable completes + * specified by the `count` argument (which ever is reached first). When the source Observable completes * or encounters an error, the current buffer is emitted and the event is propagated. * * @param timespan @@ -419,10 +492,11 @@ class Observable[+T] private[scala] (val asJava: rx.Observable[_ <: T]) /** * Creates an Observable which produces windows of collected values. This Observable produces connected * non-overlapping windows. The current window is emitted and replaced with a new window when the - * Observable produced by the specified function produces a [[rx.lang.scala.util.Closing]] object. The function will then be used to create a new Observable to listen for the end of the next + * Observable produced by the specified function produces a [[rx.lang.scala.util.Closing]] object. + * The function will then be used to create a new Observable to listen for the end of the next * window. * - * @param closingSelector + * @param closings * The function which is used to produce an [[Observable]] for every window created. * When this [[Observable]] produces a [[rx.lang.scala.util.Closing]] object, the associated window * is emitted and replaced with a new one. @@ -430,8 +504,8 @@ class Observable[+T] private[scala] (val asJava: rx.Observable[_ <: T]) * An [[Observable]] which produces connected non-overlapping windows, which are emitted * when the current [[Observable]] created with the function argument produces a [[rx.lang.scala.util.Closing]] object. */ - def window(closingSelector: () => Observable[Closing]): Observable[Observable[T]] = { - val func : Func0[_ <: rx.Observable[_ <: Closing]] = closingSelector().asJava + def window(closings: () => Observable[Closing]): Observable[Observable[T]] = { + val func : Func0[_ <: rx.Observable[_ <: Closing]] = closings().asJava val o1: rx.Observable[_ <: rx.Observable[_]] = asJava.window(func) val o2 = new Observable[rx.Observable[_]](o1).map((x: rx.Observable[_]) => { val x2 = x.asInstanceOf[rx.Observable[_ <: T]] @@ -442,36 +516,36 @@ class Observable[+T] private[scala] (val asJava: rx.Observable[_ <: T]) /** * Creates an Observable which produces windows of collected values. This Observable produces windows. - * Chunks are created when the specified "windowOpenings" Observable produces a [[rx.lang.scala.util.Opening]] object. - * Additionally the `closingSelector` argument is used to create an Observable which produces [[rx.lang.scala.util.Closing]] objects. When this Observable produces such an object, the associated window is - * emitted. + * Chunks are created when the specified `openings` Observable produces a [[rx.lang.scala.util.Opening]] object. + * Additionally the `closings` argument is used to create an Observable which produces [[rx.lang.scala.util.Closing]] objects. + * When this Observable produces such an object, the associated window is emitted. * - * @param windowOpenings + * @param openings * The [[Observable]] which when it produces a [[rx.lang.scala.util.Opening]] object, will cause * another window to be created. - * @param closingSelector + * @param closings * The function which is used to produce an [[Observable]] for every window created. * When this [[Observable]] produces a [[rx.lang.scala.util.Closing]] object, the associated window * is emitted. * @return * An [[Observable]] which produces windows which are created and emitted when the specified [[Observable]]s publish certain objects. */ - def window(windowOpenings: Observable[Opening], closingSelector: Opening => Observable[Closing]) = { + def window(openings: Observable[Opening], closings: Opening => Observable[Closing]) = { Observable.jObsOfJObsToScObsOfScObs( - asJava.window(windowOpenings.asJava, (op: Opening) => closingSelector(op).asJava)) + asJava.window(openings.asJava, (op: Opening) => closings(op).asJava)) : Observable[Observable[T]] // SI-7818 } /** * Creates an Observable which produces windows of collected values. This Observable produces connected - * non-overlapping windows, each containing "count" elements. When the source Observable completes or + * non-overlapping windows, each containing `count` elements. When the source Observable completes or * encounters an error, the current window is emitted, and the event is propagated. * * @param count * The maximum size of each window before it should be emitted. * @return * An [[Observable]] which produces connected non-overlapping windows containing at most - * "count" produced values. + * `count` produced values. */ def window(count: Int): Observable[Observable[T]] = { // this unnecessary ascription is needed because of this bug (without, compiler crashes): @@ -490,7 +564,7 @@ class Observable[+T] private[scala] (val asJava: rx.Observable[_ <: T]) * How many produced values need to be skipped before starting a new window. Note that when `skip` and * `count` are equal that this is the same operation as `window(int)`. * @return - * An [[Observable]] which produces windows every "skipped" values containing at most + * An [[Observable]] which produces windows every `skip` values containing at most * `count` produced values. */ def window(count: Int, skip: Int): Observable[Observable[T]] = { @@ -535,7 +609,7 @@ class Observable[+T] private[scala] (val asJava: rx.Observable[_ <: T]) /** * Creates an Observable which produces windows of collected values. This Observable produces connected * non-overlapping windows, each of a fixed duration specified by the `timespan` argument or a maximum size - * specified by the "count" argument (which ever is reached first). When the source Observable completes + * specified by the `count` argument (which ever is reached first). When the source Observable completes * or encounters an error, the current window is emitted and the event is propagated. * * @param timespan @@ -555,7 +629,7 @@ class Observable[+T] private[scala] (val asJava: rx.Observable[_ <: T]) /** * Creates an Observable which produces windows of collected values. This Observable produces connected * non-overlapping windows, each of a fixed duration specified by the `timespan` argument or a maximum size - * specified by the "count" argument (which ever is reached first). When the source Observable completes + * specified by the `count` argument (which ever is reached first). When the source Observable completes * or encounters an error, the current window is emitted and the event is propagated. * * @param timespan @@ -642,7 +716,6 @@ class Observable[+T] private[scala] (val asJava: rx.Observable[_ <: T]) * @param action * an function to be invoked when the source Observable finishes * @return an Observable that emits the same items as the source Observable, then invokes the function - * @see MSDN: Observable.Finally Method */ def finallyDo(action: () => Unit): Observable[T] = { Observable[T](asJava.finallyDo(action)) @@ -688,7 +761,6 @@ class Observable[+T] private[scala] (val asJava: rx.Observable[_ <: T]) * * @return an Observable whose items are the result of materializing the items and * notifications of the source Observable - * @see MSDN: Observable.materialize */ def materialize: Observable[Notification[T]] = { Observable[rx.Notification[_ <: T]](asJava.materialize()).map(Notification(_)) @@ -726,10 +798,17 @@ class Observable[+T] private[scala] (val asJava: rx.Observable[_ <: T]) * Returns an Observable that reverses the effect of [[Observable.materialize]] by * transforming the [[Notification]] objects emitted by the source Observable into the items * or notifications they represent. + * + * This operation is only available if `this` is of type `Observable[Notification[U]]` for some `U`, + * otherwise you will get a compilation error. * * * * @return an Observable that emits the items and notifications embedded in the [[Notification]] objects emitted by the source Observable + * + * @usecase def dematerialize[U]: Observable[U] + * @inheritdoc + * */ // with =:= it does not work, why? def dematerialize[U](implicit evidence: Observable[T] <:< Observable[Notification[U]]): Observable[U] = { @@ -751,7 +830,8 @@ class Observable[+T] private[scala] (val asJava: rx.Observable[_ <: T]) * function that returns an Observable (`resumeFunction`) to * `onErrorResumeNext`, if the original Observable encounters an error, instead of * invoking its Observer's `onError` method, it will instead relinquish control to - * the Observable returned from `resumeFunction`, which will invoke the Observer's [[Observer.onNext onNext]] method if it is able to do so. In such a case, because no + * the Observable returned from `resumeFunction`, which will invoke the Observer's + * [[Observer.onNext onNext]] method if it is able to do so. In such a case, because no * Observable necessarily invokes `onError`, the Observer may never know that an * error happened. * @@ -781,7 +861,8 @@ class Observable[+T] private[scala] (val asJava: rx.Observable[_ <: T]) * another Observable (`resumeSequence`) to an Observable's * `onErrorResumeNext` method, if the original Observable encounters an error, * instead of invoking its Observer's `onError` method, it will instead relinquish - * control to `resumeSequence` which will invoke the Observer's [[Observer.onNext onNext]] method if it is able to do so. In such a case, because no + * control to `resumeSequence` which will invoke the Observer's [[Observer.onNext onNext]] + * method if it is able to do so. In such a case, because no * Observable necessarily invokes `onError`, the Observer may never know that an * error happened. * @@ -813,7 +894,8 @@ class Observable[+T] private[scala] (val asJava: rx.Observable[_ <: T]) * another Observable (`resumeSequence`) to an Observable's * `onErrorResumeNext` method, if the original Observable encounters an error, * instead of invoking its Observer's `onError` method, it will instead relinquish - * control to `resumeSequence` which will invoke the Observer's [[Observer.onNext onNext]] method if it is able to do so. In such a case, because no + * control to `resumeSequence` which will invoke the Observer's [[Observer.onNext onNext]] + * method if it is able to do so. In such a case, because no * Observable necessarily invokes `onError`, the Observer may never know that an * error happened. * @@ -878,8 +960,6 @@ class Observable[+T] private[scala] (val asJava: rx.Observable[_ <: T]) * Observable, whose result will be used in the next accumulator call * @return an Observable that emits a single item that is the result of accumulating the * output from the source Observable - * @see MSDN: Observable.Aggregate - * @see Wikipedia: Fold (higher-order function) */ def reduce[U >: T](f: (U, U) => U): Observable[U] = { val func: Func2[_ >: U, _ >: U, _ <: U] = f @@ -957,8 +1037,6 @@ class Observable[+T] private[scala] (val asJava: rx.Observable[_ <: T]) * Observable, the result of which will be used in the next accumulator call * @return an Observable that emits a single item that is the result of accumulating the output * from the items emitted by the source Observable - * @see MSDN: Observable.Aggregate - * @see Wikipedia: Fold (higher-order function) */ def fold[R](initialValue: R)(accumulator: (R, T) => R): Observable[R] = { Observable[R](asJava.reduce(initialValue, accumulator)) @@ -1019,7 +1097,6 @@ class Observable[+T] private[scala] (val asJava: rx.Observable[_ <: T]) * an accumulator function to be invoked on each item emitted by the source * Observable, whose result will be emitted to [[Observer]]s via [[Observer.onNext onNext]] and used in the next accumulator call. * @return an Observable that emits the results of each call to the accumulator function - * @see MSDN: Observable.Scan */ def scan[R](initialValue: R)(accumulator: (R, T) => R): Observable[R] = { Observable[R](asJava.scan(initialValue, accumulator)) @@ -1049,9 +1126,6 @@ class Observable[+T] private[scala] (val asJava: rx.Observable[_ <: T]) * * * - * You can ignore the first `num` items emitted by an Observable and attend only to - * those items that come after, by modifying the Observable with the `skip` method. - * * @param num * the number of items to skip * @return an Observable that is identical to the source Observable except that it does not @@ -1082,7 +1156,8 @@ class Observable[+T] private[scala] (val asJava: rx.Observable[_ <: T]) * * * - * This method returns an Observable that will invoke a subscribing [[Observer]]'s [[Observer.onNext onNext]] function a maximum of `num` times before invoking + * This method returns an Observable that will invoke a subscribing [[Observer]]'s + * [[Observer.onNext onNext]] function a maximum of `num` times before invoking * [[Observer.onCompleted onCompleted]]. * * @param num @@ -1168,7 +1243,8 @@ class Observable[+T] private[scala] (val asJava: rx.Observable[_ <: T]) * * * - * Normally, an Observable that returns multiple items will do so by invoking its [[Observer]]'s [[Observer.onNext onNext]] method for each such item. You can change + * Normally, an Observable that returns multiple items will do so by invoking its [[Observer]]'s + * [[Observer.onNext onNext]] method for each such item. You can change * this behavior, instructing the Observable to compose a list of all of these items and then to * invoke the Observer's `onNext` function once, passing it the entire list, by * calling the Observable's `toList` method prior to calling its `Observable.subscribe` method. @@ -1206,10 +1282,16 @@ class Observable[+T] private[scala] (val asJava: rx.Observable[_ <: T]) * * * + * This operation is only available if `this` is of type `Observable[Observable[U]]` for some `U`, + * otherwise you'll get a compilation error. + * * @param sequenceOfSequences * the source Observable that emits Observables * @return an Observable that emits only the items emitted by the most recently published * Observable + * + * @usecase def switch[U]: Observable[U] + * @inheritdoc */ def switch[U](implicit evidence: Observable[T] <:< Observable[Observable[U]]): Observable[U] = { val o2: Observable[Observable[U]] = this @@ -1271,8 +1353,14 @@ class Observable[+T] private[scala] (val asJava: rx.Observable[_ <: T]) * You can combine the items emitted by multiple Observables so that they act like a single * Observable by using this method. * + * This operation is only available if `this` is of type `Observable[Observable[U]]` for some `U`, + * otherwise you'll get a compilation error. + * * @return an Observable that emits items that are the result of flattening the items emitted * by the Observables emitted by `this` + * + * @usecase def flatten[U]: Observable[U] + * @inheritdoc */ def flatten[U](implicit evidence: Observable[T] <:< Observable[Observable[U]]): Observable[U] = { val o2: Observable[Observable[U]] = this @@ -1283,7 +1371,7 @@ class Observable[+T] private[scala] (val asJava: rx.Observable[_ <: T]) } /** - * This behaves like [[Observable.flatten]] except that if any of the merged Observables + * This behaves like `flatten` except that if any of the merged Observables * notify of an error via [[Observer.onError onError]], this method will * refrain from propagating that error notification until all of the merged Observables have * finished emitting items. @@ -1295,9 +1383,15 @@ class Observable[+T] private[scala] (val asJava: rx.Observable[_ <: T]) * * This method allows an Observer to receive all successfully emitted items from all of the * source Observables without being interrupted by an error notification from one of them. + * + * This operation is only available if `this` is of type `Observable[Observable[U]]` for some `U`, + * otherwise you'll get a compilation error. * * @return an Observable that emits items that are the result of flattening the items emitted by * the Observables emitted by the this Observable + * + * @usecase def flattenDelayError[U]: Observable[U] + * @inheritdoc */ def flattenDelayError[U](implicit evidence: Observable[T] <:< Observable[Observable[U]]): Observable[U] = { val o2: Observable[Observable[U]] = this @@ -1328,11 +1422,7 @@ class Observable[+T] private[scala] (val asJava: rx.Observable[_ <: T]) * * * - * Information on debounce vs throttle: - * - * - http://drupalmotion.com/article/debounce-and-throttle-visual-explanation - * - http://unscriptable.com/2009/03/20/debouncing-javascript-methods/ - * - http://www.illyriad.co.uk/blog/index.php/2011/09/javascript-dont-spam-your-server-debounce-and-throttle/ + * $debounceVsThrottle * * @param timeout * The time each value has to be 'the most recent' of the [[Observable]] to ensure that it's not dropped. @@ -1351,11 +1441,7 @@ class Observable[+T] private[scala] (val asJava: rx.Observable[_ <: T]) * * * - * Information on debounce vs throttle: - * - * - http://drupalmotion.com/article/debounce-and-throttle-visual-explanation - * - http://unscriptable.com/2009/03/20/debouncing-javascript-methods/ - * - http://www.illyriad.co.uk/blog/index.php/2011/09/javascript-dont-spam-your-server-debounce-and-throttle/ + * $debounceVsThrottle * * @param timeout * The time each value has to be 'the most recent' of the [[Observable]] to ensure that it's not dropped. @@ -1374,11 +1460,7 @@ class Observable[+T] private[scala] (val asJava: rx.Observable[_ <: T]) * * * - * Information on debounce vs throttle: - * - * - http://drupalmotion.com/article/debounce-and-throttle-visual-explanation - * - http://unscriptable.com/2009/03/20/debouncing-javascript-methods/ - * - http://www.illyriad.co.uk/blog/index.php/2011/09/javascript-dont-spam-your-server-debounce-and-throttle/ + * $debounceVsThrottle * * @param timeout * The time each value has to be 'the most recent' of the [[Observable]] to ensure that it's not dropped. @@ -1474,8 +1556,14 @@ class Observable[+T] private[scala] (val asJava: rx.Observable[_ <: T]) /** * Returns an Observable that sums up the elements of this Observable. * + * This operation is only available if the elements of this Observable are numbers, otherwise + * you will get a compilation error. + * * @return an Observable emitting the sum of all the elements of the source Observable * as its single item. + * + * @usecase def sum: Observable[T] + * @inheritdoc */ def sum[U >: T](implicit num: Numeric[U]): Observable[U] = { fold(num.zero)(num.plus) @@ -1484,8 +1572,14 @@ class Observable[+T] private[scala] (val asJava: rx.Observable[_ <: T]) /** * Returns an Observable that multiplies up the elements of this Observable. * + * This operation is only available if the elements of this Observable are numbers, otherwise + * you will get a compilation error. + * * @return an Observable emitting the product of all the elements of the source Observable * as its single item. + * + * @usecase def product: Observable[T] + * @inheritdoc */ def product[U >: T](implicit num: Numeric[U]): Observable[U] = { fold(num.one)(num.times) @@ -1678,7 +1772,9 @@ class Observable[+T] private[scala] (val asJava: rx.Observable[_ <: T]) } /** - * Perform work in parallel by sharding an `Observable[T]` on a [[rx.lang.scala.concurrency.Schedulers.threadPoolForComputation]] [[Scheduler]] and return an `Observable[R]` with the output. + * Perform work in parallel by sharding an `Observable[T]` on a + * [[rx.lang.scala.concurrency.Schedulers.threadPoolForComputation computation]] + * [[Scheduler]] and return an `Observable[R]` with the output. * * @param f * a function that applies Observable operators to `Observable[T]` in parallel and returns an `Observable[R]` @@ -1753,7 +1849,10 @@ object Observable { val oScala1: Observable[rx.Observable[_ <: T]] = new Observable[rx.Observable[_ <: T]](jObs) oScala1.map((oJava: rx.Observable[_ <: T]) => new Observable[T](oJava)) } - + + /** + * Creates a new Scala Observable from a given Java Observable. + */ def apply[T](asJava: rx.Observable[_ <: T]): Observable[T] = { new Observable[T](asJava) } @@ -1807,7 +1906,8 @@ object Observable { * * * - * Implementation note: the entire array will be immediately emitted each time an [[Observer]] subscribes. Since this occurs before the [[Subscription]] is returned, + * Implementation note: the entire array will be immediately emitted each time an [[Observer]] subscribes. + * Since this occurs before the [[Subscription]] is returned, * it in not possible to unsubscribe from the sequence before it completes. * * @param items @@ -1839,10 +1939,9 @@ object Observable { /** * Returns an Observable that calls an Observable factory to create its Observable for each - * new Observer that subscribes. That is, for each subscriber, the actuall Observable is determined + * new Observer that subscribes. That is, for each subscriber, the actual Observable is determined * by the factory function. * - * * * * The defer operator allows you to defer or delay emitting items from an Observable until such @@ -1920,7 +2019,7 @@ object Observable { } /** - * Emits 0, 1, 2, ... with a delay of `duration` between consecutive numbers. + * Emits `0`, `1`, `2`, `...` with a delay of `duration` between consecutive numbers. * * * @@ -1933,7 +2032,7 @@ object Observable { } /** - * Emits 0, 1, 2, ... with a delay of `duration` between consecutive numbers. + * Emits `0`, `1`, `2`, `...` with a delay of `duration` between consecutive numbers. * * * diff --git a/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/Scheduler.scala b/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/Scheduler.scala index 12f452db59..c717a94af5 100644 --- a/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/Scheduler.scala +++ b/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/Scheduler.scala @@ -129,7 +129,7 @@ trait Scheduler { } /** - * @return the scheduler's notion of current absolute time in milliseconds. + * Returns the scheduler's notion of current absolute time in milliseconds. */ def now: Long = { asJava.now diff --git a/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/observables/package.scala b/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/observables/package.scala index 8a2241d086..8507f0a54c 100644 --- a/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/observables/package.scala +++ b/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/observables/package.scala @@ -3,7 +3,7 @@ package rx.lang.scala /** * Contains special Observables. * - * In Scala, this package only contains [[rx.lang.scala.observables.BlockingObservable]]. + * In Scala, this package only contains [[BlockingObservable]]. * In the corresponding Java package `rx.observables`, there is also a * `GroupedObservable` and a `ConnectableObservable`, but these are not needed * in Scala, because we use a pair `(key, observable)` instead of `GroupedObservable` diff --git a/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/package.scala b/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/package.scala index 9356b08f6b..8aa0e63760 100644 --- a/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/package.scala +++ b/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/package.scala @@ -50,40 +50,40 @@ package object scala { /** * Provides a mechanism for receiving push-based notifications. * - * After an Observer calls an [[rx.lang.scala.Observable]]'s `subscribe` method, the Observable + * After an Observer calls an [[Observable]]'s `subscribe` method, the Observable * calls the Observer's `onNext` method to provide notifications. A well-behaved Observable will * call an Observer's `onCompleted` method exactly once or the Observer's `onError` method exactly once. */ trait Observer[-T] { /** - * Notifies the Observer that the [[rx.lang.scala.Observable]] has finished sending push-based notifications. + * Notifies the Observer that the [[Observable]] has finished sending push-based notifications. * - * The [[rx.lang.scala.Observable]] will not call this method if it calls `onError`. + * The [[Observable]] will not call this method if it calls `onError`. */ def onCompleted(): Unit /** - * Notifies the Observer that the [[rx.lang.scala.Observable]] has experienced an error condition. + * Notifies the Observer that the [[Observable]] has experienced an error condition. * - * If the [[rx.lang.scala.Observable]] calls this method, it will not thereafter call `onNext` or `onCompleted`. + * If the [[Observable]] calls this method, it will not thereafter call `onNext` or `onCompleted`. */ def onError(e: Throwable): Unit /** * Provides the Observer with new data. * - * The [[rx.lang.scala.Observable]] calls this closure 0 or more times. + * The [[Observable]] calls this closure 0 or more times. * - * The [[rx.lang.scala.Observable]] will not call this method again after it calls either `onCompleted` or `onError`. + * The [[Observable]] will not call this method again after it calls either `onCompleted` or `onError`. */ def onNext(arg: T): Unit } /** - * Subscriptions are returned from all Observable.subscribe methods to allow unsubscribing. + * Subscriptions are returned from all `Observable.subscribe` methods to allow unsubscribing. * - * This interface is the equivalent of IDisposable in the .NET Rx implementation. + * This interface is the equivalent of `IDisposable` in the .NET Rx implementation. */ trait Subscription { /** @@ -115,13 +115,13 @@ package object scala { private[scala] implicit def rxObserver2fakeObserver[T](o: rx.Observer[_ >: T]): Observer[T] = ??? *///#else - + type Observer[-T] = rx.Observer[_ >: T] type Subscription = rx.Subscription - + //#endif - + /** * Allows to construct observables in a similar way as futures. * diff --git a/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/util/package.scala b/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/util/package.scala index 7913808794..ed19d849ab 100644 --- a/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/util/package.scala +++ b/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/util/package.scala @@ -16,7 +16,7 @@ package rx.lang.scala /** - * Provides [[rx.lang.scala.util.Opening]]s, [[rx.lang.scala.util.Closing]]s, and [[rx.lang.scala.util.Timestamped]]. + * Provides [[Opening]]s, [[Closing]]s, and [[Timestamped]]. */ package object util { From 01f54644229db8061d1a507abe5dd18b169ec317 Mon Sep 17 00:00:00 2001 From: samuelgruetter Date: Wed, 2 Oct 2013 17:32:40 +0200 Subject: [PATCH 30/33] rename fold to foldLeft --- .../scala/rx/lang/scala/examples/RxScalaDemo.scala | 2 +- .../src/main/scala/rx/lang/scala/Observable.scala | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/language-adaptors/rxjava-scala/src/examples/scala/rx/lang/scala/examples/RxScalaDemo.scala b/language-adaptors/rxjava-scala/src/examples/scala/rx/lang/scala/examples/RxScalaDemo.scala index a449737acf..cb59c7246b 100644 --- a/language-adaptors/rxjava-scala/src/examples/scala/rx/lang/scala/examples/RxScalaDemo.scala +++ b/language-adaptors/rxjava-scala/src/examples/scala/rx/lang/scala/examples/RxScalaDemo.scala @@ -289,7 +289,7 @@ class RxScalaDemo extends JUnitSuite { // We can't put a general average method into Observable.scala, because Scala's Numeric // does not have scalar multiplication (we would need to calculate (1.0/numberOfElements)*sum) def doubleAverage(o: Observable[Double]): Observable[Double] = { - for ((finalSum, finalCount) <- o.fold((0.0, 0))({case ((sum, count), elem) => (sum+elem, count+1)})) + for ((finalSum, finalCount) <- o.foldLeft((0.0, 0))({case ((sum, count), elem) => (sum+elem, count+1)})) yield finalSum / finalCount } diff --git a/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/Observable.scala b/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/Observable.scala index cbbac22aa0..8e6a2d658e 100644 --- a/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/Observable.scala +++ b/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/Observable.scala @@ -1038,7 +1038,7 @@ class Observable[+T] private[scala] (val asJava: rx.Observable[_ <: T]) * @return an Observable that emits a single item that is the result of accumulating the output * from the items emitted by the source Observable */ - def fold[R](initialValue: R)(accumulator: (R, T) => R): Observable[R] = { + def foldLeft[R](initialValue: R)(accumulator: (R, T) => R): Observable[R] = { Observable[R](asJava.reduce(initialValue, accumulator)) } @@ -1117,7 +1117,7 @@ class Observable[+T] private[scala] (val asJava: rx.Observable[_ <: T]) // type mismatch; found : rx.Observable[java.lang.Boolean] required: rx.Observable[_ <: scala.Boolean] // new Observable[Boolean](asJava.all(predicate)) // it's more fun in Scala: - this.map(predicate).fold(true)(_ && _) + this.map(predicate).foldLeft(true)(_ && _) } /** @@ -1566,7 +1566,7 @@ class Observable[+T] private[scala] (val asJava: rx.Observable[_ <: T]) * @inheritdoc */ def sum[U >: T](implicit num: Numeric[U]): Observable[U] = { - fold(num.zero)(num.plus) + foldLeft(num.zero)(num.plus) } /** @@ -1582,7 +1582,7 @@ class Observable[+T] private[scala] (val asJava: rx.Observable[_ <: T]) * @inheritdoc */ def product[U >: T](implicit num: Numeric[U]): Observable[U] = { - fold(num.one)(num.times) + foldLeft(num.one)(num.times) } /** @@ -1598,7 +1598,7 @@ class Observable[+T] private[scala] (val asJava: rx.Observable[_ <: T]) * if the source Observable completes without emitting any item. */ def firstOrElse[U >: T](default: => U): Observable[U] = { - this.take(1).fold[Option[U]](None)((v: Option[U], e: U) => Some(e)).map({ + this.take(1).foldLeft[Option[U]](None)((v: Option[U], e: U) => Some(e)).map({ case Some(element) => element case None => default }) From f3734bfad009063f75be0bb75f5379dd5bedd593 Mon Sep 17 00:00:00 2001 From: samuelgruetter Date: Wed, 2 Oct 2013 17:37:40 +0200 Subject: [PATCH 31/33] remove takeWhileWithIndex --- .../rx/lang/scala/examples/RxScalaDemo.scala | 5 +++++ .../main/scala/rx/lang/scala/Observable.scala | 17 ----------------- 2 files changed, 5 insertions(+), 17 deletions(-) diff --git a/language-adaptors/rxjava-scala/src/examples/scala/rx/lang/scala/examples/RxScalaDemo.scala b/language-adaptors/rxjava-scala/src/examples/scala/rx/lang/scala/examples/RxScalaDemo.scala index cb59c7246b..950081e8ce 100644 --- a/language-adaptors/rxjava-scala/src/examples/scala/rx/lang/scala/examples/RxScalaDemo.scala +++ b/language-adaptors/rxjava-scala/src/examples/scala/rx/lang/scala/examples/RxScalaDemo.scala @@ -454,6 +454,11 @@ class RxScalaDemo extends JUnitSuite { Thread.sleep(1500) // or convert to BlockingObservable } + @Test def takeWhileWithIndexAlternative { + val condition = true + Observable("a", "b").zipWithIndex.takeWhile{case (elem, index) => condition}.map(_._1) + } + def output(s: String): Unit = println(s) // blocks until obs has completed diff --git a/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/Observable.scala b/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/Observable.scala index 8e6a2d658e..776640357b 100644 --- a/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/Observable.scala +++ b/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/Observable.scala @@ -1185,23 +1185,6 @@ class Observable[+T] private[scala] (val asJava: rx.Observable[_ <: T]) def takeWhile(predicate: T => Boolean): Observable[T] = { Observable[T](asJava.takeWhile(predicate)) } - - /** - * Returns an Observable that emits the items emitted by a source Observable so long as a given - * predicate remains true, where the predicate can operate on both the item and its index - * relative to the complete sequence. - * - * - * - * @param predicate - * a function to test each item emitted by the source Observable for a condition; - * the second parameter of the function represents the index of the source item - * @return an Observable that emits items from the source Observable so long as the predicate - * continues to return `true` for each item, then completes - */ - def takeWhileWithIndex(predicate: (T, Integer) => Boolean): Observable[T] = { - Observable[T](asJava.takeWhileWithIndex(predicate)) - } /** * Returns an Observable that emits only the last `count` items emitted by the source From c66b2ebabfd695b8060b8614c73a22442cb4a4a1 Mon Sep 17 00:00:00 2001 From: samuelgruetter Date: Wed, 2 Oct 2013 17:43:58 +0200 Subject: [PATCH 32/33] use Tuple instead of Timestamped --- .../rx/lang/scala/examples/RxScalaDemo.scala | 3 +- .../main/scala/rx/lang/scala/Observable.scala | 7 ++-- .../rx/lang/scala/util/Timestamped.scala | 34 ------------------- 3 files changed, 5 insertions(+), 39 deletions(-) delete mode 100644 language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/util/Timestamped.scala diff --git a/language-adaptors/rxjava-scala/src/examples/scala/rx/lang/scala/examples/RxScalaDemo.scala b/language-adaptors/rxjava-scala/src/examples/scala/rx/lang/scala/examples/RxScalaDemo.scala index 950081e8ce..fe1747a1e6 100644 --- a/language-adaptors/rxjava-scala/src/examples/scala/rx/lang/scala/examples/RxScalaDemo.scala +++ b/language-adaptors/rxjava-scala/src/examples/scala/rx/lang/scala/examples/RxScalaDemo.scala @@ -22,7 +22,6 @@ import scala.concurrent.duration._ import org.junit.{Before, Test, Ignore} import org.junit.Assert._ import rx.lang.scala.concurrency.Schedulers -import rx.lang.scala.util.Timestamped import java.io.IOException @Ignore // Since this doesn't do automatic testing, don't increase build time unnecessarily @@ -379,7 +378,7 @@ class RxScalaDemo extends JUnitSuite { @Test def timestampExample() { val timestamped = Observable.interval(100 millis).take(3).timestamp.toBlockingObservable - for (Timestamped(millis, value) <- timestamped if value > 0) { + for ((millis, value) <- timestamped if value > 0) { println(value + " at t = " + millis) } } diff --git a/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/Observable.scala b/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/Observable.scala index 776640357b..d845a65fa5 100644 --- a/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/Observable.scala +++ b/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/Observable.scala @@ -246,14 +246,15 @@ class Observable[+T] private[scala] (val asJava: rx.Observable[_ <: T]) } /** - * Wraps each item emitted by a source Observable in a [[rx.lang.scala.util.Timestamped]] object. + * Wraps each item emitted by a source Observable in a timestamped tuple. * * * * @return an Observable that emits timestamped items from the source Observable */ - def timestamp: Observable[Timestamped[T]] = { - Observable[rx.util.Timestamped[_ <: T]](asJava.timestamp()).map(Timestamped(_)) + def timestamp: Observable[(Long, T)] = { + Observable[rx.util.Timestamped[_ <: T]](asJava.timestamp()) + .map((t: rx.util.Timestamped[_ <: T]) => (t.getTimestampMillis, t.getValue())) } /** diff --git a/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/util/Timestamped.scala b/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/util/Timestamped.scala deleted file mode 100644 index e00b9bb17e..0000000000 --- a/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/util/Timestamped.scala +++ /dev/null @@ -1,34 +0,0 @@ -package rx.lang.scala.util - -/** - * Wraps a value and a timestamp. - */ -// constructor is private because users should use apply from companion -class Timestamped[+T] private[util] (val asJava: rx.util.Timestamped[_ <: T]) extends AnyVal { - /** - * Returns the timestamp, in milliseconds. - */ - def millis: Long = asJava.getTimestampMillis - - /** - * Returns the value. - */ - def value: T = asJava.getValue : T -} - -/** - * Provides constructor and pattern matching functionality for `Timestamped`. - */ -object Timestamped { - def apply[T](timestampMillis: Long, value: T): Timestamped[T] = { - new Timestamped(new rx.util.Timestamped(timestampMillis, value)) - } - - def apply[T](asJava: rx.util.Timestamped[_ <: T]): Timestamped[T] = { - new Timestamped(asJava) - } - - def unapply[T](v: Timestamped[T]): Option[(Long, T)] = { - Some((v.millis, v.value)) - } -} From 677f84c4c37186367e448652f5e364120ecf4c9e Mon Sep 17 00:00:00 2001 From: samuelgruetter Date: Wed, 2 Oct 2013 17:53:42 +0200 Subject: [PATCH 33/33] update completeness test --- .../scala/rx/lang/scala/CompletenessTest.scala | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/language-adaptors/rxjava-scala/src/test/scala/rx/lang/scala/CompletenessTest.scala b/language-adaptors/rxjava-scala/src/test/scala/rx/lang/scala/CompletenessTest.scala index cf22630a3a..d9c26c54c0 100644 --- a/language-adaptors/rxjava-scala/src/test/scala/rx/lang/scala/CompletenessTest.scala +++ b/language-adaptors/rxjava-scala/src/test/scala/rx/lang/scala/CompletenessTest.scala @@ -22,11 +22,14 @@ class CompletenessTest extends JUnitSuite { "You can use `fold` instead to accumulate `sum` and `numberOfElements` and divide at the end.]" val commentForFirstWithPredicate = "[use `.filter(condition).first`]" + + val fromFuture = "[TODO: Decide how Scala Futures should relate to Observables. Should there be a " + + "common base interface for Future and Observable? And should Futures also have an unsubscribe method?]" val correspondence = defaultMethodCorrespondence ++ Map( // manually added entries for Java instance methods "aggregate(Func2[T, T, T])" -> "reduce((U, U) => U)", - "aggregate(R, Func2[R, _ >: T, R])" -> "fold(R)((R, T) => R)", + "aggregate(R, Func2[R, _ >: T, R])" -> "foldLeft(R)((R, T) => R)", "all(Func1[_ >: T, Boolean])" -> "forall(T => Boolean)", "buffer(Long, Long, TimeUnit)" -> "buffer(Duration, Duration)", "buffer(Long, Long, TimeUnit, Scheduler)" -> "buffer(Duration, Duration, Scheduler)", @@ -47,7 +50,7 @@ class CompletenessTest extends JUnitSuite { "parallel(Func1[Observable[T], Observable[R]])" -> "parallel(Observable[T] => Observable[R])", "parallel(Func1[Observable[T], Observable[R]], Scheduler)" -> "parallel(Observable[T] => Observable[R], Scheduler)", "reduce(Func2[T, T, T])" -> "reduce((U, U) => U)", - "reduce(R, Func2[R, _ >: T, R])" -> "fold(R)((R, T) => R)", + "reduce(R, Func2[R, _ >: T, R])" -> "foldLeft(R)((R, T) => R)", "scan(Func2[T, T, T])" -> unnecessary, "scan(R, Func2[R, _ >: T, R])" -> "scan(R)((R, T) => R)", "skip(Int)" -> "drop(Int)", @@ -57,6 +60,7 @@ class CompletenessTest extends JUnitSuite { "takeFirst()" -> "first", "takeFirst(Func1[_ >: T, Boolean])" -> commentForFirstWithPredicate, "takeLast(Int)" -> "takeRight(Int)", + "takeWhileWithIndex(Func2[_ >: T, _ >: Integer, Boolean])" -> "[use `.zipWithIndex.takeWhile{case (elem, index) => condition}.map(_._1)`]", "toList()" -> "toSeq", "toSortedList()" -> "[Sorting is already done in Scala's collection library, use `.toSeq.map(_.sorted)`]", "toSortedList(Func2[_ >: T, _ >: T, Integer])" -> "[Sorting is already done in Scala's collection library, use `.toSeq.map(_.sortWith(f))`]", @@ -77,9 +81,10 @@ class CompletenessTest extends JUnitSuite { "error(Throwable)" -> "apply(Throwable)", "from(Array[T])" -> "apply(T*)", "from(Iterable[_ <: T])" -> "apply(T*)", - "from(Future[_ <: T])" -> "apply(Future[T])", - "from(Future[_ <: T], Long, TimeUnit)" -> "apply(Future[T], Duration)", - "from(Future[_ <: T], Scheduler)" -> "apply(Future[T], Scheduler)", + "from(Future[_ <: T])" -> fromFuture, + "from(Future[_ <: T], Long, TimeUnit)" -> fromFuture, + "from(Future[_ <: T], Scheduler)" -> fromFuture, + "just(T)" -> "apply(T*)", "merge(Observable[_ <: T], Observable[_ <: T])" -> "merge(Observable[U])", "merge(Observable[_ <: Observable[_ <: T]])" -> "flatten(<:<[Observable[T], Observable[Observable[U]]])", "mergeDelayError(Observable[_ <: T], Observable[_ <: T])" -> "mergeDelayError(Observable[U])", @@ -298,7 +303,7 @@ class CompletenessTest extends JUnitSuite { (if (p._1.startsWith("average")) "average" else p._1.takeWhile(_ != '('), p._2) def formatJavaCol(name: String, alternatives: Iterable[String]): String = { alternatives.toList.sorted.map(scalaToJavaSignature(_)).map(s => { - if (s.length > 50) { + if (s.length > 64) { val toolTip = escapeJava(s) "" + name + "(...)" } else {