rx_ruby 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitattributes +22 -0
- data/.gitignore +173 -0
- data/.travis.yml +10 -0
- data/Gemfile +4 -0
- data/Rakefile +11 -0
- data/examples/aggregate.rb +39 -0
- data/examples/amb.rb +25 -0
- data/examples/ambproto.rb +24 -0
- data/examples/and.rb +26 -0
- data/examples/as_observable.rb +25 -0
- data/examples/average.rb +43 -0
- data/examples/buffer_with_count.rb +44 -0
- data/examples/buffer_with_time.rb +51 -0
- data/examples/case.rb +29 -0
- data/examples/catch.rb +20 -0
- data/examples/catchproto.rb +39 -0
- data/examples/combine_latest.rb +35 -0
- data/examples/combine_latestproto.rb +33 -0
- data/examples/concat.rb +22 -0
- data/examples/concat_all.rb +27 -0
- data/examples/concat_map.rb +61 -0
- data/examples/concat_map_observer.rb +29 -0
- data/examples/concatproto.rb +25 -0
- data/examples/connect.rb +41 -0
- data/examples/contains.rb +37 -0
- data/examples/count.rb +36 -0
- data/examples/create.rb +55 -0
- data/examples/debounce.rb +35 -0
- data/examples/default_if_empty.rb +35 -0
- data/examples/defer.rb +20 -0
- data/examples/delay.rb +49 -0
- data/examples/delay_with_selector.rb +63 -0
- data/examples/dematerialize.rb +22 -0
- data/examples/disposable.rb +12 -0
- data/examples/distinct.rb +43 -0
- data/examples/distinct_until_changed.rb +43 -0
- data/examples/do.rb +59 -0
- data/examples/empty.rb +16 -0
- data/examples/for.rb +26 -0
- data/examples/fork_join.rb +23 -0
- data/examples/from.rb +106 -0
- data/examples/from_array.rb +21 -0
- data/examples/from_callback.rb +21 -0
- data/examples/generate.rb +24 -0
- data/examples/group_join.rb +39 -0
- data/examples/if.rb +46 -0
- data/examples/intervals.rb +26 -0
- data/examples/merge.rb +36 -0
- data/examples/merge_all.rb +27 -0
- data/examples/multicast.rb +32 -0
- data/examples/never.rb +15 -0
- data/examples/of.rb +19 -0
- data/examples/on_error_resume_next.rb +21 -0
- data/examples/pairs.rb +26 -0
- data/examples/publish.rb +79 -0
- data/examples/range.rb +19 -0
- data/examples/reduce.rb +18 -0
- data/examples/repeat.rb +19 -0
- data/examples/return.rb +17 -0
- data/examples/scan.rb +41 -0
- data/examples/start.rb +29 -0
- data/examples/throw.rb +17 -0
- data/examples/time_intervals.rb +28 -0
- data/examples/timer.rb +26 -0
- data/examples/timestamp.rb +28 -0
- data/examples/to_a.rb +23 -0
- data/examples/to_async.rb +26 -0
- data/examples/using.rb +52 -0
- data/examples/when.rb +26 -0
- data/examples/while.rb +25 -0
- data/examples/window_with_time.rb +78 -0
- data/examples/zip.rb +27 -0
- data/examples/zip_array.rb +25 -0
- data/lib/core_ext/enumerable.rb +22 -0
- data/lib/rx_ruby.rb +27 -0
- data/lib/rx_ruby/concurrency/async_lock.rb +57 -0
- data/lib/rx_ruby/concurrency/current_thread_scheduler.rb +75 -0
- data/lib/rx_ruby/concurrency/default_scheduler.rb +51 -0
- data/lib/rx_ruby/concurrency/historical_scheduler.rb +16 -0
- data/lib/rx_ruby/concurrency/immediate_scheduler.rb +68 -0
- data/lib/rx_ruby/concurrency/local_scheduler.rb +39 -0
- data/lib/rx_ruby/concurrency/periodic_scheduler.rb +74 -0
- data/lib/rx_ruby/concurrency/scheduled_item.rb +42 -0
- data/lib/rx_ruby/concurrency/scheduler.rb +150 -0
- data/lib/rx_ruby/concurrency/virtual_time_scheduler.rb +170 -0
- data/lib/rx_ruby/core/async_lock_observer.rb +46 -0
- data/lib/rx_ruby/core/auto_detach_observer.rb +59 -0
- data/lib/rx_ruby/core/checked_observer.rb +66 -0
- data/lib/rx_ruby/core/notification.rb +161 -0
- data/lib/rx_ruby/core/observable.rb +104 -0
- data/lib/rx_ruby/core/observe_on_observer.rb +50 -0
- data/lib/rx_ruby/core/observer.rb +119 -0
- data/lib/rx_ruby/core/scheduled_observer.rb +83 -0
- data/lib/rx_ruby/core/synchronized_observer.rb +47 -0
- data/lib/rx_ruby/core/time_interval.rb +17 -0
- data/lib/rx_ruby/internal/priority_queue.rb +122 -0
- data/lib/rx_ruby/internal/util.rb +9 -0
- data/lib/rx_ruby/joins/active_plan.rb +45 -0
- data/lib/rx_ruby/joins/join_observer.rb +51 -0
- data/lib/rx_ruby/joins/pattern.rb +14 -0
- data/lib/rx_ruby/joins/plan.rb +44 -0
- data/lib/rx_ruby/linq/connectable_observable.rb +34 -0
- data/lib/rx_ruby/linq/observable/_observable_timer_date_and_period.rb +22 -0
- data/lib/rx_ruby/linq/observable/_observable_timer_time_span.rb +14 -0
- data/lib/rx_ruby/linq/observable/_observable_timer_time_span_and_period.rb +20 -0
- data/lib/rx_ruby/linq/observable/aggregate.rb +7 -0
- data/lib/rx_ruby/linq/observable/and.rb +7 -0
- data/lib/rx_ruby/linq/observable/case.rb +15 -0
- data/lib/rx_ruby/linq/observable/concat_all.rb +7 -0
- data/lib/rx_ruby/linq/observable/concat_map.rb +35 -0
- data/lib/rx_ruby/linq/observable/concat_map_observer.rb +43 -0
- data/lib/rx_ruby/linq/observable/contains.rb +28 -0
- data/lib/rx_ruby/linq/observable/debounce.rb +41 -0
- data/lib/rx_ruby/linq/observable/delay.rb +81 -0
- data/lib/rx_ruby/linq/observable/delay_with_selector.rb +64 -0
- data/lib/rx_ruby/linq/observable/do.rb +42 -0
- data/lib/rx_ruby/linq/observable/for.rb +13 -0
- data/lib/rx_ruby/linq/observable/fork_join.rb +55 -0
- data/lib/rx_ruby/linq/observable/from.rb +34 -0
- data/lib/rx_ruby/linq/observable/group_join.rb +108 -0
- data/lib/rx_ruby/linq/observable/if.rb +17 -0
- data/lib/rx_ruby/linq/observable/interval.rb +5 -0
- data/lib/rx_ruby/linq/observable/multicast.rb +14 -0
- data/lib/rx_ruby/linq/observable/of.rb +11 -0
- data/lib/rx_ruby/linq/observable/pairs.rb +7 -0
- data/lib/rx_ruby/linq/observable/pluck.rb +7 -0
- data/lib/rx_ruby/linq/observable/publish.rb +11 -0
- data/lib/rx_ruby/linq/observable/start.rb +7 -0
- data/lib/rx_ruby/linq/observable/time_interval.rb +15 -0
- data/lib/rx_ruby/linq/observable/timer.rb +26 -0
- data/lib/rx_ruby/linq/observable/timestamp.rb +9 -0
- data/lib/rx_ruby/linq/observable/to_async.rb +40 -0
- data/lib/rx_ruby/linq/observable/when.rb +36 -0
- data/lib/rx_ruby/linq/observable/while.rb +41 -0
- data/lib/rx_ruby/operators/aggregates.rb +611 -0
- data/lib/rx_ruby/operators/creation.rb +220 -0
- data/lib/rx_ruby/operators/multiple.rb +735 -0
- data/lib/rx_ruby/operators/single.rb +399 -0
- data/lib/rx_ruby/operators/standard_query_operators.rb +279 -0
- data/lib/rx_ruby/operators/synchronization.rb +47 -0
- data/lib/rx_ruby/operators/time.rb +120 -0
- data/lib/rx_ruby/subjects/async_subject.rb +161 -0
- data/lib/rx_ruby/subjects/behavior_subject.rb +149 -0
- data/lib/rx_ruby/subjects/replay_subject.rb +39 -0
- data/lib/rx_ruby/subjects/subject.rb +131 -0
- data/lib/rx_ruby/subjects/subject_extensions.rb +45 -0
- data/lib/rx_ruby/subscriptions/composite_subscription.rb +91 -0
- data/lib/rx_ruby/subscriptions/ref_count_subscription.rb +88 -0
- data/lib/rx_ruby/subscriptions/scheduled_subscription.rb +32 -0
- data/lib/rx_ruby/subscriptions/serial_subscription.rb +60 -0
- data/lib/rx_ruby/subscriptions/single_assignment_subscription.rb +64 -0
- data/lib/rx_ruby/subscriptions/subscription.rb +56 -0
- data/lib/rx_ruby/testing/cold_observable.rb +45 -0
- data/lib/rx_ruby/testing/hot_observable.rb +47 -0
- data/lib/rx_ruby/testing/mock_observer.rb +33 -0
- data/lib/rx_ruby/testing/reactive_test.rb +94 -0
- data/lib/rx_ruby/testing/recorded.rb +17 -0
- data/lib/rx_ruby/testing/test_scheduler.rb +96 -0
- data/lib/rx_ruby/testing/test_subscription.rb +22 -0
- data/lib/rx_ruby/version.rb +3 -0
- data/license.txt +13 -0
- data/readme.md +152 -0
- data/rx_ruby.gemspec +22 -0
- data/test/rx_ruby/concurrency/helpers/historical_virtual_scheduler_helper.rb +135 -0
- data/test/rx_ruby/concurrency/helpers/immediate_local_scheduler_helper.rb +51 -0
- data/test/rx_ruby/concurrency/test_async_lock.rb +56 -0
- data/test/rx_ruby/concurrency/test_current_thread_scheduler.rb +44 -0
- data/test/rx_ruby/concurrency/test_default_scheduler.rb +44 -0
- data/test/rx_ruby/concurrency/test_historical_scheduler.rb +18 -0
- data/test/rx_ruby/concurrency/test_immediate_scheduler.rb +53 -0
- data/test/rx_ruby/concurrency/test_local_scheduler.rb +12 -0
- data/test/rx_ruby/concurrency/test_periodic_scheduler.rb +53 -0
- data/test/rx_ruby/concurrency/test_scheduled_item.rb +50 -0
- data/test/rx_ruby/concurrency/test_scheduler.rb +128 -0
- data/test/rx_ruby/concurrency/test_virtual_time_scheduler.rb +14 -0
- data/test/rx_ruby/core/test_notification.rb +129 -0
- data/test/rx_ruby/core/test_observable_creation.rb +483 -0
- data/test/rx_ruby/core/test_observer.rb +634 -0
- data/test/rx_ruby/internal/test_priority_queue.rb +71 -0
- data/test/rx_ruby/subscriptions/test_composite_subscription.rb +116 -0
- data/test/rx_ruby/subscriptions/test_serial_subscription.rb +62 -0
- data/test/rx_ruby/subscriptions/test_singleassignment_subscription.rb +61 -0
- data/test/rx_ruby/subscriptions/test_subscription.rb +27 -0
- data/test/test_helper.rb +11 -0
- metadata +291 -0
@@ -0,0 +1,399 @@
|
|
1
|
+
# Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
|
2
|
+
|
3
|
+
require 'rx_ruby/subscriptions/subscription'
|
4
|
+
require 'rx_ruby/subscriptions/composite_subscription'
|
5
|
+
require 'rx_ruby/subscriptions/ref_count_subscription'
|
6
|
+
require 'rx_ruby/subscriptions/single_assignment_subscription'
|
7
|
+
require 'rx_ruby/core/observer'
|
8
|
+
require 'rx_ruby/core/observable'
|
9
|
+
require 'rx_ruby/operators/creation'
|
10
|
+
|
11
|
+
module RxRuby
|
12
|
+
|
13
|
+
module Observable
|
14
|
+
|
15
|
+
# Hides the identity of an observable sequence.
|
16
|
+
def as_observable
|
17
|
+
AnonymousObservable.new {|observer| subscribe(observer) }
|
18
|
+
end
|
19
|
+
|
20
|
+
# Projects each element of an observable sequence into zero or more buffers which are produced based on element count information.
|
21
|
+
def buffer_with_count(count, skip = count)
|
22
|
+
raise ArgumentError.new 'Count must be greater than zero' if count <= 0
|
23
|
+
raise ArgumentError.new 'Skip must be greater than zero' if skip <= 0
|
24
|
+
window_with_count(count, skip).flat_map(&:to_a).find_all {|x| x.length > 0 }
|
25
|
+
end
|
26
|
+
|
27
|
+
# Dematerializes the explicit notification values of an observable sequence as implicit notifications.
|
28
|
+
def dematerialize
|
29
|
+
AnonymousObservable.new do |observer|
|
30
|
+
|
31
|
+
new_obs = RxRuby::Observer.configure do |o|
|
32
|
+
o.on_next {|x| x.accept observer }
|
33
|
+
o.on_error(&observer.method(:on_error))
|
34
|
+
o.on_completed(&observer.method(:on_completed))
|
35
|
+
end
|
36
|
+
|
37
|
+
subscribe new_obs
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
# Returns an observable sequence that contains only distinct contiguous elements according to the optional key_selector.
|
42
|
+
def distinct_until_changed(&key_selector)
|
43
|
+
key_selector ||= lambda {|x| x}
|
44
|
+
AnonymousObservable.new do |observer|
|
45
|
+
current_key = nil
|
46
|
+
has_current = nil
|
47
|
+
|
48
|
+
new_obs = RxRuby::Observer.configure do |o|
|
49
|
+
o.on_next do |value|
|
50
|
+
key = nil
|
51
|
+
begin
|
52
|
+
key = key_selector.call value
|
53
|
+
rescue => err
|
54
|
+
observer.on_error err
|
55
|
+
next
|
56
|
+
end
|
57
|
+
|
58
|
+
if !current_key || key != current_key
|
59
|
+
has_current = true
|
60
|
+
current_key = key
|
61
|
+
observer.on_next value
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
o.on_error(&observer.method(:on_error))
|
66
|
+
o.on_completed(&observer.method(:on_completed))
|
67
|
+
end
|
68
|
+
|
69
|
+
subscribe new_obs
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
# Invokes the observer's methods for each message in the source sequence.
|
74
|
+
# This method can be used for debugging, logging, etc. of query behavior by intercepting the message stream to run arbitrary actions for messages on the pipeline.
|
75
|
+
def tap(observer)
|
76
|
+
raise ArgumentError.new 'Observer cannot be nil' unless observer
|
77
|
+
AnonymousObservable.new do |obs|
|
78
|
+
new_obs = RxRuby::Observer.configure do |o|
|
79
|
+
|
80
|
+
o.on_next do |value|
|
81
|
+
begin
|
82
|
+
observer.on_next value
|
83
|
+
rescue => err
|
84
|
+
obs.on_error err
|
85
|
+
end
|
86
|
+
|
87
|
+
obs.on_next value
|
88
|
+
end
|
89
|
+
|
90
|
+
o.on_error do |err|
|
91
|
+
begin
|
92
|
+
observer.on_error err
|
93
|
+
rescue => e
|
94
|
+
obs.on_error e
|
95
|
+
end
|
96
|
+
|
97
|
+
obs.on_error err
|
98
|
+
end
|
99
|
+
|
100
|
+
o.on_completed do
|
101
|
+
begin
|
102
|
+
observer.on_completed
|
103
|
+
rescue => err
|
104
|
+
obs.on_error err
|
105
|
+
end
|
106
|
+
|
107
|
+
obs.on_completed
|
108
|
+
end
|
109
|
+
|
110
|
+
end
|
111
|
+
|
112
|
+
subscribe new_obs
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
# Invokes a specified action after the source observable sequence terminates gracefully or exceptionally.
|
117
|
+
def ensures
|
118
|
+
AnonymousObservable.new do |observer|
|
119
|
+
subscription = subscribe observer
|
120
|
+
Subscription.create do
|
121
|
+
begin
|
122
|
+
subscription.unsubscribe
|
123
|
+
ensure
|
124
|
+
yield
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
# Ignores all elements in an observable sequence leaving only the termination messages.
|
131
|
+
def ignore_elements
|
132
|
+
AnonymousObservable.new do |observer|
|
133
|
+
new_obs = RxRuby::Observer.configure do |o|
|
134
|
+
o.on_next {|_| }
|
135
|
+
o.on_error(&observer.method(:on_error))
|
136
|
+
o.on_completed(&observer.method(:on_completed))
|
137
|
+
end
|
138
|
+
|
139
|
+
subscribe new_obs
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
# Materializes the implicit notifications of an observable sequence as explicit notification values.
|
144
|
+
def materialize
|
145
|
+
AnonymousObservable.new do |observer|
|
146
|
+
new_obs = RxRuby::Observer.configure do |o|
|
147
|
+
|
148
|
+
o.on_next {|x| observer.on_next(Notification.create_on_next x) }
|
149
|
+
|
150
|
+
o.on_error do |err|
|
151
|
+
observer.on_next(Notification.create_on_next err)
|
152
|
+
observer.on_completed
|
153
|
+
end
|
154
|
+
|
155
|
+
o.on_completed do
|
156
|
+
observer.on_next(Notification.create_on_completed)
|
157
|
+
observer.on_completed
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
subscribe new_obs
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
# Repeats the observable sequence indefinitely.
|
166
|
+
def repeat_infinitely
|
167
|
+
Observable.concat(enumerator_repeat_infinitely(self))
|
168
|
+
end
|
169
|
+
|
170
|
+
# Repeats the observable sequence a specified number of times.
|
171
|
+
def repeat(repeat_count)
|
172
|
+
Observable.concat(enumerator_repeat_times(repeat_count, self))
|
173
|
+
end
|
174
|
+
|
175
|
+
# Repeats the source observable sequence until it successfully terminates.
|
176
|
+
def retry_infinitely
|
177
|
+
Observable.rescue_error(enumerator_repeat_infinitely(self))
|
178
|
+
end
|
179
|
+
|
180
|
+
# Repeats the source observable sequence the specified number of times or until it successfully terminates.
|
181
|
+
def retry(retry_count)
|
182
|
+
Observable.rescue_error(enumerator_repeat_times(retry_count, self))
|
183
|
+
end
|
184
|
+
|
185
|
+
# Applies an accumulator function over an observable sequence and returns each intermediate result.
|
186
|
+
# The optional seed value is used as the initial accumulator value.
|
187
|
+
# For aggregation behavior with no intermediate results, see Observable.reduce.
|
188
|
+
def scan(*args, &block)
|
189
|
+
has_seed = false
|
190
|
+
seed = nil
|
191
|
+
action = nil
|
192
|
+
|
193
|
+
# Argument parsing to support:
|
194
|
+
# 1. (seed, Symbol)
|
195
|
+
# 2. (seed, &block)
|
196
|
+
# 3. (Symbol)
|
197
|
+
# 4. (&block)
|
198
|
+
if args.length == 2 && args[1].is_a?(Symbol)
|
199
|
+
seed = args[0]
|
200
|
+
action = args[1].to_proc
|
201
|
+
has_seed = true
|
202
|
+
elsif args.length == 1 && block_given?
|
203
|
+
seed = args[0]
|
204
|
+
has_seed = true
|
205
|
+
action = block
|
206
|
+
elsif args.length == 1 && args[0].is_a?(Symbol)
|
207
|
+
action = args[0].to_proc
|
208
|
+
elsif args.length == 0 && block_given?
|
209
|
+
action = block
|
210
|
+
else
|
211
|
+
raise ArgumentError.new 'Invalid arguments'
|
212
|
+
end
|
213
|
+
|
214
|
+
AnonymousObservable.new do |observer|
|
215
|
+
|
216
|
+
has_accumulation = false
|
217
|
+
accumulation = nil
|
218
|
+
has_value = false
|
219
|
+
|
220
|
+
new_obs = Observer.configure do |o|
|
221
|
+
o.on_next do |x|
|
222
|
+
begin
|
223
|
+
has_value = true unless has_value
|
224
|
+
|
225
|
+
if has_accumulation
|
226
|
+
accumulation = action.call(accumulation, x)
|
227
|
+
else
|
228
|
+
accumulation = has_seed ? action.call(seed, x) : x
|
229
|
+
has_accumulation = true
|
230
|
+
end
|
231
|
+
rescue => err
|
232
|
+
observer.on_error err
|
233
|
+
return
|
234
|
+
end
|
235
|
+
|
236
|
+
observer.on_next accumulation
|
237
|
+
end
|
238
|
+
|
239
|
+
o.on_error(&observer.method(:on_error))
|
240
|
+
|
241
|
+
o.on_completed do
|
242
|
+
observer.on_next seed if !has_value && has_seed
|
243
|
+
observer.on_completed
|
244
|
+
end
|
245
|
+
end
|
246
|
+
|
247
|
+
subscribe new_obs
|
248
|
+
end
|
249
|
+
end
|
250
|
+
|
251
|
+
# Bypasses a specified number of elements at the end of an observable sequence.
|
252
|
+
# @param [Numeric] count The number of elements to bypass at the end of an observable sequence.
|
253
|
+
def skip_last(count)
|
254
|
+
raise ArgumentError.new 'Count cannot be less than zero' if count < 0
|
255
|
+
AnonymousObservable.new do |observer|
|
256
|
+
q = []
|
257
|
+
new_obs = Observer.configure do |o|
|
258
|
+
|
259
|
+
o.on_next do |x|
|
260
|
+
q.push x
|
261
|
+
observer.on_next(q.shift) if q.length > count
|
262
|
+
end
|
263
|
+
|
264
|
+
o.on_error(&observer.method(:on_error))
|
265
|
+
o.on_completed(&observer.method(:on_completed))
|
266
|
+
end
|
267
|
+
|
268
|
+
subscribe new_obs
|
269
|
+
end
|
270
|
+
end
|
271
|
+
|
272
|
+
# Prepends a sequence of values to an observable sequence.
|
273
|
+
def start_with(*args)
|
274
|
+
scheduler = CurrentThreadScheduler.instance
|
275
|
+
if args.size > 0 && Scheduler === args[0]
|
276
|
+
scheduler = args.shift
|
277
|
+
end
|
278
|
+
Observable.from_array(args, scheduler).concat(self)
|
279
|
+
end
|
280
|
+
|
281
|
+
# Returns a specified number of contiguous elements from the end of an observable sequence.
|
282
|
+
def take_last(count, scheduler = CurrentThreadScheduler.instance)
|
283
|
+
raise ArgumentError.new 'Count cannot be less than zero' if count < 0
|
284
|
+
AnonymousObservable.new do |observer|
|
285
|
+
q = []
|
286
|
+
g = CompositeSubscription.new
|
287
|
+
|
288
|
+
new_obs = Observer.configure do |o|
|
289
|
+
o.on_next do |x|
|
290
|
+
q.push x
|
291
|
+
q.shift if q.length > 0
|
292
|
+
end
|
293
|
+
|
294
|
+
o.on_error(&observer.method(:on_error))
|
295
|
+
|
296
|
+
o.on_completed do
|
297
|
+
g.push(scheduler.schedule_recursive lambda {|this|
|
298
|
+
if q.length > 0
|
299
|
+
observer.on_next(q.shift)
|
300
|
+
this.call
|
301
|
+
else
|
302
|
+
observer.on_completed
|
303
|
+
end
|
304
|
+
})
|
305
|
+
end
|
306
|
+
|
307
|
+
g.add(subscribe new_obs)
|
308
|
+
g
|
309
|
+
end
|
310
|
+
end
|
311
|
+
end
|
312
|
+
|
313
|
+
# Returns a list with the specified number of contiguous elements from the end of an observable sequence.
|
314
|
+
def take_last_buffer(count)
|
315
|
+
AnonymousObservable.new do |observer|
|
316
|
+
q = []
|
317
|
+
new_obs = Observer.configure do |o|
|
318
|
+
o.on_next do |x|
|
319
|
+
q.push x
|
320
|
+
q.shift if q.length > count
|
321
|
+
end
|
322
|
+
|
323
|
+
o.on_error(&observer.method(:on_error))
|
324
|
+
|
325
|
+
o.on_completed do
|
326
|
+
observer.on_next q
|
327
|
+
observer.on_completed
|
328
|
+
end
|
329
|
+
end
|
330
|
+
|
331
|
+
susbcribe new_obs
|
332
|
+
end
|
333
|
+
end
|
334
|
+
|
335
|
+
# Projects each element of an observable sequence into zero or more windows which are produced based on element count information.
|
336
|
+
def window_with_count(count, skip)
|
337
|
+
raise ArgumentError.new 'Count must be greater than zero' if count <= 0
|
338
|
+
raise ArgumentError.new 'Skip must be greater than zero' if skip <= 0
|
339
|
+
|
340
|
+
AnonymousObservable.new do |observer|
|
341
|
+
q = []
|
342
|
+
n = 0
|
343
|
+
|
344
|
+
m = SingleAssignmentSubscription.new
|
345
|
+
ref_count_disposable = RefCountSubscription.new m
|
346
|
+
|
347
|
+
create_window = lambda {
|
348
|
+
s = Subject.new
|
349
|
+
q.push s
|
350
|
+
observer.on_next(s.add_ref(ref_count_disposable))
|
351
|
+
}
|
352
|
+
|
353
|
+
create_window.call
|
354
|
+
|
355
|
+
new_obs = Observer.configure do |o|
|
356
|
+
o.on_next do |x|
|
357
|
+
q.each {|s| s.on_next x}
|
358
|
+
|
359
|
+
c = n - count + 1
|
360
|
+
q.shift.on_completed if c >=0 && c % skip == 0
|
361
|
+
|
362
|
+
n += 1
|
363
|
+
create_window.call if n % skip == 0
|
364
|
+
end
|
365
|
+
|
366
|
+
o.on_error do |err|
|
367
|
+
q.shift.on_error err while q.length > 0
|
368
|
+
observer.on_error err
|
369
|
+
end
|
370
|
+
|
371
|
+
o.on_completed do
|
372
|
+
q.shift.on_completed while q.length > 0
|
373
|
+
observer.on_completed
|
374
|
+
end
|
375
|
+
end
|
376
|
+
|
377
|
+
m.subscription = subscribe new_obs
|
378
|
+
ref_count_disposable
|
379
|
+
end
|
380
|
+
end
|
381
|
+
|
382
|
+
def enumerator_repeat_times(num, value)
|
383
|
+
Enumerator.new do |y|
|
384
|
+
num.times do |i|
|
385
|
+
y << value
|
386
|
+
end
|
387
|
+
end
|
388
|
+
end
|
389
|
+
|
390
|
+
def enumerator_repeat_infinitely(value)
|
391
|
+
Enumerator.new do |y|
|
392
|
+
while true
|
393
|
+
y << value
|
394
|
+
end
|
395
|
+
end
|
396
|
+
end
|
397
|
+
|
398
|
+
end
|
399
|
+
end
|
@@ -0,0 +1,279 @@
|
|
1
|
+
# Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
|
2
|
+
|
3
|
+
require 'rx_ruby/concurrency/current_thread_scheduler'
|
4
|
+
require 'rx_ruby/concurrency/immediate_scheduler'
|
5
|
+
require 'rx_ruby/core/observer'
|
6
|
+
require 'rx_ruby/subscriptions/composite_subscription'
|
7
|
+
require 'rx_ruby/subscriptions/subscription'
|
8
|
+
|
9
|
+
module RxRuby
|
10
|
+
|
11
|
+
module Observable
|
12
|
+
|
13
|
+
# Standard Query Operators
|
14
|
+
|
15
|
+
# Returns the elements of the specified sequence or the type parameter's default value in a singleton sequence if the sequence is empty.
|
16
|
+
def default_if_empty(default_value = nil)
|
17
|
+
AnonymousObservable.new do |observer|
|
18
|
+
found = false
|
19
|
+
new_observer = Observer.configure do |o|
|
20
|
+
|
21
|
+
o.on_next do |x|
|
22
|
+
found = true
|
23
|
+
observer.on_next x
|
24
|
+
end
|
25
|
+
|
26
|
+
o.on_error(&observer.method(:on_error))
|
27
|
+
|
28
|
+
o.on_completed do
|
29
|
+
observer.on_next(default_value) unless found
|
30
|
+
observer.on_completed
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
subscribe(new_observer)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
# Returns an observable sequence that contains only distinct elements according to the optional key_selector.
|
39
|
+
def distinct(&key_selector)
|
40
|
+
key_selector ||= lambda {|x| x}
|
41
|
+
|
42
|
+
AnonymousObservable.new do |observer|
|
43
|
+
|
44
|
+
h = Hash.new
|
45
|
+
|
46
|
+
new_observer = Observer.configure do |o|
|
47
|
+
|
48
|
+
o.on_next do |x|
|
49
|
+
key = nil
|
50
|
+
has_added = false
|
51
|
+
|
52
|
+
begin
|
53
|
+
key = key_selector.call x
|
54
|
+
key_s = key.to_s
|
55
|
+
unless h.key? key_s
|
56
|
+
has_added = true
|
57
|
+
h[key_s] = true
|
58
|
+
end
|
59
|
+
rescue => e
|
60
|
+
observer.on_error e
|
61
|
+
next
|
62
|
+
end
|
63
|
+
|
64
|
+
observer.on_next x if has_added
|
65
|
+
end
|
66
|
+
|
67
|
+
o.on_error(&observer.method(:on_error))
|
68
|
+
o.on_completed(&observer.method(:on_completed))
|
69
|
+
end
|
70
|
+
|
71
|
+
subscribe(new_observer)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
# Projects each element of an observable sequence into a new form by incorporating the element's index.
|
76
|
+
def map_with_index(&block)
|
77
|
+
AnonymousObservable.new do |observer|
|
78
|
+
new_observer = Observer.configure do |o|
|
79
|
+
i = 0
|
80
|
+
|
81
|
+
o.on_next do |x|
|
82
|
+
result = nil
|
83
|
+
begin
|
84
|
+
result = block.call(x, i)
|
85
|
+
i += 1
|
86
|
+
rescue => e
|
87
|
+
observer.on_error e
|
88
|
+
next
|
89
|
+
end
|
90
|
+
|
91
|
+
observer.on_next result
|
92
|
+
end
|
93
|
+
|
94
|
+
o.on_error(&observer.method(:on_error))
|
95
|
+
o.on_completed(&observer.method(:on_completed))
|
96
|
+
end
|
97
|
+
|
98
|
+
subscribe(new_observer)
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
# Projects each element of an observable sequence into a new form.
|
103
|
+
def map(&block)
|
104
|
+
map_with_index {|x, _| block.call x }
|
105
|
+
end
|
106
|
+
|
107
|
+
# Projects each element of the source observable sequence to the other observable sequence and merges the resulting observable sequences into one observable sequence.
|
108
|
+
def flat_map(&block)
|
109
|
+
map(&block).merge_all
|
110
|
+
end
|
111
|
+
|
112
|
+
# Projects each element of an observable sequence to an observable sequence by incorporating the element's index and merges the resulting observable sequences into one observable sequence.
|
113
|
+
def flat_map_with_index(&block)
|
114
|
+
map_with_index(&block).merge_all
|
115
|
+
end
|
116
|
+
|
117
|
+
# Bypasses a specified number of elements in an observable sequence and then returns the remaining elements.
|
118
|
+
def skip(count)
|
119
|
+
AnonymousObservable.new do |observer|
|
120
|
+
remaining = count
|
121
|
+
|
122
|
+
new_observer = Observer.configure do |o|
|
123
|
+
|
124
|
+
o.on_next do |x|
|
125
|
+
if remaining <= 0
|
126
|
+
observer.on_next x
|
127
|
+
else
|
128
|
+
remaining -= 1
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
o.on_error(&observer.method(:on_error))
|
133
|
+
o.on_completed(&observer.method(:on_completed))
|
134
|
+
end
|
135
|
+
|
136
|
+
|
137
|
+
subscribe(new_observer)
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
# Bypasses elements in an observable sequence as long as a specified condition is true and then returns the remaining elements.
|
142
|
+
def skip_while(&block)
|
143
|
+
skip_while_with_index {|x, _| block.call x }
|
144
|
+
end
|
145
|
+
|
146
|
+
# Bypasses elements in an observable sequence as long as a specified condition is true and then returns the remaining elements.
|
147
|
+
# The element's index is used in the logic of the predicate function.
|
148
|
+
def skip_while_with_index(&block)
|
149
|
+
AnonymousObservable.new do |observer|
|
150
|
+
running = false
|
151
|
+
i = 0
|
152
|
+
|
153
|
+
new_observer = Observer.configure do |o|
|
154
|
+
|
155
|
+
o.on_next do |x|
|
156
|
+
unless running
|
157
|
+
begin
|
158
|
+
running = !block.call(x, i)
|
159
|
+
i += 1
|
160
|
+
rescue => e
|
161
|
+
observer.on_error e
|
162
|
+
next
|
163
|
+
end
|
164
|
+
|
165
|
+
observer.on_next x if running
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
o.on_error(&observer.method(:on_error))
|
170
|
+
o.on_completed(&observer.method(:on_completed))
|
171
|
+
end
|
172
|
+
|
173
|
+
subscribe(new_observer)
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
# Returns a specified number of contiguous elements from the start of an observable sequence.
|
178
|
+
def take(count, scheduler = ImmediateScheduler.instance)
|
179
|
+
return Observable.empty(scheduler) if count == 0
|
180
|
+
|
181
|
+
AnonymousObservable.new do |observer|
|
182
|
+
|
183
|
+
remaining = count
|
184
|
+
|
185
|
+
new_observer = Observer.configure do |o|
|
186
|
+
|
187
|
+
o.on_next do |x|
|
188
|
+
if remaining > 0
|
189
|
+
remaining -= 1
|
190
|
+
observer.on_next x
|
191
|
+
observer.on_completed if remaining == 0
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|
195
|
+
o.on_error(&observer.method(:on_error))
|
196
|
+
o.on_completed(&observer.method(:on_completed))
|
197
|
+
end
|
198
|
+
|
199
|
+
subscribe(new_observer)
|
200
|
+
end
|
201
|
+
end
|
202
|
+
|
203
|
+
# Returns elements from an observable sequence as long as a specified condition is true.
|
204
|
+
def take_while(&block)
|
205
|
+
take_while_with_index {|x, _| block.call x }
|
206
|
+
end
|
207
|
+
|
208
|
+
# Returns elements from an observable sequence as long as a specified condition is true.
|
209
|
+
# The element's index is used in the logic of the predicate function.
|
210
|
+
def take_while_with_index(&block)
|
211
|
+
AnonymousObservable.new do |observer|
|
212
|
+
running = true
|
213
|
+
i = 0
|
214
|
+
|
215
|
+
new_observer = Observer.configure do |o|
|
216
|
+
|
217
|
+
o.on_next do |x|
|
218
|
+
if running
|
219
|
+
begin
|
220
|
+
running = block.call(x, i)
|
221
|
+
i += 1
|
222
|
+
rescue => e
|
223
|
+
observer.on_error e
|
224
|
+
next
|
225
|
+
end
|
226
|
+
|
227
|
+
if running
|
228
|
+
observer.on_next x
|
229
|
+
else
|
230
|
+
observer.on_completed
|
231
|
+
end
|
232
|
+
end
|
233
|
+
end
|
234
|
+
|
235
|
+
o.on_error(&observer.method(:on_error))
|
236
|
+
o.on_completed(&observer.method(:on_completed))
|
237
|
+
end
|
238
|
+
|
239
|
+
subscribe(new_observer)
|
240
|
+
end
|
241
|
+
end
|
242
|
+
|
243
|
+
# Filters the elements of an observable sequence based on a predicate.
|
244
|
+
def select(&block)
|
245
|
+
select_with_index {|x, _| block.call x }
|
246
|
+
end
|
247
|
+
alias_method :find_all, :select
|
248
|
+
|
249
|
+
# Filters the elements of an observable sequence based on a predicate by incorporating the element's index.
|
250
|
+
def select_with_index(&block)
|
251
|
+
AnonymousObservable.new do |observer|
|
252
|
+
i = 0
|
253
|
+
|
254
|
+
new_observer = Observer.configure do |o|
|
255
|
+
|
256
|
+
o.on_next do |x|
|
257
|
+
should_run = false
|
258
|
+
begin
|
259
|
+
should_run = block.call(x, i)
|
260
|
+
i += 1
|
261
|
+
rescue => e
|
262
|
+
observer.on_error e
|
263
|
+
next
|
264
|
+
end
|
265
|
+
|
266
|
+
observer.on_next x if should_run
|
267
|
+
end
|
268
|
+
|
269
|
+
o.on_error(&observer.method(:on_error))
|
270
|
+
o.on_completed(&observer.method(:on_completed))
|
271
|
+
end
|
272
|
+
|
273
|
+
subscribe(new_observer)
|
274
|
+
end
|
275
|
+
end
|
276
|
+
|
277
|
+
alias_method :find_all_with_index, :select_with_index
|
278
|
+
end
|
279
|
+
end
|