@@ -190,6 +190,107 @@ def combineLatest(other, &result_selector)
190
190
end
191
191
end
192
192
193
+ # Concatenates the second observable sequence to the first observable sequence upon successful termination of the first.
194
+ def concat ( other )
195
+ Observable . concat ( [ self , other ] . to_enum )
196
+ end
197
+
198
+ # Merges elements from all inner observable sequences into a single observable sequence, limiting the number of concurrent subscriptions to inner sequences.
199
+ def merge_concurrent ( max_concurrent = 1 )
200
+ AnonymousObservable . new do |observer |
201
+ gate = Mutex . new
202
+ q = [ ]
203
+ stopped = false
204
+ group = CompositeSubscription . new
205
+ active = 0
206
+
207
+ subscriber = lambda do |xs |
208
+ subscription = SingleAssignmentSubscription . new
209
+ group >> subscription
210
+
211
+ new_obs = Observer . configure do |o |
212
+ o . on_next { |x | gate . synchronize { observer . on_next x } }
213
+
214
+ o . on_error { |err | gate . synchronize { observer . on_error err } }
215
+
216
+ o . on_completed do
217
+ group . delete subscription
218
+ gate . synchronize do
219
+ if q . length > 0
220
+ s = q . shift
221
+ subscriber . call s
222
+ else
223
+ active -= 1
224
+ observer . on_completed if stopped && active == 0
225
+ end
226
+ end
227
+ end
228
+ end
229
+
230
+ xs . subscribe new_obs
231
+ end
232
+
233
+ inner_obs = Observer . configure do |o |
234
+ o . on_next do |inner_source |
235
+ gate . synchronize do
236
+ if active < max_concurrent
237
+ active += 1
238
+ subscriber . call inner_source
239
+ else
240
+ q >> inner_source
241
+ end
242
+ end
243
+ end
244
+
245
+ o . on_error { |err | gate . synchronize { observer . on_error err } }
246
+
247
+ o . on_completed do
248
+ stopped = true
249
+ observer . on_completed if active == 0
250
+ end
251
+ end
252
+
253
+ group >> subscribe ( inner_obs )
254
+ end
255
+ end
256
+
257
+ # Concatenates all inner observable sequences, as long as the previous observable sequence terminated successfully.
258
+ def merge_all
259
+ AnonymousObservable . new do |observer |
260
+ gate = Mutex . new
261
+ stopped = false
262
+ m = SingleAssignmentSubscription . new
263
+ group = CompositeDisposable . new [ m ]
264
+
265
+ new_obs = Observer . configure do |o |
266
+ o . on_next do |inner_source |
267
+ inner_subscription = SingleAssignmentSubscription . new
268
+ group >> inner_subscription
269
+
270
+ inner_obs = Observer . configure do |io |
271
+ io . on_next { |x | gate . synchronize { observer . on_next x } }
272
+
273
+ io . on_error { |err | gate . synchronize { observer . on_error x } }
274
+
275
+ io . on_completed do
276
+ group . delete inner_subscription
277
+ gate . synchronize { observer . on_completed } if stopped && group . length == 1
278
+ end
279
+ end
280
+
281
+ inner_subscription . subscription = inner_source . subscribe inner_obs
282
+ end
283
+
284
+ o . on_error { |err | gate . synchronize { observer . on_error err } }
285
+
286
+ o . on_completed do
287
+ stopped = true
288
+ gate . synchronize { observer . on_completed } if group . length == 1
289
+ end
290
+ end
291
+ end
292
+ end
293
+
193
294
class << self
194
295
195
296
# Propagates the observable sequence that reacts first.
@@ -210,18 +311,26 @@ def rescue_error(*args)
210
311
gate . wait do
211
312
current = nil
212
313
has_next = false
314
+ err = nil
213
315
214
316
if !disposed
215
317
begin
216
318
current = e . next
217
319
has_next = true
218
320
rescue StopIteration => se
219
321
322
+ rescue => e
323
+ err = e
220
324
end
221
325
else
222
326
return
223
327
end
224
328
329
+ if err
330
+ observer . on_error err
331
+ return
332
+ end
333
+
225
334
unless has_next
226
335
if last_error
227
336
observer . on_error last_error
@@ -274,12 +383,104 @@ def combine_latest(*args, &result_selector)
274
383
end
275
384
276
385
observer . on_next ( res )
277
- #TODO FInish
386
+ elsif enumerable_select_with_index ( is_done ) { |x , j | j != i } . all?
387
+ observer . on_completed
388
+ return
278
389
end
390
+ end
279
391
392
+ done = lambda do |i |
393
+ is_done [ i ] = true
394
+ observer . on_completed if is_done . all?
280
395
end
396
+
397
+ gate = Mutex . new
398
+ subscriptions = Array . new ( n ) do |i |
399
+ sas = SingleAssignmentSubscription . new
400
+
401
+ sas_obs = Observer . configure do |o |
402
+ o . on_next do |x |
403
+ values [ i ] = x
404
+ next_item . call i
405
+ end
406
+
407
+ o . on_error &observer . method ( :on_error )
408
+
409
+ o . on_completed { done . call i }
410
+ end
411
+
412
+ sas . subscription = args [ i ] . synchronize ( gate ) . subscribe ( sas_obs )
413
+
414
+ subscriptions [ i ] = sas
415
+ end
416
+
417
+ CompositeSubscription . new subscriptions
281
418
end
282
419
end
283
420
end
421
+
422
+ # Concatenates all of the specified observable sequences, as long as the previous observable sequence terminated successfully.
423
+ def concat ( *args )
424
+ AnonymousObservable . new do |observer |
425
+ disposed = false
426
+ e = args . length == 1 && args [ 0 ] . is_a? ( Enumerator ) ? args [ 0 ] : args . to_enum
427
+ subscription = SerialSubscription . new
428
+ gate = AsyncLock . new
429
+
430
+ cancelable = CurrentThreadScheduler . instance . schedule_recursive do |this |
431
+ gate . wait do
432
+ current = nil
433
+ has_next = false
434
+ err = nil
435
+
436
+ if !disposed
437
+ begin
438
+ current = e . next
439
+ has_next = true
440
+ rescue StopIteration => se
441
+
442
+ rescue => e
443
+ err = e
444
+ end
445
+ else
446
+ return
447
+ end
448
+
449
+ if err
450
+ observer . on_error err
451
+ return
452
+ end
453
+
454
+ unless has_next
455
+ observer . on_completed
456
+ return
457
+ end
458
+
459
+ d = SingleAssignmentSubscription . new
460
+ subscription . subscription = d
461
+
462
+ new_obs = Observer . configure do |o |
463
+ o . on_next &observer . method ( :on_next )
464
+ o . on_error &observer . method ( :on_error )
465
+ o . on_completed { this . call }
466
+ end
467
+
468
+ current . subscribe new_obs
469
+ end
470
+ end
471
+
472
+ CompositeSubscription . new [ subscription , cancelable , Subscription . create { gate . wait { disposed = true } } ]
473
+ end
474
+ end
475
+
476
+ private
477
+
478
+ def enumerable_select_with_index ( arr , &block )
479
+ [ ] . tap do |new_arr |
480
+ arr . each_with_index do |item , index |
481
+ new_arr . push item if block . call item , index
482
+ end
483
+ end
484
+ end
284
485
end
285
486
end
0 commit comments