@@ -17,18 +17,21 @@ package rx.lang.scala.observables
17
17
18
18
import scala .collection .JavaConverters ._
19
19
import rx .lang .scala .ImplicitFunctionConversions ._
20
+ import rx .lang .scala .Observable
21
+ import rx .observables .{BlockingObservable => JBlockingObservable }
20
22
21
23
22
24
/**
23
25
* An Observable that provides blocking operators.
24
26
*
25
- * You can obtain a BlockingObservable from an Observable using [[rx.lang.scala.Observable.toBlockingObservable ]]
27
+ * You can obtain a BlockingObservable from an Observable using [[rx.lang.scala.Observable.toBlocking ]]
26
28
*/
27
- // constructor is private because users should use Observable.toBlockingObservable
28
- class BlockingObservable [+ T ] private [scala] (val asJava : rx.observables. BlockingObservable [_ <: T ])
29
- extends AnyVal
29
+ // constructor is private because users should use Observable.toBlocking
30
+ class BlockingObservable [+ T ] private [scala] (val o : Observable [ T ])
31
+ extends AnyVal
30
32
{
31
-
33
+ // This is def because "field definition is not allowed in value class"
34
+ private def asJava : JBlockingObservable [_ <: T ] = o.asJavaObservable.toBlocking
32
35
/**
33
36
* Invoke a method on each item emitted by the {@link Observable}; block until the Observable
34
37
* completes.
@@ -69,6 +72,34 @@ class BlockingObservable[+T] private[scala] (val asJava: rx.observables.Blocking
69
72
asJava.last : T
70
73
}
71
74
75
+ /**
76
+ * Returns an `Option` with the last item emitted by the source Observable,
77
+ * or `None` if the source Observable completes without emitting any items.
78
+ *
79
+ * @return an `Option` with the last item emitted by the source Observable,
80
+ * or `None` if the source Observable is empty
81
+ */
82
+ def lastOption : Option [T ] = {
83
+ o.lastOption.toBlocking.single
84
+ }
85
+
86
+ /**
87
+ * Returns the last item emitted by the source Observable, or a default item
88
+ * if the source Observable completes without emitting any items.
89
+ *
90
+ * <img width="640" src="https://raw.github.com/wiki/Netflix/RxJava/images/rx-operators/lastOrDefault.png">
91
+ *
92
+ * @param default the default item to emit if the source Observable is empty.
93
+ * This is a by-name parameter, so it is only evaluated if the source Observable doesn't emit anything.
94
+ * @return the last item emitted by the source Observable, or a default item if the source Observable is empty
95
+ */
96
+ def lastOrElse [U >: T ](default : => U ): U = {
97
+ lastOption match {
98
+ case Some (element) => element
99
+ case None => default
100
+ }
101
+ }
102
+
72
103
/**
73
104
* Returns the first item emitted by a specified [[Observable ]], or
74
105
* `NoSuchElementException` if source contains no elements.
@@ -96,12 +127,32 @@ class BlockingObservable[+T] private[scala] (val asJava: rx.observables.Blocking
96
127
*/
97
128
def head : T = first
98
129
99
- // last -> use toIterable.last
100
- // lastOrDefault -> use toIterable.lastOption
101
- // first -> use toIterable.head
102
- // firstOrDefault -> use toIterable.headOption
103
- // single(predicate) -> use filter and single
104
- // singleOrDefault -> use singleOption
130
+ /**
131
+ * Returns an `Option` with the very first item emitted by the source Observable,
132
+ * or `None` if the source Observable is empty.
133
+ *
134
+ * @return an `Option` with the very first item from the source,
135
+ * or `None` if the source Observable completes without emitting any item.
136
+ */
137
+ def headOption : Option [T ] = {
138
+ o.headOption.toBlocking.single
139
+ }
140
+
141
+ /**
142
+ * Returns the very first item emitted by the source Observable, or a default value if the source Observable is empty.
143
+ *
144
+ * <img width="640" src="https://raw.github.com/wiki/Netflix/RxJava/images/rx-operators/firstOrDefault.png">
145
+ *
146
+ * @param default The default value to emit if the source Observable doesn't emit anything.
147
+ * This is a by-name parameter, so it is only evaluated if the source Observable doesn't emit anything.
148
+ * @return the very first item from the source, or a default value if the source Observable completes without emitting any item.
149
+ */
150
+ def headOrElse [U >: T ](default : => U ): U = {
151
+ headOption match {
152
+ case Some (element) => element
153
+ case None => default
154
+ }
155
+ }
105
156
106
157
/**
107
158
* Returns an {@link Iterable} that always returns the item most recently emitted by an {@link Observable}.
@@ -130,29 +181,50 @@ class BlockingObservable[+T] private[scala] (val asJava: rx.observables.Blocking
130
181
}
131
182
132
183
/**
133
- * If this {@link Observable} completes after emitting a single item, return that item,
134
- * otherwise throw an exception.
135
- * <p>
136
- * <img width="640" src="https://github.com/Netflix/RxJava/wiki/images/rx-operators/B.single.png">
184
+ * If the source Observable completes after emitting a single item, return that item. If the source Observable
185
+ * emits more than one item or no items, notify of an `IllegalArgumentException` or `NoSuchElementException` respectively.
137
186
*
138
- * @return the single item emitted by the {@link Observable}
187
+ * <img width="640" src="https://raw.github.com/wiki/Netflix/RxJava/images/rx-operators/single.png">
188
+ *
189
+ * @return an Observable that emits the single item emitted by the source Observable
190
+ * @throws IllegalArgumentException if the source emits more than one item
191
+ * @throws NoSuchElementException if the source emits no items
139
192
*/
140
193
def single : T = {
141
194
asJava.single(): T // useless ascription because of compiler bug
142
195
}
143
196
144
197
/**
145
- * If this {@link Observable} completes after emitting a single item, return an Option containing
146
- * this item, otherwise return {@code None}.
198
+ * If the source Observable completes after emitting a single item, return an `Option` with that item;
199
+ * if the source Observable is empty, return `None`. If the source Observable emits more than one item,
200
+ * throw an `IllegalArgumentException`.
201
+ *
202
+ * @return an `Option` with the single item emitted by the source Observable, or
203
+ * `None` if the source Observable is empty
204
+ * @throws IllegalArgumentException if the source Observable emits more than one item
147
205
*/
148
206
def singleOption : Option [T ] = {
149
- var size : Int = 0
150
- var last : Option [T ] = None
151
- for (t <- toIterable) {
152
- size += 1
153
- last = Some (t)
207
+ o.singleOption.toBlocking.single
208
+ }
209
+
210
+ /**
211
+ * If the source Observable completes after emitting a single item, return that item;
212
+ * if the source Observable is empty, return a default item. If the source Observable
213
+ * emits more than one item, throw an `IllegalArgumentException`.
214
+ *
215
+ * <img width="640" src="https://raw.github.com/wiki/Netflix/RxJava/images/rx-operators/singleOrDefault.png">
216
+ *
217
+ * @param default a default value to emit if the source Observable emits no item.
218
+ * This is a by-name parameter, so it is only evaluated if the source Observable doesn't emit anything.
219
+ * @return the single item emitted by the source Observable, or a default item if
220
+ * the source Observable is empty
221
+ * @throws IllegalArgumentException if the source Observable emits more than one item
222
+ */
223
+ def singleOrElse [U >: T ](default : => U ): U = {
224
+ singleOption match {
225
+ case Some (element) => element
226
+ case None => default
154
227
}
155
- if (size == 1 ) last else None
156
228
}
157
229
158
230
// TODO toFuture()
0 commit comments