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,15 @@
|
|
1
|
+
module RxRuby
|
2
|
+
module Observable
|
3
|
+
def time_interval(scheduler = DefaultScheduler.instance)
|
4
|
+
Observable.defer {
|
5
|
+
last = scheduler.now
|
6
|
+
self.map {|x|
|
7
|
+
now = scheduler.now
|
8
|
+
span = now - last
|
9
|
+
last = now
|
10
|
+
TimeInterval.new(span, x)
|
11
|
+
}
|
12
|
+
}
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module RxRuby
|
2
|
+
class << Observable
|
3
|
+
def timer(due_time, period_or_scheduler = DefaultScheduler.instance, scheduler = DefaultScheduler.instance)
|
4
|
+
case period_or_scheduler
|
5
|
+
when Numeric
|
6
|
+
period = period_or_scheduler
|
7
|
+
when Scheduler
|
8
|
+
scheduler = period_or_scheduler
|
9
|
+
end
|
10
|
+
|
11
|
+
if Time === due_time
|
12
|
+
if period.nil?
|
13
|
+
observable_timer_date(due_time, scheduler)
|
14
|
+
else
|
15
|
+
observable_timer_date_and_period(due_time, period, scheduler)
|
16
|
+
end
|
17
|
+
else
|
18
|
+
if period.nil?
|
19
|
+
observable_timer_time_span(due_time, scheduler)
|
20
|
+
else
|
21
|
+
observable_timer_time_span_and_period(due_time, period, scheduler)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module RxRuby
|
2
|
+
class << Observable
|
3
|
+
def to_async(func, context = nil, scheduler = DefaultScheduler.instance)
|
4
|
+
lambda() {|*args|
|
5
|
+
subject = AsyncSubject.new
|
6
|
+
|
7
|
+
scheduler.schedule lambda {
|
8
|
+
begin
|
9
|
+
if context
|
10
|
+
result = proc_bind(func, context).call(*args)
|
11
|
+
else
|
12
|
+
result = func.call(*args)
|
13
|
+
end
|
14
|
+
rescue => e
|
15
|
+
subject.on_error e
|
16
|
+
return
|
17
|
+
end
|
18
|
+
subject.on_next result
|
19
|
+
subject.on_completed
|
20
|
+
}
|
21
|
+
return subject.as_observable
|
22
|
+
}
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
# derived from Proc#to_method from Ruby Facets
|
28
|
+
# https://github.com/rubyworks/facets/blob/master/lib/core/facets/proc/to_method.rb
|
29
|
+
def proc_bind(block, object)
|
30
|
+
time = Time.now
|
31
|
+
method_name = "__bind_#{time.to_i}_#{time.usec}"
|
32
|
+
(class << object; self; end).class_eval do
|
33
|
+
define_method(method_name, &block)
|
34
|
+
method = instance_method(method_name)
|
35
|
+
remove_method(method_name)
|
36
|
+
method
|
37
|
+
end.bind(object)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module RxRuby
|
2
|
+
class << Observable
|
3
|
+
def when(*plans)
|
4
|
+
AnonymousObservable.new do |observer|
|
5
|
+
active_plans = []
|
6
|
+
external_subscriptions = {}
|
7
|
+
out_observer = Observer.configure {|o|
|
8
|
+
o.on_next(&observer.method(:on_next))
|
9
|
+
o.on_error {|err|
|
10
|
+
external_subscriptions.each {|_, v|
|
11
|
+
v.on_error err
|
12
|
+
}
|
13
|
+
}
|
14
|
+
o.on_completed(&observer.method(:on_completed))
|
15
|
+
}
|
16
|
+
begin
|
17
|
+
plans.each {|x|
|
18
|
+
active_plans.push x.activate(external_subscriptions, out_observer, lambda {|active_plan|
|
19
|
+
active_plans.delete(active_plan)
|
20
|
+
active_plans.length == 0 && observer.on_completed
|
21
|
+
})
|
22
|
+
}
|
23
|
+
rescue => e
|
24
|
+
Observable.raise_error(e).subscribe(observer)
|
25
|
+
end
|
26
|
+
group = CompositeSubscription.new
|
27
|
+
external_subscriptions.each {|_, join_observer|
|
28
|
+
join_observer.subscribe
|
29
|
+
group.push join_observer
|
30
|
+
}
|
31
|
+
|
32
|
+
group
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module RxRuby
|
2
|
+
class << Observable
|
3
|
+
def while(condition, source)
|
4
|
+
enum = Enumerator.new {|y|
|
5
|
+
while condition.call
|
6
|
+
y << source
|
7
|
+
end
|
8
|
+
}
|
9
|
+
scheduler = ImmediateScheduler.instance
|
10
|
+
|
11
|
+
is_disposed = false
|
12
|
+
subscription = SerialSubscription.new
|
13
|
+
|
14
|
+
AnonymousObservable.new do |observer|
|
15
|
+
cancelable = scheduler.schedule_recursive lambda {|this|
|
16
|
+
return if is_disposed
|
17
|
+
|
18
|
+
begin
|
19
|
+
current_value = enum.next
|
20
|
+
rescue StopIteration => e
|
21
|
+
observer.on_completed
|
22
|
+
return
|
23
|
+
rescue => e
|
24
|
+
observer.on_error e
|
25
|
+
return
|
26
|
+
end
|
27
|
+
|
28
|
+
d = SingleAssignmentSubscription.new
|
29
|
+
subscription.subscription = d
|
30
|
+
d.subscription = current_value.subscribe(
|
31
|
+
observer.method(:on_next),
|
32
|
+
observer.method(:on_error),
|
33
|
+
lambda { this.call }
|
34
|
+
)
|
35
|
+
}
|
36
|
+
|
37
|
+
CompositeSubscription.new [subscription, cancelable, Subscription.create { is_disposed = true }]
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,611 @@
|
|
1
|
+
# Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
|
2
|
+
|
3
|
+
require 'thread'
|
4
|
+
require 'rx_ruby/subscriptions/composite_subscription'
|
5
|
+
require 'rx_ruby/core/observer'
|
6
|
+
require 'rx_ruby/core/observable'
|
7
|
+
require 'rx_ruby/operators/single'
|
8
|
+
require 'rx_ruby/operators/standard_query_operators'
|
9
|
+
|
10
|
+
module RxRuby
|
11
|
+
|
12
|
+
module Observable
|
13
|
+
|
14
|
+
# Internal method to get the final value
|
15
|
+
# @return [RxRuby::Observable]
|
16
|
+
def final
|
17
|
+
AnonymousObservable.new do |observer|
|
18
|
+
value = nil
|
19
|
+
has_value = false
|
20
|
+
|
21
|
+
new_obs = Observer.configure do |o|
|
22
|
+
o.on_next do |x|
|
23
|
+
value = x
|
24
|
+
has_value = true
|
25
|
+
end
|
26
|
+
|
27
|
+
o.on_error(&observer.method(:on_error))
|
28
|
+
|
29
|
+
o.on_completed do
|
30
|
+
if has_value
|
31
|
+
observer.on_next value
|
32
|
+
observer.on_completed
|
33
|
+
else
|
34
|
+
observer.on_error(RuntimeError.new 'Sequence contains no elements')
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
subscribe new_obs
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
# Applies an accumulator function over an observable sequence, returning the result of the aggregation as a single
|
44
|
+
# element in the result sequence. The specified seed value is used as the initial accumulator value.
|
45
|
+
# For aggregation behavior with incremental intermediate results, see RxRuby::Observable.scan
|
46
|
+
# @return [RxRuby::Observable]
|
47
|
+
def reduce(*args, &block)
|
48
|
+
# Argument parsing to support:
|
49
|
+
# 1. (seed, Symbol) || (seed, &block)
|
50
|
+
# 2. (Symbol) || (&block)
|
51
|
+
if (args.length == 2 && args[1].is_a?(Symbol)) || (args.length == 1 && block_given?)
|
52
|
+
scan(*args, &block).start_with(args[0]).final
|
53
|
+
elsif (args.length == 1 && args[0].is_a?(Symbol)) || (args.length == 0 && block_given?)
|
54
|
+
scan(*args, &block).final
|
55
|
+
else
|
56
|
+
raise ArgumentError.new 'Invalid arguments'
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
# Determines whether all elements of an observable sequence satisfy a condition if block given, else if all are
|
61
|
+
# true
|
62
|
+
# @param [Proc] block
|
63
|
+
# @return [RxRuby::Observable]
|
64
|
+
def all?(&block)
|
65
|
+
block ||= lambda { |_| true }
|
66
|
+
select {|v| !(block.call v)}.
|
67
|
+
any?.
|
68
|
+
map {|b| !b }
|
69
|
+
end
|
70
|
+
|
71
|
+
# Determines whether no elements of an observable sequence satisfy a condition if block given, else if all are
|
72
|
+
# false
|
73
|
+
# @param [Proc] block
|
74
|
+
# @return [RxRuby::Observable]
|
75
|
+
def none?(&block)
|
76
|
+
block ||= lambda { |_| true }
|
77
|
+
select {|v| !(block.call v)}.
|
78
|
+
any?
|
79
|
+
end
|
80
|
+
|
81
|
+
# Determines whether any element of an observable sequence satisfies a condition if a block is given else if
|
82
|
+
# there are any items in the observable sequence.
|
83
|
+
# @return [RxRuby::Observable]
|
84
|
+
def any?(&block)
|
85
|
+
return map(&block).any? if block_given?
|
86
|
+
AnonymousObservable.new do |observer|
|
87
|
+
new_obs = Observer.configure do |o|
|
88
|
+
o.on_next do |_|
|
89
|
+
observer.on_next true
|
90
|
+
observer.on_completed
|
91
|
+
end
|
92
|
+
|
93
|
+
o.on_error(&observer.method(:on_error))
|
94
|
+
|
95
|
+
o.on_completed do
|
96
|
+
observer.on_next false
|
97
|
+
observer.on_completed
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
subscribe new_obs
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
# Computes the average of an observable sequence of values that are optionally obtained by invoking a
|
106
|
+
# transform function on each element of the input sequence if a block is given
|
107
|
+
# @param [Object] block
|
108
|
+
# @return [RxRuby::Observable]
|
109
|
+
def average(&block)
|
110
|
+
return map(&block).average if block_given?
|
111
|
+
scan({:sum => 0, :count => 0}) {|prev, current| {:sum => prev[:sum] + current, :count => prev[:count] + 1 }}.
|
112
|
+
final.
|
113
|
+
map {|x|
|
114
|
+
raise 'Sequence contains no elements' if x[:count] == 0
|
115
|
+
x[:sum] / x[:count]
|
116
|
+
}
|
117
|
+
end
|
118
|
+
|
119
|
+
# Determines whether an observable sequence contains a specified element.
|
120
|
+
# @param [Object] item The value to locate in the source sequence.
|
121
|
+
# @return [RxRuby::Observable] An observable sequence containing a single element determining whether the source
|
122
|
+
# sequence contains an element that has the specified value.
|
123
|
+
def contains?(item)
|
124
|
+
select {|x| x.eql? item}.any?
|
125
|
+
end
|
126
|
+
|
127
|
+
# Returns an observable sequence containing a number that represents how many elements in the specified
|
128
|
+
# observable sequence satisfy a condition if the block is given, else the number of items in the observable
|
129
|
+
# sequence
|
130
|
+
def count(&block)
|
131
|
+
return select(&block).count if block_given?
|
132
|
+
reduce(0) {|c, _| c + 1 }
|
133
|
+
end
|
134
|
+
|
135
|
+
# Returns the element at a specified index in a sequence.
|
136
|
+
# @param [Numeric] index The zero-based index of the element to retrieve.
|
137
|
+
# @return [RxRuby::Observable] An observable sequence that produces the element at the specified position in the
|
138
|
+
# source sequence.
|
139
|
+
def element_at(index)
|
140
|
+
raise ArgumentError.new 'index cannot be less than zero' if index < 0
|
141
|
+
AnonymousObservable.new do |observer|
|
142
|
+
i = index
|
143
|
+
new_obs = Observer.configure do |o|
|
144
|
+
o.on_next do |value|
|
145
|
+
if i == 0
|
146
|
+
observer.on_next value
|
147
|
+
observer.on_completed
|
148
|
+
end
|
149
|
+
|
150
|
+
i -= 1
|
151
|
+
end
|
152
|
+
|
153
|
+
o.on_error(&observer.method(:on_error))
|
154
|
+
o.on_completed { raise 'Sequence contains no elements' }
|
155
|
+
end
|
156
|
+
|
157
|
+
subscribe new_obs
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
# Returns the element at a specified index in a sequence or a default value if the index is out of range.
|
162
|
+
# @param [Numeric] index The zero-based index of the element to retrieve.
|
163
|
+
# @param [Object] default_value The default value to use if the index is out of range.
|
164
|
+
def element_at_or_default(index, default_value = nil)
|
165
|
+
raise ArgumentError.new 'index cannot be less than zero' if index < 0
|
166
|
+
AnonymousObservable.new do |observer|
|
167
|
+
i = index
|
168
|
+
new_obs = Observer.configure do |o|
|
169
|
+
o.on_next do |value|
|
170
|
+
if i == 0
|
171
|
+
observer.on_next value
|
172
|
+
observer.on_completed
|
173
|
+
end
|
174
|
+
|
175
|
+
i -= 1
|
176
|
+
end
|
177
|
+
|
178
|
+
o.on_error(&observer.method(:on_error))
|
179
|
+
|
180
|
+
o.on_completed do
|
181
|
+
observer.on_next default_value
|
182
|
+
observer.on_completed
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
subscribe new_obs
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
190
|
+
# Returns the first element of an observable sequence that satisfies the condition in the predicate if a block is
|
191
|
+
# given, else the first item in the observable sequence.
|
192
|
+
# @param [Proc] block Optional predicate function to evaluate for elements in the source sequence.
|
193
|
+
# @return [RxRuby::Observable] Sequence containing the first element in the observable sequence that satisfies the
|
194
|
+
# condition in the predicate if a block is given, else the first element.
|
195
|
+
def first(&block)
|
196
|
+
return select(&block).first if block_given?
|
197
|
+
AnonymousObservable.new do |observer|
|
198
|
+
new_obs = Observer.configure do |o|
|
199
|
+
o.on_next do |x|
|
200
|
+
observer.on_next x
|
201
|
+
observer.on_completed
|
202
|
+
end
|
203
|
+
|
204
|
+
o.on_error(&observer.method(:on_error))
|
205
|
+
o.on_completed { raise 'Sequence contains no elements' }
|
206
|
+
end
|
207
|
+
|
208
|
+
subscribe new_obs
|
209
|
+
end
|
210
|
+
end
|
211
|
+
|
212
|
+
# Returns the first element of an observable sequence that satisfies the condition in the predicate if given,
|
213
|
+
# or a default value if no such element exists.
|
214
|
+
# @param [Object] default_value The default value to use if the sequence is empty.
|
215
|
+
# @param [Proc] block An optional predicate function to evaluate for elements in the source sequence.
|
216
|
+
# @return [RxRuby::Observable] Sequence containing the first element in the observable sequence that satisfies the
|
217
|
+
# condition in the predicate if given, or a default value if no such element exists.
|
218
|
+
def first_or_default(default_value = nil, &block)
|
219
|
+
return select(&block).first_or_default(default_value) if block_given?
|
220
|
+
AnonymousObservable.new do |observer|
|
221
|
+
new_obs = Observer.configure do |o|
|
222
|
+
o.on_next do |x|
|
223
|
+
observer.on_next x
|
224
|
+
observer.on_completed
|
225
|
+
end
|
226
|
+
|
227
|
+
o.on_error(&observer.method(:on_error))
|
228
|
+
|
229
|
+
o.on_completed do
|
230
|
+
observer.on_next default_value
|
231
|
+
observer.on_completed
|
232
|
+
end
|
233
|
+
end
|
234
|
+
|
235
|
+
subscribe new_obs
|
236
|
+
end
|
237
|
+
end
|
238
|
+
|
239
|
+
# Determines whether an observable sequence is empty.
|
240
|
+
# @return [RxRuby::Observable] An observable sequence containing a single element determining whether the source
|
241
|
+
# sequence is empty.
|
242
|
+
def empty?
|
243
|
+
any?.map {|b| !b }
|
244
|
+
end
|
245
|
+
|
246
|
+
# Returns the last element of an observable sequence that satisfies the condition in the predicate if the block is
|
247
|
+
# given, else the last element in the observable sequence.
|
248
|
+
# @param [Proc] block An predicate function to evaluate for elements in the source sequence.
|
249
|
+
# @return {RxRuby::Observable} Sequence containing the last element in the observable sequence that satisfies the
|
250
|
+
# condition in the predicate if given, or the last element in the observable sequence.
|
251
|
+
def last(&block)
|
252
|
+
return select(&block).last if block_given?
|
253
|
+
AnonymousObservable.new do |observer|
|
254
|
+
|
255
|
+
value = nil
|
256
|
+
seen_value = false
|
257
|
+
|
258
|
+
new_obs = Observer.configure do |o|
|
259
|
+
o.on_next do |v|
|
260
|
+
value = v
|
261
|
+
seen_value = true
|
262
|
+
end
|
263
|
+
|
264
|
+
o.on_error(&observer.method(:on_error))
|
265
|
+
|
266
|
+
o.on_completed do
|
267
|
+
if seen_value
|
268
|
+
observer.on_next value
|
269
|
+
observer.on_completed
|
270
|
+
else
|
271
|
+
observer.on_error(RuntimeError.new 'Sequence contains no elements' )
|
272
|
+
end
|
273
|
+
end
|
274
|
+
end
|
275
|
+
|
276
|
+
subscribe new_obs
|
277
|
+
end
|
278
|
+
end
|
279
|
+
|
280
|
+
# Returns the last element of an observable sequence that satisfies the condition in the predicate if given, or
|
281
|
+
# a default value if no such element exists.
|
282
|
+
# @param [Object] default_value The default value to use if the sequence is empty.
|
283
|
+
# @param [Proc] block An predicate function to evaluate for elements in the source sequence.
|
284
|
+
# @return {RxRuby::Observable} Sequence containing the last element in the observable sequence that satisfies the
|
285
|
+
# condition in the predicate if given, or a default value if no such element exists.
|
286
|
+
def last_or_default(default_value = nil, &block)
|
287
|
+
return select(&block).last_or_default(default_value) if block_given?
|
288
|
+
AnonymousObservable.new do |observer|
|
289
|
+
|
290
|
+
value = nil
|
291
|
+
seen_value = false
|
292
|
+
|
293
|
+
new_obs = Observer.configure do |o|
|
294
|
+
o.on_next do |v|
|
295
|
+
value = v
|
296
|
+
seen_value = true
|
297
|
+
end
|
298
|
+
|
299
|
+
o.on_error(&observer.method(:on_error))
|
300
|
+
|
301
|
+
o.on_completed do
|
302
|
+
observer.on_next (seen_value ? value : default_value)
|
303
|
+
observer.on_completed
|
304
|
+
end
|
305
|
+
end
|
306
|
+
|
307
|
+
subscribe new_obs
|
308
|
+
end
|
309
|
+
end
|
310
|
+
|
311
|
+
# Returns the maximum element in an observable sequence.
|
312
|
+
# @param [Proc] block An optional selector function to produce an element.
|
313
|
+
# @return [RxRuby::Observable] The maximum element in an observable sequence.
|
314
|
+
def max(&block)
|
315
|
+
return map(&block).max if block_given?
|
316
|
+
max_by {x| x} .map {|x| x[0] }
|
317
|
+
end
|
318
|
+
|
319
|
+
# Returns the elements in an observable sequence with the maximum key value.
|
320
|
+
# @param [Proc] block Key selector function.
|
321
|
+
# @return [RxRuby::Observable] An observable sequence containing a list of zero or more elements that have a maximum
|
322
|
+
# key value.
|
323
|
+
def max_by(&block)
|
324
|
+
extrema_by(&block)
|
325
|
+
end
|
326
|
+
|
327
|
+
# Returns the minimum element in an observable sequence.
|
328
|
+
# @param [Proc] block An optional selector function to produce an element.
|
329
|
+
# @return [RxRuby::Observable] The minimum element in an observable sequence.
|
330
|
+
def min(&block)
|
331
|
+
return map(&block).min if block_given?
|
332
|
+
min_by {|x| x} .map {|x| x[0] }
|
333
|
+
end
|
334
|
+
|
335
|
+
# Returns the elements in an observable sequence with the minimum key value.
|
336
|
+
# @param [Proc] block Key selector function.
|
337
|
+
# @return [RxRuby::Observable] >An observable sequence containing a list of zero or more elements that have a
|
338
|
+
# minimum key value.
|
339
|
+
def min_by(&block)
|
340
|
+
extrema_by(true, &block)
|
341
|
+
end
|
342
|
+
|
343
|
+
# Determines whether two sequences are equal by comparing the elements pairwise.
|
344
|
+
# @param [RxRuby::Observable] other Other observable sequence to compare.
|
345
|
+
# @return [RxRuby::Observable] An observable sequence that contains a single element which indicates whether both
|
346
|
+
# sequences are of equal length and their corresponding elements are equal.
|
347
|
+
def sequence_eql?(other)
|
348
|
+
AnonymousObservable.new do |observer|
|
349
|
+
gate = Mutex.new
|
350
|
+
left_done = false
|
351
|
+
right_done = false
|
352
|
+
left_queue = []
|
353
|
+
right_queue = []
|
354
|
+
|
355
|
+
obs1 = Observer.configure do |o|
|
356
|
+
o.on_next do |x|
|
357
|
+
gate.synchronize do
|
358
|
+
if right_queue.length > 0
|
359
|
+
v = right_queue.shift
|
360
|
+
equal = x == v
|
361
|
+
|
362
|
+
unless equal
|
363
|
+
observer.on_next false
|
364
|
+
observer.on_completed
|
365
|
+
end
|
366
|
+
elsif right_done
|
367
|
+
observer.on_next false
|
368
|
+
observer.on_completed
|
369
|
+
else
|
370
|
+
left_queue.push x
|
371
|
+
end
|
372
|
+
end
|
373
|
+
end
|
374
|
+
|
375
|
+
o.on_error(&observer.method(:on_error))
|
376
|
+
|
377
|
+
o.on_completed do
|
378
|
+
gate.synchronize do
|
379
|
+
left_done = true
|
380
|
+
if left_queue.length == 0
|
381
|
+
if right_queue.length > 0
|
382
|
+
observer.on_next false
|
383
|
+
observer.on_completed
|
384
|
+
elsif right_done
|
385
|
+
observer.on_next true
|
386
|
+
observer.on_completed
|
387
|
+
end
|
388
|
+
end
|
389
|
+
end
|
390
|
+
end
|
391
|
+
end
|
392
|
+
|
393
|
+
subscription1 = subscribe obs1
|
394
|
+
|
395
|
+
obs2 = Observer.configure do |o|
|
396
|
+
o.on_next do |x|
|
397
|
+
gate.synchronize do
|
398
|
+
if left_queue.length > 0
|
399
|
+
v = left_queue.shift
|
400
|
+
equal = x == v
|
401
|
+
|
402
|
+
unless equal
|
403
|
+
observer.on_next false
|
404
|
+
observer.on_completed
|
405
|
+
end
|
406
|
+
elsif left_done
|
407
|
+
observer.on_next false
|
408
|
+
observer.on_completed
|
409
|
+
else
|
410
|
+
right_queue.push x
|
411
|
+
end
|
412
|
+
end
|
413
|
+
end
|
414
|
+
|
415
|
+
o.on_error(&observer.method(:on_error))
|
416
|
+
|
417
|
+
o.on_completed do
|
418
|
+
gate.synchronize do
|
419
|
+
right_done = true
|
420
|
+
if right_queue.length == 0
|
421
|
+
if left_queue.length > 0
|
422
|
+
observer.on_next false
|
423
|
+
observer.on_completed
|
424
|
+
elsif left_done
|
425
|
+
observer.on_next true
|
426
|
+
observer.on_completed
|
427
|
+
end
|
428
|
+
end
|
429
|
+
end
|
430
|
+
end
|
431
|
+
end
|
432
|
+
|
433
|
+
subscription2 = other.subscribe obs2
|
434
|
+
|
435
|
+
CompositeSubscription.new [subscription1, subscription2]
|
436
|
+
end
|
437
|
+
end
|
438
|
+
|
439
|
+
# Returns the only element of an observable sequence, and reports an exception if there is not exactly one
|
440
|
+
# element in the observable sequence.
|
441
|
+
# @param [Proc] block A predicate function to evaluate for elements in the source sequence.
|
442
|
+
# @return [RxRuby::Observable] >Sequence containing the single element in the observable sequence.
|
443
|
+
def single(&block)
|
444
|
+
return select(&block).single if block_given?
|
445
|
+
AnonymousObservable.new do |observer|
|
446
|
+
seen_value = false
|
447
|
+
value = nil
|
448
|
+
|
449
|
+
new_obs = Observer.configure do |o|
|
450
|
+
o.on_next do |x|
|
451
|
+
if seen_value
|
452
|
+
observer.on_error(RuntimeError.new 'More than one element produced')
|
453
|
+
else
|
454
|
+
value = x
|
455
|
+
seen_value = true
|
456
|
+
end
|
457
|
+
end
|
458
|
+
|
459
|
+
o.on_error(&observer.method(:on_error))
|
460
|
+
|
461
|
+
o.on_completed do
|
462
|
+
if seen_value
|
463
|
+
observer.on_next value
|
464
|
+
observer.on_completed
|
465
|
+
else
|
466
|
+
observer.on_error(RuntimeError.new 'Sequence contains no elements')
|
467
|
+
end
|
468
|
+
end
|
469
|
+
end
|
470
|
+
|
471
|
+
subscribe new_obs
|
472
|
+
end
|
473
|
+
end
|
474
|
+
|
475
|
+
# Returns the only element of an observable sequence, or a default value if the observable sequence is empty;
|
476
|
+
# this method reports an exception if there is more than one element in the observable sequence.
|
477
|
+
# @param [Object] default_value The default value if no value is provided
|
478
|
+
# @param [Proc] block A predicate function to evaluate for elements in the source sequence.
|
479
|
+
# @return [RxRuby::Observable] Sequence containing the single element in the observable sequence, or a default value
|
480
|
+
# if no such element exists.
|
481
|
+
def single_or_default(default_value = nil, &block)
|
482
|
+
return select(&block).single_or_default(default_value) if block_given?
|
483
|
+
AnonymousObservable.new do |observer|
|
484
|
+
seen_value = false
|
485
|
+
value = nil
|
486
|
+
|
487
|
+
new_obs = Observer.configure do |o|
|
488
|
+
o.on_next do |x|
|
489
|
+
if seen_value
|
490
|
+
observer.on_error(RuntimeError.new 'More than one element produced')
|
491
|
+
else
|
492
|
+
value = x
|
493
|
+
seen_value = true
|
494
|
+
end
|
495
|
+
end
|
496
|
+
|
497
|
+
o.on_error(&observer.method(:on_error))
|
498
|
+
|
499
|
+
o.on_completed do
|
500
|
+
observer.on_next (seen_value ? value : default_value)
|
501
|
+
observer.on_completed
|
502
|
+
end
|
503
|
+
end
|
504
|
+
|
505
|
+
subscribe new_obs
|
506
|
+
end
|
507
|
+
end
|
508
|
+
|
509
|
+
# Computes the sum of a sequence of values.
|
510
|
+
# @param [Proc] block Optional block used to obtain the value to sum.
|
511
|
+
# @return [RxRuby::Observable] An observable sequence containing a single element with the sum of the values in the
|
512
|
+
# source sequence.
|
513
|
+
def sum(&block)
|
514
|
+
return map(&block).sum if block_given?
|
515
|
+
reduce(0) {|acc, x| acc + x}
|
516
|
+
end
|
517
|
+
|
518
|
+
# Creates an array from an observable sequence.
|
519
|
+
# @return [RxRuby::Observable] An array created from an observable sequence.
|
520
|
+
def to_a
|
521
|
+
AnonymousObservable.new do |observer|
|
522
|
+
arr = []
|
523
|
+
self.subscribe(
|
524
|
+
arr.method(:push),
|
525
|
+
observer.method(:on_error),
|
526
|
+
lambda {
|
527
|
+
observer.on_next arr
|
528
|
+
observer.on_completed
|
529
|
+
})
|
530
|
+
end
|
531
|
+
end
|
532
|
+
|
533
|
+
class HashConfiguration
|
534
|
+
DEFAULT_SELECTOR = lambda {|x| x}
|
535
|
+
|
536
|
+
attr_reader :key_selector_block, :value_selector_block
|
537
|
+
|
538
|
+
def initialize
|
539
|
+
@key_selector_block = DEFAULT_SELECTOR
|
540
|
+
@value_selector_block = DEFAULT_SELECTOR
|
541
|
+
end
|
542
|
+
|
543
|
+
def key_selector(&key_selector_block)
|
544
|
+
@key_selector_block = key_selector_block
|
545
|
+
end
|
546
|
+
|
547
|
+
def value_selector(&value_selector_block)
|
548
|
+
@on_error_block = value_selector_block
|
549
|
+
end
|
550
|
+
end
|
551
|
+
|
552
|
+
# Creates a Hash from the observable collection. Note that any duplicate keys will be overwritten.
|
553
|
+
# @return [RxRuby::Observable] A Hash created from an observable sequence.
|
554
|
+
def to_h
|
555
|
+
h = HashConfiguration.new
|
556
|
+
yield h if block_given?
|
557
|
+
reduce(Hash.new) do |acc, x|
|
558
|
+
acc[h.key_selector_block.call x] = h.value_selector_block.call x
|
559
|
+
acc
|
560
|
+
end
|
561
|
+
end
|
562
|
+
|
563
|
+
private
|
564
|
+
|
565
|
+
def extrema_by(is_min = false, &block)
|
566
|
+
AnonymousObservable.new do |observer|
|
567
|
+
has_value = false
|
568
|
+
last_key = nil
|
569
|
+
list = []
|
570
|
+
|
571
|
+
new_obs = Observer.configure do |o|
|
572
|
+
o.on_next do |x|
|
573
|
+
key = nil
|
574
|
+
begin
|
575
|
+
key = block.call(x)
|
576
|
+
rescue => e
|
577
|
+
observer.on_error e
|
578
|
+
return
|
579
|
+
end
|
580
|
+
|
581
|
+
comparison = 0
|
582
|
+
if has_value
|
583
|
+
comparison = key<=>last_key
|
584
|
+
comparison = comparison * -1 if is_min
|
585
|
+
else
|
586
|
+
has_value = true
|
587
|
+
last_key = key
|
588
|
+
end
|
589
|
+
|
590
|
+
if comparison > 0
|
591
|
+
last_key = key
|
592
|
+
list = []
|
593
|
+
end
|
594
|
+
list.push x if comparison >= 0
|
595
|
+
end
|
596
|
+
|
597
|
+
o.on_error(&observer.method(:on_error))
|
598
|
+
|
599
|
+
o.on_completed do
|
600
|
+
observer.on_next list
|
601
|
+
observer.on_completed
|
602
|
+
end
|
603
|
+
|
604
|
+
end
|
605
|
+
|
606
|
+
subscribe new_obs
|
607
|
+
end
|
608
|
+
end
|
609
|
+
|
610
|
+
end
|
611
|
+
end
|