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.
Files changed (186) hide show
  1. checksums.yaml +7 -0
  2. data/.gitattributes +22 -0
  3. data/.gitignore +173 -0
  4. data/.travis.yml +10 -0
  5. data/Gemfile +4 -0
  6. data/Rakefile +11 -0
  7. data/examples/aggregate.rb +39 -0
  8. data/examples/amb.rb +25 -0
  9. data/examples/ambproto.rb +24 -0
  10. data/examples/and.rb +26 -0
  11. data/examples/as_observable.rb +25 -0
  12. data/examples/average.rb +43 -0
  13. data/examples/buffer_with_count.rb +44 -0
  14. data/examples/buffer_with_time.rb +51 -0
  15. data/examples/case.rb +29 -0
  16. data/examples/catch.rb +20 -0
  17. data/examples/catchproto.rb +39 -0
  18. data/examples/combine_latest.rb +35 -0
  19. data/examples/combine_latestproto.rb +33 -0
  20. data/examples/concat.rb +22 -0
  21. data/examples/concat_all.rb +27 -0
  22. data/examples/concat_map.rb +61 -0
  23. data/examples/concat_map_observer.rb +29 -0
  24. data/examples/concatproto.rb +25 -0
  25. data/examples/connect.rb +41 -0
  26. data/examples/contains.rb +37 -0
  27. data/examples/count.rb +36 -0
  28. data/examples/create.rb +55 -0
  29. data/examples/debounce.rb +35 -0
  30. data/examples/default_if_empty.rb +35 -0
  31. data/examples/defer.rb +20 -0
  32. data/examples/delay.rb +49 -0
  33. data/examples/delay_with_selector.rb +63 -0
  34. data/examples/dematerialize.rb +22 -0
  35. data/examples/disposable.rb +12 -0
  36. data/examples/distinct.rb +43 -0
  37. data/examples/distinct_until_changed.rb +43 -0
  38. data/examples/do.rb +59 -0
  39. data/examples/empty.rb +16 -0
  40. data/examples/for.rb +26 -0
  41. data/examples/fork_join.rb +23 -0
  42. data/examples/from.rb +106 -0
  43. data/examples/from_array.rb +21 -0
  44. data/examples/from_callback.rb +21 -0
  45. data/examples/generate.rb +24 -0
  46. data/examples/group_join.rb +39 -0
  47. data/examples/if.rb +46 -0
  48. data/examples/intervals.rb +26 -0
  49. data/examples/merge.rb +36 -0
  50. data/examples/merge_all.rb +27 -0
  51. data/examples/multicast.rb +32 -0
  52. data/examples/never.rb +15 -0
  53. data/examples/of.rb +19 -0
  54. data/examples/on_error_resume_next.rb +21 -0
  55. data/examples/pairs.rb +26 -0
  56. data/examples/publish.rb +79 -0
  57. data/examples/range.rb +19 -0
  58. data/examples/reduce.rb +18 -0
  59. data/examples/repeat.rb +19 -0
  60. data/examples/return.rb +17 -0
  61. data/examples/scan.rb +41 -0
  62. data/examples/start.rb +29 -0
  63. data/examples/throw.rb +17 -0
  64. data/examples/time_intervals.rb +28 -0
  65. data/examples/timer.rb +26 -0
  66. data/examples/timestamp.rb +28 -0
  67. data/examples/to_a.rb +23 -0
  68. data/examples/to_async.rb +26 -0
  69. data/examples/using.rb +52 -0
  70. data/examples/when.rb +26 -0
  71. data/examples/while.rb +25 -0
  72. data/examples/window_with_time.rb +78 -0
  73. data/examples/zip.rb +27 -0
  74. data/examples/zip_array.rb +25 -0
  75. data/lib/core_ext/enumerable.rb +22 -0
  76. data/lib/rx_ruby.rb +27 -0
  77. data/lib/rx_ruby/concurrency/async_lock.rb +57 -0
  78. data/lib/rx_ruby/concurrency/current_thread_scheduler.rb +75 -0
  79. data/lib/rx_ruby/concurrency/default_scheduler.rb +51 -0
  80. data/lib/rx_ruby/concurrency/historical_scheduler.rb +16 -0
  81. data/lib/rx_ruby/concurrency/immediate_scheduler.rb +68 -0
  82. data/lib/rx_ruby/concurrency/local_scheduler.rb +39 -0
  83. data/lib/rx_ruby/concurrency/periodic_scheduler.rb +74 -0
  84. data/lib/rx_ruby/concurrency/scheduled_item.rb +42 -0
  85. data/lib/rx_ruby/concurrency/scheduler.rb +150 -0
  86. data/lib/rx_ruby/concurrency/virtual_time_scheduler.rb +170 -0
  87. data/lib/rx_ruby/core/async_lock_observer.rb +46 -0
  88. data/lib/rx_ruby/core/auto_detach_observer.rb +59 -0
  89. data/lib/rx_ruby/core/checked_observer.rb +66 -0
  90. data/lib/rx_ruby/core/notification.rb +161 -0
  91. data/lib/rx_ruby/core/observable.rb +104 -0
  92. data/lib/rx_ruby/core/observe_on_observer.rb +50 -0
  93. data/lib/rx_ruby/core/observer.rb +119 -0
  94. data/lib/rx_ruby/core/scheduled_observer.rb +83 -0
  95. data/lib/rx_ruby/core/synchronized_observer.rb +47 -0
  96. data/lib/rx_ruby/core/time_interval.rb +17 -0
  97. data/lib/rx_ruby/internal/priority_queue.rb +122 -0
  98. data/lib/rx_ruby/internal/util.rb +9 -0
  99. data/lib/rx_ruby/joins/active_plan.rb +45 -0
  100. data/lib/rx_ruby/joins/join_observer.rb +51 -0
  101. data/lib/rx_ruby/joins/pattern.rb +14 -0
  102. data/lib/rx_ruby/joins/plan.rb +44 -0
  103. data/lib/rx_ruby/linq/connectable_observable.rb +34 -0
  104. data/lib/rx_ruby/linq/observable/_observable_timer_date_and_period.rb +22 -0
  105. data/lib/rx_ruby/linq/observable/_observable_timer_time_span.rb +14 -0
  106. data/lib/rx_ruby/linq/observable/_observable_timer_time_span_and_period.rb +20 -0
  107. data/lib/rx_ruby/linq/observable/aggregate.rb +7 -0
  108. data/lib/rx_ruby/linq/observable/and.rb +7 -0
  109. data/lib/rx_ruby/linq/observable/case.rb +15 -0
  110. data/lib/rx_ruby/linq/observable/concat_all.rb +7 -0
  111. data/lib/rx_ruby/linq/observable/concat_map.rb +35 -0
  112. data/lib/rx_ruby/linq/observable/concat_map_observer.rb +43 -0
  113. data/lib/rx_ruby/linq/observable/contains.rb +28 -0
  114. data/lib/rx_ruby/linq/observable/debounce.rb +41 -0
  115. data/lib/rx_ruby/linq/observable/delay.rb +81 -0
  116. data/lib/rx_ruby/linq/observable/delay_with_selector.rb +64 -0
  117. data/lib/rx_ruby/linq/observable/do.rb +42 -0
  118. data/lib/rx_ruby/linq/observable/for.rb +13 -0
  119. data/lib/rx_ruby/linq/observable/fork_join.rb +55 -0
  120. data/lib/rx_ruby/linq/observable/from.rb +34 -0
  121. data/lib/rx_ruby/linq/observable/group_join.rb +108 -0
  122. data/lib/rx_ruby/linq/observable/if.rb +17 -0
  123. data/lib/rx_ruby/linq/observable/interval.rb +5 -0
  124. data/lib/rx_ruby/linq/observable/multicast.rb +14 -0
  125. data/lib/rx_ruby/linq/observable/of.rb +11 -0
  126. data/lib/rx_ruby/linq/observable/pairs.rb +7 -0
  127. data/lib/rx_ruby/linq/observable/pluck.rb +7 -0
  128. data/lib/rx_ruby/linq/observable/publish.rb +11 -0
  129. data/lib/rx_ruby/linq/observable/start.rb +7 -0
  130. data/lib/rx_ruby/linq/observable/time_interval.rb +15 -0
  131. data/lib/rx_ruby/linq/observable/timer.rb +26 -0
  132. data/lib/rx_ruby/linq/observable/timestamp.rb +9 -0
  133. data/lib/rx_ruby/linq/observable/to_async.rb +40 -0
  134. data/lib/rx_ruby/linq/observable/when.rb +36 -0
  135. data/lib/rx_ruby/linq/observable/while.rb +41 -0
  136. data/lib/rx_ruby/operators/aggregates.rb +611 -0
  137. data/lib/rx_ruby/operators/creation.rb +220 -0
  138. data/lib/rx_ruby/operators/multiple.rb +735 -0
  139. data/lib/rx_ruby/operators/single.rb +399 -0
  140. data/lib/rx_ruby/operators/standard_query_operators.rb +279 -0
  141. data/lib/rx_ruby/operators/synchronization.rb +47 -0
  142. data/lib/rx_ruby/operators/time.rb +120 -0
  143. data/lib/rx_ruby/subjects/async_subject.rb +161 -0
  144. data/lib/rx_ruby/subjects/behavior_subject.rb +149 -0
  145. data/lib/rx_ruby/subjects/replay_subject.rb +39 -0
  146. data/lib/rx_ruby/subjects/subject.rb +131 -0
  147. data/lib/rx_ruby/subjects/subject_extensions.rb +45 -0
  148. data/lib/rx_ruby/subscriptions/composite_subscription.rb +91 -0
  149. data/lib/rx_ruby/subscriptions/ref_count_subscription.rb +88 -0
  150. data/lib/rx_ruby/subscriptions/scheduled_subscription.rb +32 -0
  151. data/lib/rx_ruby/subscriptions/serial_subscription.rb +60 -0
  152. data/lib/rx_ruby/subscriptions/single_assignment_subscription.rb +64 -0
  153. data/lib/rx_ruby/subscriptions/subscription.rb +56 -0
  154. data/lib/rx_ruby/testing/cold_observable.rb +45 -0
  155. data/lib/rx_ruby/testing/hot_observable.rb +47 -0
  156. data/lib/rx_ruby/testing/mock_observer.rb +33 -0
  157. data/lib/rx_ruby/testing/reactive_test.rb +94 -0
  158. data/lib/rx_ruby/testing/recorded.rb +17 -0
  159. data/lib/rx_ruby/testing/test_scheduler.rb +96 -0
  160. data/lib/rx_ruby/testing/test_subscription.rb +22 -0
  161. data/lib/rx_ruby/version.rb +3 -0
  162. data/license.txt +13 -0
  163. data/readme.md +152 -0
  164. data/rx_ruby.gemspec +22 -0
  165. data/test/rx_ruby/concurrency/helpers/historical_virtual_scheduler_helper.rb +135 -0
  166. data/test/rx_ruby/concurrency/helpers/immediate_local_scheduler_helper.rb +51 -0
  167. data/test/rx_ruby/concurrency/test_async_lock.rb +56 -0
  168. data/test/rx_ruby/concurrency/test_current_thread_scheduler.rb +44 -0
  169. data/test/rx_ruby/concurrency/test_default_scheduler.rb +44 -0
  170. data/test/rx_ruby/concurrency/test_historical_scheduler.rb +18 -0
  171. data/test/rx_ruby/concurrency/test_immediate_scheduler.rb +53 -0
  172. data/test/rx_ruby/concurrency/test_local_scheduler.rb +12 -0
  173. data/test/rx_ruby/concurrency/test_periodic_scheduler.rb +53 -0
  174. data/test/rx_ruby/concurrency/test_scheduled_item.rb +50 -0
  175. data/test/rx_ruby/concurrency/test_scheduler.rb +128 -0
  176. data/test/rx_ruby/concurrency/test_virtual_time_scheduler.rb +14 -0
  177. data/test/rx_ruby/core/test_notification.rb +129 -0
  178. data/test/rx_ruby/core/test_observable_creation.rb +483 -0
  179. data/test/rx_ruby/core/test_observer.rb +634 -0
  180. data/test/rx_ruby/internal/test_priority_queue.rb +71 -0
  181. data/test/rx_ruby/subscriptions/test_composite_subscription.rb +116 -0
  182. data/test/rx_ruby/subscriptions/test_serial_subscription.rb +62 -0
  183. data/test/rx_ruby/subscriptions/test_singleassignment_subscription.rb +61 -0
  184. data/test/rx_ruby/subscriptions/test_subscription.rb +27 -0
  185. data/test/test_helper.rb +11 -0
  186. metadata +291 -0
@@ -0,0 +1,39 @@
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/concurrency/current_thread_scheduler'
5
+ require 'rx_ruby/core/observer'
6
+ require 'rx_ruby/core/observable'
7
+ require 'rx_ruby/core/time_interval'
8
+
9
+ module RxRuby
10
+
11
+ # Represents an object that is both an observable sequence as well as an observer.
12
+ # Each notification is broadcasted to all subscribed and future observers, subject to buffer trimming policies.
13
+ class ReplaySubject
14
+
15
+ include Observer
16
+ include Observable
17
+
18
+ INFINITE_BUFFER_SIZE = Float::MAX.to_i
19
+
20
+ def initialize(buffer_size = INFINITE_BUFFER_SIZE, window_size = INFINITE_BUFFER_SIZE, scheduler = CurrentThreadScheduler.instance)
21
+ @buffer_size = buffer_size
22
+ @window_size = window_size
23
+ @scheduler = scheduler
24
+ @queue = []
25
+ @observers = []
26
+ @stopped = false
27
+ @error = nil
28
+ end
29
+
30
+ # Indicates whether the subject has observers subscribed to it.
31
+ # @return [B]
32
+ def has_observers?
33
+ observers = @observers
34
+ observers && observers.length > 0
35
+ end
36
+
37
+ end
38
+
39
+ end
@@ -0,0 +1,131 @@
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/core/observer'
5
+ require 'rx_ruby/core/observable'
6
+ require 'rx_ruby/subscriptions/subscription'
7
+
8
+ module RxRuby
9
+
10
+ # Represents an object that is both an observable sequence as well as an observer.
11
+ # Each notification is broadcasted to all subscribed observers.
12
+ class Subject
13
+
14
+ include Observable
15
+ include Observer
16
+
17
+ def initialize
18
+ @observers = []
19
+ @gate = Mutex.new
20
+ @disposed = false
21
+ @stopped = false
22
+ @error = nil
23
+ end
24
+
25
+ # Indicates whether the subject has observers subscribed to it.
26
+ def has_observers?
27
+ @observers && @observers.length > 0
28
+ end
29
+
30
+ # Notifies all subscribed observers about the end of the sequence.
31
+ def on_completed
32
+ os = nil
33
+ @gate.synchronize do
34
+ check_disposed
35
+
36
+ unless @stopped
37
+ os = @observers.clone
38
+ @observers = []
39
+ @stopped = true
40
+ end
41
+ end
42
+
43
+ os.each {|o| o.on_completed } if os
44
+ end
45
+
46
+ # Notifies all subscribed observers with the error.
47
+ def on_error(error)
48
+ raise 'error cannot be nil' unless error
49
+
50
+ os = nil
51
+ @gate.synchronize do
52
+ check_disposed
53
+
54
+ unless @stopped
55
+ os = @observers.clone
56
+ @observers = []
57
+ @stopped = true
58
+ @error = error
59
+ end
60
+ end
61
+
62
+ os.each {|o| o.on_error error } if os
63
+ end
64
+
65
+ # Notifies all subscribed observers with the value.
66
+ def on_next(value)
67
+ os = nil
68
+ @gate.synchronize do
69
+ check_disposed
70
+ os = @observers.clone unless @stopped
71
+ end
72
+
73
+ os.each {|o| o.on_next value } if os
74
+ end
75
+
76
+ # Subscribes an observer to the subject.
77
+ def subscribe(observer)
78
+ raise 'observer cannot be nil' unless observer
79
+
80
+ @gate.synchronize do
81
+ check_disposed
82
+
83
+ if !@stopped
84
+ @observers.push(observer)
85
+ return InnerSubscription.new(self, observer)
86
+ elsif @error
87
+ observer.on_error @error
88
+ return Subscription.empty
89
+ else
90
+ observer.on_completed
91
+ return Subscription.empty
92
+ end
93
+ end
94
+ end
95
+
96
+ # Unsubscribe all observers and release resources.
97
+ def unsubscribe
98
+ @gate.synchronize do
99
+ @disposed = true
100
+ @observers = nil
101
+ end
102
+ end
103
+
104
+ class InnerSubscription
105
+ def initialize(subject, observer)
106
+ @subject = subject
107
+ @observer = observer
108
+ end
109
+
110
+ def unsubscribe
111
+ if @observer
112
+ @subject.send(:unsubscribe_observer, @observer)
113
+ @subject = nil
114
+ @observer = nil
115
+ end
116
+ end
117
+ end
118
+
119
+ private
120
+
121
+ def unsubscribe_observer(observer)
122
+ @gate.synchronize do
123
+ @observers.delete(observer) if @observers
124
+ end
125
+ end
126
+
127
+ def check_disposed
128
+ raise ArgumentError.new 'Subject disposed' if @disposed
129
+ end
130
+ end
131
+ end
@@ -0,0 +1,45 @@
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/core/observer'
4
+ require 'rx_ruby/core/observable'
5
+
6
+ module RxRuby
7
+
8
+ # Provides a set of static methods for creating subjects.
9
+ class Subject
10
+
11
+ # Creates a subject from the specified observer and observable.
12
+ def self.create(observer, observable)
13
+ AnonymousSubject.new(observer, observable)
14
+ end
15
+
16
+ class AnonymousSubject
17
+ include Observable
18
+ include Observer
19
+
20
+ def initialize(observer, observable)
21
+ @observer = observer
22
+ @observable = observable
23
+ end
24
+
25
+ def on_completed
26
+ @observer.on_completed
27
+ end
28
+
29
+ def on_error(error)
30
+ raise 'error cannot be nil' unless error
31
+ @observer.on_error(error)
32
+ end
33
+
34
+ def on_next(value)
35
+ @observer.on_next(value)
36
+ end
37
+
38
+ def subscribe(observer)
39
+ raise 'observer cannot be nil' unless observer
40
+ @observable.subscribe(observer)
41
+ end
42
+ end
43
+
44
+ end
45
+ end
@@ -0,0 +1,91 @@
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
+
5
+ module RxRuby
6
+
7
+ # Represents a group of subscription resources that are unsubscribed together.
8
+ class CompositeSubscription
9
+
10
+ include Enumerable
11
+
12
+ attr_reader :length
13
+
14
+ def initialize(subscriptions = [])
15
+ @subscriptions = subscriptions
16
+ @length = subscriptions.length
17
+ @unsubscribed = false
18
+ @gate = Mutex.new
19
+ end
20
+
21
+ # Gets a value that indicates whether the object is unsubscribed.
22
+ def unsubscribed?
23
+ @unsubscribed
24
+ end
25
+
26
+ def each(&block)
27
+ @subscriptions.each(&block)
28
+ end
29
+
30
+ # Unsubscribes all subscriptions in the group and removes them from the group.
31
+ def unsubscribe
32
+ currentSubscriptions = nil
33
+
34
+ @gate.synchronize do
35
+ unless @unsubscribed
36
+ @unsubscribed = true
37
+ currentSubscriptions = @subscriptions
38
+ @subscriptions = []
39
+ @length = 0
40
+ end
41
+ end
42
+
43
+ currentSubscriptions.each {|subscription| subscription.unsubscribe} if currentSubscriptions
44
+ end
45
+
46
+ # Adds a subscription to the CompositeSubscription or unsubscribes the subscription if the CompositeSubscription is unsubscribed.
47
+ def push(subscription)
48
+ should_unsubscribe = false
49
+
50
+ @gate.synchronize do
51
+ should_unsubscribe = @unsubscribed
52
+
53
+ unless @unsubscribed
54
+ @subscriptions.push(subscription)
55
+ @length += 1
56
+ end
57
+ end
58
+
59
+ subscription.unsubscribe if should_unsubscribe
60
+
61
+ return self
62
+ end
63
+ alias_method :<<, :push
64
+
65
+ # Removes and unsubscribes all subscriptions from the CompositeSubscription, but does not dispose the CompositeSubscription.
66
+ def clear
67
+ currentSubscriptions = nil
68
+
69
+ @gate.synchronize do
70
+ currentSubscriptions = @subscriptions
71
+ @subscriptions = []
72
+ @length = 0
73
+ end
74
+ currentSubscriptions.each {|subscription| subscription.unsubscribe}
75
+ end
76
+
77
+ # Removes and unsubscribes the first occurrence of a subscription from the CompositeSubscription.
78
+ def delete(subscription)
79
+ should_unsubscribe = nil
80
+
81
+ @gate.synchronize do
82
+ should_unsubscribe = @subscriptions.delete(subscription)
83
+ @length -= 1 if should_unsubscribe
84
+ end
85
+
86
+ subscription.unsubscribe if should_unsubscribe
87
+
88
+ should_unsubscribe
89
+ end
90
+ end
91
+ end
@@ -0,0 +1,88 @@
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/subscription'
5
+
6
+ module RxRuby
7
+
8
+ # Represents a subscription resource that only disposes its underlying subscription resource when all dependent subscription objects have been unsubscribed.
9
+ class RefCountSubscription
10
+
11
+ def initialize(subscription)
12
+ raise ArgumentError.new 'Subscription cannot be nil' unless subscription
13
+
14
+ @subscription = subscription
15
+ @primary_unsubscribed = false
16
+ @gate = Mutex.new
17
+ @count = 0
18
+ end
19
+
20
+ # Gets a value that indicates whether the object is disposed.
21
+ def unsubscribed?
22
+ @subscription.nil?
23
+ end
24
+
25
+ # Returns a dependent subscription that when disposed decreases the refcount on the underlying subscription.
26
+ def subscription
27
+ @gate.synchronize do
28
+ if @subscription
29
+ @count += 1
30
+ return InnerSubscription.new self
31
+ else
32
+ return Subscription.empty
33
+ end
34
+ end
35
+ end
36
+
37
+ # Unsubscribes the underlying subscription only when all dependent subscriptions have been unsubscribed.
38
+ def unsubscribe
39
+ subscription = nil
40
+ @gate.synchronize do
41
+ if @subscription
42
+ unless @primary_unsubscribed
43
+ @primary_unsubscribed = true
44
+
45
+ if @count == 0
46
+ subscription = @subscription
47
+ @subscription = nil
48
+ end
49
+ end
50
+ end
51
+ end
52
+
53
+ subscription.unsubscribe if subscription
54
+ end
55
+
56
+ def release
57
+ subscription = nil
58
+ @gate.synchronize do
59
+ if @subscription
60
+ @count -= 1
61
+
62
+ if @primary_unsubscribed && @count == 0
63
+ subscription = @subscription
64
+ @subscription = nil
65
+ end
66
+ end
67
+ end
68
+
69
+ subscription.unsubscribe if subscription
70
+ end
71
+
72
+ class InnerSubscription
73
+ def initialize(parent)
74
+ @parent = parent
75
+ end
76
+
77
+ def unsubscribe
78
+ parent = nil
79
+ Mutex.new.synchronize do
80
+ parent = @parent
81
+ @parent = nil
82
+ end
83
+ parent.release if parent
84
+ end
85
+ end
86
+
87
+ end
88
+ end
@@ -0,0 +1,32 @@
1
+ # Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
2
+
3
+ module RxRuby
4
+ # Represents a disposable resource whose disposal invocation will be scheduled on the specified scheduler
5
+ class ScheduledDisposable
6
+
7
+ attr_reader :scheduler, :subscription
8
+
9
+ def initialize(scheduler, subscription)
10
+ raise 'disposable cannot be nil' unless subscription
11
+ raise 'scheduler cannot be nil' unless scheduler
12
+
13
+ @scheduler = scheduler
14
+ @subscription = subscription
15
+ end
16
+
17
+ # Gets a value that indicates whether the object is unsubscribed.
18
+ def unsubscribed?
19
+ @subscription.nil?
20
+ end
21
+
22
+ # Unsubscribes the wrapped subscription on the provided scheduler.
23
+ def unsubscribe
24
+ @scheduler.schedule lambda do
25
+ unless @subscription.nil?
26
+ @subscription.unsubscribe
27
+ @subscription = nil
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,60 @@
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
+
5
+ module RxRuby
6
+
7
+ # Represents a subscription resource whose underlying subscription resource can be replaced by another subscription resource, causing automatic disposal of the previous underlying subscription resource.
8
+ class SerialSubscription
9
+ include Subscription
10
+
11
+ def initialize
12
+ @gate = Mutex.new
13
+ @current = nil
14
+ @unsubscribed = false
15
+ end
16
+
17
+ # Gets a value that indicates whether the object is unsubscribed.
18
+ def unsubscribed?
19
+ @gate.synchronize do
20
+ return @unsubscribed
21
+ end
22
+ end
23
+
24
+ # Gets the underlying subscription.
25
+ def subscription
26
+ @current
27
+ end
28
+
29
+ # Sets the underlying subscription.
30
+ def subscription=(new_subscription)
31
+ should_unsubscribe = false
32
+ old = nil
33
+ @gate.synchronize do
34
+ should_unsubscribe = @unsubscribed
35
+ unless should_unsubscribe
36
+ old = @current
37
+ @current = new_subscription
38
+ end
39
+ end
40
+
41
+ old.unsubscribe if old
42
+ new_subscription.unsubscribe if should_unsubscribe && !new_subscription.nil?
43
+ end
44
+
45
+ # Unsubscribes the current underlying subscription and all future subscriptions.
46
+ def unsubscribe
47
+ old = nil
48
+ @gate.synchronize do
49
+ unless @unsubscribed
50
+ @unsubscribed = true
51
+ old = @current
52
+ @current = nil
53
+ end
54
+ end
55
+
56
+ old.unsubscribe if old
57
+ end
58
+
59
+ end
60
+ end