Skip to content

Commit 25417a0

Browse files
Adding through merge
1 parent 0e9a845 commit 25417a0

File tree

5 files changed

+210
-6
lines changed

5 files changed

+210
-6
lines changed

lib/rx/operators/multiple.rb

+202-1
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,107 @@ def combineLatest(other, &result_selector)
190190
end
191191
end
192192

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+
193294
class << self
194295

195296
# Propagates the observable sequence that reacts first.
@@ -210,18 +311,26 @@ def rescue_error(*args)
210311
gate.wait do
211312
current = nil
212313
has_next = false
314+
err = nil
213315

214316
if !disposed
215317
begin
216318
current = e.next
217319
has_next = true
218320
rescue StopIteration => se
219321

322+
rescue => e
323+
err = e
220324
end
221325
else
222326
return
223327
end
224328

329+
if err
330+
observer.on_error err
331+
return
332+
end
333+
225334
unless has_next
226335
if last_error
227336
observer.on_error last_error
@@ -274,12 +383,104 @@ def combine_latest(*args, &result_selector)
274383
end
275384

276385
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
278389
end
390+
end
279391

392+
done = lambda do |i|
393+
is_done[i] = true
394+
observer.on_completed if is_done.all?
280395
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
281418
end
282419
end
283420
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
284485
end
285486
end

lib/rx/operators/single.rb

+2-2
Original file line numberDiff line numberDiff line change
@@ -163,12 +163,12 @@ def materialize
163163

164164
# Repeats the observable sequence indefinitely.
165165
def repeat_infinitely
166-
concat_enumerator(enumerator_repeat_infinitely(self))
166+
Observable.concat(enumerator_repeat_infinitely(self))
167167
end
168168

169169
# Repeats the observable sequence a specified number of times.
170170
def repeat(repeat_count)
171-
concat_enumerator(enumerator_repeat_times(repeat_count, self))
171+
Observable.concat(enumerator_repeat_times(repeat_count, self))
172172
end
173173

174174
# Repeats the source observable sequence until it successfully terminates.

lib/rx/operators/standard_query_operators.rb

+5-2
Original file line numberDiff line numberDiff line change
@@ -241,12 +241,13 @@ def take_while_with_index(&block)
241241
end
242242

243243
# Filters the elements of an observable sequence based on a predicate.
244-
def filter(&block)
244+
def select(&block)
245245
filter_with_index {|x, i| block.call x }
246246
end
247+
alias_method :find_all, :select
247248

248249
# Filters the elements of an observable sequence based on a predicate by incorporating the element's index.
249-
def filter_with_index(&block)
250+
def select_with_index(&block)
250251
AnonymousObservable.new do |observer|
251252
i = 0
252253

@@ -272,5 +273,7 @@ def filter_with_index(&block)
272273
subscribe(new_observer)
273274
end
274275
end
276+
277+
alias_method :find_all_with_index, :select_with_index
275278
end
276279
end

license.txt

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
Copyright (c) Microsoft Corporation. All rights reserved.
1+
Copyright (c) Microsoft Open Technologies. All rights reserved.
22

33
Licensed under the Apache License, Version 2.0 (the "License"); you
44
may not use this file except in compliance with the License. You may

output.txt

Whitespace-only changes.

0 commit comments

Comments
 (0)