Rx
Reactive operators for Observables.
Attributes
Members list
Type members
Types
A Binding that can be terminated.
A Binding that can be terminated.
Once the value turned into a scala.None, this Observable would be considered as terminated, and any future changes of this Observable will be ignored by any Rx operators derived from this Observable, even if this Observable turns into a scala.Some value again.
Attributes
- Note:
Even though an Observable is technically a Binding, an Observable created from a Rx operator does not actually indicates data-binding. For example, given an Observable created from Rx.concat,
import com.thoughtworks.binding.Binding._ val sourceObservable0 = Var[Option[String]](Some("0")) val sourceObservable1 = Var[Option[String]](Some("1")) val sourceObservables = List(sourceObservable0, sourceObservable1) val derivedObservable = Rx.concat(sourceObservables) derivedObservable.watch()
when a source value gets changed,
val originalDerivedObservableValue = derivedObservable.get sourceObservable0.value = None
and the source value is changed back to the original value,
sourceObservable0.value = Some("0")
then the value of the derived observable might not be the original value.
derivedObservable.get shouldNot be(originalDerivedObservableValue)
In contrast, if the
concat
operator is implemented by ordinary Binding.bind macros, the derived Binding is indeed a data-binding, i.e. it always perform the same calculation for the same values of source Bindings.import com.thoughtworks.binding.Binding._ val sourceBinding0 = Var[Option[String]](Some("0")) val sourceBinding1 = Var[Option[String]](Some("1")) val sourceBindings = List(sourceBinding0, sourceBinding1) def concatBinding( sourceBindings: collection.LinearSeq[Rx.Observable[String]] ): Rx.Observable[String] = { sourceBindings match { case head +: tail => Binding { head.bind match { case None => concatBinding(tail).bind case someValue => someValue } } case _ => Constant(None) } } val derivedBinding = concatBinding(sourceBindings) derivedBinding.watch() val originalDerivedBindingValue = derivedBinding.get sourceBinding0.value = None sourceBinding0.value = Some("0") derivedBinding.get should be(originalDerivedBindingValue)
Value members
Concrete methods
Emit the emissions from two or more Observables without interleaving them.
Emit the emissions from two or more Observables without interleaving them.
Attributes
- See also:
- Example:
Given a sequence of Observables,
import com.thoughtworks.binding.Binding._ val observable0 = Var[Option[String]](None) val observable1 = Var[Option[String]](Some("1")) val observable2 = Var[Option[String]](Some("2")) val observable3 = Var[Option[String]](None) val observable4 = Var[Option[String]](None) val observable7 = Var[Option[String]](Some("7")) val observable8 = Binding { observable7.bind.map { v => s"8-$v-derived" } } val observable5 = Binding { observable7.bind.map { v => s"5-$v-derived" } } val observable6 = Var[Option[String]](None) val observable9 = Var[Option[String]](Some("9")) val observables = Seq( observable0, observable1, observable2, observable3, observable4, observable5, observable6, observable7, observable8, observable9, )
when concatenate them together,
val concatenated = Rx.concat(observables).map(identity) concatenated.watch()
the concatenated value should be the first scala.Some value in the sequence of observables;
concatenated.get should be(Some("1"))
when the current observable becomes
None
,observable1.value = None
the concatenated value should be the next scala.Some value in the sequence of observables,
concatenated.get should be(Some("2"))
even when the next scala.Some value is derived from another Binding;
observable2.value = None concatenated.get should be(Some("5-7-derived"))
when the value of the upstream Binding is changed to another scala.Some value,
observable7.value = Some("7-running")
the concatenated value should be changed accordingly;
concatenated.get should be(Some("5-7-running-derived"))
when multiple observables become scala.None at once,
observable7.value = None
they all should be skipped when calculate the concatenated value;
concatenated.get should be(Some("9"))
when the last observable in the sequence becomes scala.None,
observable9.value = None
the concatenated value should become scala.None permanently,
concatenated.get should be(None)
even when some observables in the sequence become scala.Some again.
observable9.value = Some("9-after-termination") concatenated.get should be(None) observable7.value = Some("7-after-termination") concatenated.get should be(None)
do not create the Observable until the observer subscribes
do not create the Observable until the observer subscribes
Attributes
- See also:
- Note:
This defer is slightly different from other implementation the ReactiveX Defer operator, because this defer shares the same upstream Observable instance for all subscribes.
- Example:
Circular referenced Observables can be created with the help of defer
import Binding._ val source = Var("init") lazy val observable1: Rx.Observable[String] = Binding[Option[String]] { source.bind match { case "init" => None case v => observable2.bind.map(_ + "_" + v) } } lazy val observable2: Rx.Observable[String] = Rx.defer( Binding[Option[String]] { Some(observable1.getClass.getSimpleName) } )
Initially,
observable1
did not subscribeobservable2
becausesource
isinit
,observable1.watch()
therefore observable2 should be
None
,observable1.get should be (None) observable2.get should be (None)
when
source
changed,source.value = "changed"
observable1
should subscribeobservable2
, and there should beSome
values.observable1.get should be (Some("FlatMap_changed")) observable2.get should be (Some("FlatMap"))
Even though circular referenced Observables can be created in this way, their calculation must not be mutually dependent.
Attributes
- See also:
Combine multiple Observables into one by merging their emissions.
Combine multiple Observables into one by merging their emissions.
Attributes
- See also:
- Example:
Given a sequence of Observables,
import com.thoughtworks.binding.Binding._ val observable0 = Var[Option[String]](None) val observable1 = Var[Option[String]](Some("1")) val observable2 = Var[Option[String]](Some("2")) val observable3 = Var[Option[String]](None) val observable4 = Var[Option[String]](None) val observable7 = Var[Option[String]](Some("7")) val observable8 = Binding { observable7.bind.map { v => s"8-$v-derived" } } val observable5 = Binding { observable7.bind.map { v => s"5-$v-derived" } } val observable6 = Var[Option[String]](None) val observable9 = Var[Option[String]](Some("9")) val observables = Seq( observable0, observable1, observable2, observable3, observable4, observable5, observable6, observable7, observable8, observable9, )
when merge them together,
val merged = Rx.merge(observables).map(identity) merged.watch()
the merged value should be the first scala.Some value in the sequence of observables;
merged.get should be(Some("1"))
when the some but not all of the observable becomes
None
,observable1.value = None
the merged value should be unchanged,
merged.get should be(Some("1"))
when any of the observable becomes
Some
value,observable2.value = Some("2-changed")
the merged value should be the new value,
merged.get should be(Some("2-changed"))
even when a previous
None
observable becomesSome
value,,observable3.value = Some("3-previous-None")
the merged value should be the new value of the previous
None
observable,merged.get should be(Some("3-previous-None"))
when multiple observables are changed at once,
observable7.value = Some("7-changed")
the merged value should be the value of the last derived observable
merged.get should be(Some("8-7-changed-derived"))
when all the observables become
None
,observable1.value = None merged.get should be(Some("8-7-changed-derived")) observable2.value = None merged.get should be(Some("8-7-changed-derived")) observable3.value = None merged.get should be(Some("8-7-changed-derived")) observable6.value = None merged.get should be(Some("8-7-changed-derived")) observable7.value = None merged.get should be(Some("8-7-changed-derived")) observable9.value = None merged.get should be(None)
Attributes
- See also:
convert an Observable into a BindingSeq.
convert an Observable into a BindingSeq.
Attributes
- See also:
- Example:
Given a source observable,
import com.thoughtworks.binding.Binding._ val observable = Var[Option[String]](Some("1"))
when converting it into a BindingSeq,
val bindingSeq = Rx.toBindingSeq(observable)
and flat-mapping to the result,
val result = new BindingSeq.FlatMap( bindingSeq, { value: String => Constants("the value is", value) } ).all result.watch()
then result should have the values corresponding to the source observable,
result.get.toSeq should contain theSameElementsInOrderAs Seq("the value is", "1")
when the source observable changes,
observable.value = Some("2")
then the corresponding new value should be appended to the result,
result.get.toSeq should contain theSameElementsInOrderAs Seq( "the value is", "1", "the value is", "2" )
when the source observable terminates,
observable.value = None
then the result should be empty
result.get.toSeq should be(empty)