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,26 @@
1
+ require 'rx_ruby'
2
+
3
+ func = RxRuby::Observable.to_async(lambda {|x, y|
4
+ return x + y
5
+ })
6
+
7
+ # Execute function with 3 and 4
8
+ source = func.call(3, 4)
9
+
10
+ subscription = source.subscribe(
11
+ lambda {|x|
12
+ puts 'Next: ' + x.to_s
13
+ },
14
+ lambda {|err|
15
+ puts 'Error: ' + err.to_s
16
+ },
17
+ lambda {
18
+ puts 'Completed'
19
+ })
20
+
21
+ # => Next: 7
22
+ # => Completed
23
+
24
+ while Thread.list.size > 1
25
+ (Thread.list - [Thread.current]).each &:join
26
+ end
data/examples/using.rb ADDED
@@ -0,0 +1,52 @@
1
+ require 'rx_ruby'
2
+
3
+ # Using an AsyncSubject as a resource which supports the .dispose method
4
+ class DisposableResource
5
+ def initialize(value, disposed = false)
6
+ @value = value
7
+ @disposed = disposed
8
+ end
9
+
10
+ def value
11
+ if @disposed
12
+ throw Exception.new('Object is disposed')
13
+ end
14
+ @value
15
+ end
16
+
17
+ def unsubscribe
18
+ unless @disposed
19
+ @disposed = true
20
+ @value = nil
21
+ end
22
+ puts 'Disposed'
23
+ end
24
+ end
25
+
26
+ source = RxRuby::Observable.using(
27
+ lambda { return DisposableResource.new(42) },
28
+ lambda {|resource|
29
+ subject = RxRuby::AsyncSubject.new
30
+ subject.on_next(resource.value)
31
+ subject.on_completed
32
+ return subject
33
+ }
34
+ )
35
+
36
+ subscription = source.subscribe(
37
+ lambda {|x|
38
+ puts 'Next: ' + x.to_s
39
+ },
40
+ lambda {|err|
41
+ puts 'Error: ' + err.to_s
42
+ },
43
+ lambda {
44
+ puts 'Completed'
45
+ })
46
+
47
+ # => Next: 42
48
+ # => Completed
49
+
50
+ subscription.dispose
51
+
52
+ # => Disposed
data/examples/when.rb ADDED
@@ -0,0 +1,26 @@
1
+ require 'rx_ruby'
2
+
3
+ # Fire each plan when both are ready
4
+ source = RxRuby::Observable.when(
5
+ RxRuby::Observable.timer(0.1).and(RxRuby::Observable.timer(0.5)).then_do(lambda {|x, y| return 'first' }),
6
+ RxRuby::Observable.timer(0.4).and(RxRuby::Observable.timer(0.3)).then_do {|x, y| 'second' }
7
+ )
8
+
9
+ subscription = source.subscribe(
10
+ lambda {|x|
11
+ puts 'Next: ' + x.to_s
12
+ },
13
+ lambda {|err|
14
+ puts 'Error: ' + err.to_s
15
+ },
16
+ lambda {
17
+ puts 'Completed'
18
+ })
19
+
20
+ # => Next: second
21
+ # => Next: first
22
+ # => Completed
23
+
24
+ while Thread.list.size > 1
25
+ (Thread.list - [Thread.current]).each &:join
26
+ end
data/examples/while.rb ADDED
@@ -0,0 +1,25 @@
1
+ require 'rx_ruby'
2
+
3
+ i = 0
4
+
5
+ # Repeat until condition no longer holds
6
+ source = RxRuby::Observable.while(
7
+ lambda { i += 1; i <= 3 },
8
+ RxRuby::Observable.return(42)
9
+ )
10
+
11
+ subscription = source.subscribe(
12
+ lambda {|x|
13
+ puts 'Next: ' + x.to_s
14
+ },
15
+ lambda {|err|
16
+ puts 'Error: ' + err.to_s
17
+ },
18
+ lambda {
19
+ puts 'Completed'
20
+ })
21
+
22
+ # => Next: 42
23
+ # => Next: 42
24
+ # => Next: 42
25
+ # => Completed
@@ -0,0 +1,78 @@
1
+ require 'rx_ruby'
2
+
3
+ # Without a skip
4
+ source = RxRuby::Observable.interval(0.1)
5
+ .window_with_time(0.5)
6
+ .take(3)
7
+
8
+ subscription = source.subscribe(
9
+ lambda {|child|
10
+ child.to_a.subscribe(
11
+ lambda {|x|
12
+ puts 'Child Next: ' + x.to_s
13
+ },
14
+ lambda {|err|
15
+ puts 'Child Error: ' + err.to_s
16
+ },
17
+ lambda {
18
+ puts 'Child Completed'
19
+ }
20
+ )
21
+ },
22
+ lambda {|err|
23
+ puts 'Error: ' + err.to_s
24
+ },
25
+ lambda {
26
+ puts 'Completed'
27
+ })
28
+
29
+ # => Child Next: [0, 1, 2, 3]
30
+ # => Child Completed
31
+ # => Completed
32
+ # => Child Next: [4, 5, 6, 7, 8]
33
+ # => Child Completed
34
+ # => Child Next: [9, 10, 11, 12, 13]
35
+ # => Child Completed
36
+
37
+ while Thread.list.size > 1
38
+ (Thread.list - [Thread.current]).each &:join
39
+ end
40
+
41
+ # Using a skip
42
+ source = RxRuby::Observable.interval(0.1)
43
+ .window_with_time(0.5, 0.1)
44
+ .take(3)
45
+
46
+ subscription = source.subscribe(
47
+ lambda {|child|
48
+
49
+ child.to_a.subscribe(
50
+ lambda {|x|
51
+ puts 'Child Next: ' + x.to_s
52
+ },
53
+ lambda {|err|
54
+ puts 'Child Error: ' + err.to_s
55
+ },
56
+ lambda {
57
+ puts 'Child Completed'
58
+ }
59
+ )
60
+ },
61
+ lambda {|err|
62
+ puts 'Error: ' + err.to_s
63
+ },
64
+ lambda {
65
+ puts 'Completed'
66
+ })
67
+
68
+ # => Completed
69
+ # => Child Next: [0, 1, 2, 3, 4]
70
+ # => Child Completed
71
+ # => Child Next: [1, 2, 3, 4, 5]
72
+ # => Child Completed
73
+ # => Child Next: [2, 3, 4, 5, 6]
74
+ # => Child Completed
75
+
76
+ while Thread.list.size > 1
77
+ (Thread.list - [Thread.current]).each &:join
78
+ end
data/examples/zip.rb ADDED
@@ -0,0 +1,27 @@
1
+ require 'rx_ruby'
2
+
3
+ # Using arguments
4
+ range = RxRuby::Observable.range(0, 5)
5
+
6
+ source = RxRuby::Observable.zip(
7
+ range,
8
+ range.skip(1),
9
+ range.skip(2)) {|s1, s2, s3|
10
+ s1.to_s + ':' + s2.to_s + ':' + s3.to_s
11
+ }
12
+
13
+ subscription = source.subscribe(
14
+ lambda {|x|
15
+ puts 'Next: ' + x.to_s
16
+ },
17
+ lambda {|err|
18
+ puts 'Error: ' + err.to_s
19
+ },
20
+ lambda {
21
+ puts 'Completed'
22
+ })
23
+
24
+ # => Next: 0:1:2
25
+ # => Next: 1:2:3
26
+ # => Next: 2:3:4
27
+ # => Completed
@@ -0,0 +1,25 @@
1
+ require 'rx_ruby'
2
+
3
+ range = RxRuby::Observable.range(0, 5)
4
+
5
+ source = RxRuby::Observable.zip(
6
+ range,
7
+ range.skip(1),
8
+ range.skip(2)
9
+ )
10
+
11
+ subscription = source.subscribe(
12
+ lambda {|x|
13
+ puts 'Next: ' + x.to_s
14
+ },
15
+ lambda {|err|
16
+ puts 'Error: ' + err.to_s
17
+ },
18
+ lambda {
19
+ puts 'Completed'
20
+ })
21
+
22
+ # => Next: [0, 1, 2]
23
+ # => Next: [1, 2, 3]
24
+ # => Next: [2, 3, 4]
25
+ # => Completed
@@ -0,0 +1,22 @@
1
+ module Enumerable
2
+ def subscribe(observer, scheduler = RxRuby::ImmediateScheduler.instance)
3
+ begin
4
+ self.each do |e|
5
+ scheduler.schedule lambda {
6
+ observer.on_next(e)
7
+ }
8
+ end
9
+ rescue => ex
10
+ observer.on_error(ex)
11
+ return
12
+ end
13
+
14
+ observer.on_completed
15
+ end
16
+
17
+ def to_observable(scheduler = RxRuby::ImmediateScheduler.instance)
18
+ RxRuby::AnonymousObservable.new do |observer|
19
+ self.subscribe(observer, scheduler)
20
+ end
21
+ end
22
+ end
data/lib/rx_ruby.rb ADDED
@@ -0,0 +1,27 @@
1
+ # Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
2
+
3
+ $:.unshift File.dirname(__FILE__) # For use/testing when no gem is installed
4
+
5
+ # Require all of the Ruby files in the given directory.
6
+ #
7
+ # path - The String relative path from here to the directory.
8
+ #
9
+ # Returns nothing.
10
+ def require_all(path)
11
+ glob = File.join(File.dirname(__FILE__), path, '*.rb')
12
+ Dir[glob].sort.each do |f|
13
+ require f
14
+ end
15
+ end
16
+
17
+ require_all 'rx_ruby/internal/'
18
+ require_all 'rx_ruby/concurrency/'
19
+ require_all 'rx_ruby/subscriptions/'
20
+ require_all 'rx_ruby/core/'
21
+ require_all 'rx_ruby/linq/'
22
+ require_all 'rx_ruby/linq/observable/'
23
+ require_all 'rx_ruby/operators/'
24
+ require_all 'rx_ruby/subjects/'
25
+ require_all 'rx_ruby/testing/'
26
+ require_all 'rx_ruby/joins/'
27
+ require_all 'rx_ruby/'
@@ -0,0 +1,57 @@
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
+ # Asynchronous lock.
7
+ class AsyncLock
8
+
9
+ def initialize
10
+ @queue = []
11
+ @is_acquired = false
12
+ @has_faulted = false
13
+ @gate = Mutex.new
14
+ end
15
+
16
+ def wait(&action)
17
+ @gate.synchronize do
18
+ @queue.push action unless @has_faulted
19
+
20
+ if @is_acquired or @has_faulted
21
+ return
22
+ else
23
+ @is_acquired = true
24
+ end
25
+ end
26
+
27
+ loop do
28
+ work = nil
29
+
30
+ @gate.synchronize do
31
+ work = @queue.shift
32
+
33
+ unless work
34
+ @is_acquired = false
35
+ return
36
+ end
37
+ end
38
+
39
+ begin
40
+ work.call
41
+ rescue
42
+ clear
43
+ raise
44
+ end
45
+ end
46
+ end
47
+
48
+ # Clears the work items in the queue and drops further work being queued.
49
+ def clear
50
+ @gate.synchronize do
51
+ @queue = []
52
+ @has_faulted = true
53
+ end
54
+ end
55
+
56
+ end
57
+ end
@@ -0,0 +1,75 @@
1
+ # Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
2
+
3
+ require 'singleton'
4
+ require 'thread'
5
+ require 'rx_ruby/internal/priority_queue'
6
+ require 'rx_ruby/concurrency/local_scheduler'
7
+ require 'rx_ruby/concurrency/scheduled_item'
8
+ require 'rx_ruby/subscriptions/subscription'
9
+
10
+ module RxRuby
11
+
12
+ # Represents an object that schedules units of work on the platform's default scheduler.
13
+ class CurrentThreadScheduler < RxRuby::LocalScheduler
14
+
15
+ include Singleton
16
+
17
+ @@thread_local_queue = nil
18
+
19
+ # Gets a value that indicates whether the caller must call a Schedule method.
20
+ def self.schedule_required?
21
+ @@thread_local_queue.nil?
22
+ end
23
+
24
+ # Schedules an action to be executed after dueTime.
25
+ def schedule_relative_with_state(state, due_time, action)
26
+ raise 'action cannot be nil' unless action
27
+
28
+ dt = self.now.to_i + Scheduler.normalize(due_time)
29
+ si = ScheduledItem.new self, state, dt, &action
30
+
31
+ local_queue = self.class.queue
32
+
33
+ unless local_queue
34
+ local_queue = PriorityQueue.new
35
+ local_queue.push si
36
+
37
+ self.class.queue = local_queue
38
+
39
+ begin
40
+ self.class.run_trampoline local_queue
41
+ ensure
42
+ self.class.queue = nil
43
+ end
44
+ else
45
+ local_queue.push si
46
+ end
47
+
48
+ Subscription.create { si.cancel }
49
+ end
50
+
51
+ private
52
+
53
+ class << self
54
+ def queue
55
+ @@thread_local_queue
56
+ end
57
+
58
+ def queue=(new_queue)
59
+ @@thread_local_queue = new_queue
60
+ end
61
+
62
+ def run_trampoline(queue)
63
+ while item = queue.shift
64
+ unless item.cancelled?
65
+ wait = item.due_time - Scheduler.now.to_i
66
+ sleep wait if wait > 0
67
+ item.invoke unless item.cancelled?
68
+ end
69
+ end
70
+ end
71
+
72
+ end
73
+
74
+ end
75
+ end