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,51 @@
|
|
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/concurrency/local_scheduler'
|
6
|
+
require 'rx_ruby/concurrency/periodic_scheduler'
|
7
|
+
require 'rx_ruby/subscriptions/subscription'
|
8
|
+
require 'rx_ruby/subscriptions/single_assignment_subscription'
|
9
|
+
require 'rx_ruby/subscriptions/composite_subscription'
|
10
|
+
|
11
|
+
module RxRuby
|
12
|
+
|
13
|
+
# Represents an object that schedules units of work on the platform's default scheduler.
|
14
|
+
class DefaultScheduler < RxRuby::LocalScheduler
|
15
|
+
|
16
|
+
include Singleton
|
17
|
+
include RxRuby::PeriodicScheduler
|
18
|
+
|
19
|
+
# Schedules an action to be executed.
|
20
|
+
def schedule_with_state(state, action)
|
21
|
+
raise 'action cannot be nil' unless action
|
22
|
+
|
23
|
+
d = SingleAssignmentSubscription.new
|
24
|
+
|
25
|
+
t = Thread.new do
|
26
|
+
d.subscription = action.call self, state unless d.unsubscribed?
|
27
|
+
end
|
28
|
+
|
29
|
+
CompositeSubscription.new [d, Subscription.create { t.exit }]
|
30
|
+
end
|
31
|
+
|
32
|
+
# Schedules an action to be executed after dueTime
|
33
|
+
def schedule_relative_with_state(state, due_time, action)
|
34
|
+
raise 'action cannot be nil' unless action
|
35
|
+
|
36
|
+
dt = Scheduler.normalize due_time
|
37
|
+
return self.schedule_with_state state, action if dt == 0
|
38
|
+
|
39
|
+
d = SingleAssignmentSubscription.new
|
40
|
+
|
41
|
+
t = Thread.new do
|
42
|
+
sleep dt
|
43
|
+
Thread.new {
|
44
|
+
d.subscription = action.call self, state unless d.unsubscribed?
|
45
|
+
}
|
46
|
+
end
|
47
|
+
|
48
|
+
CompositeSubscription.new [d, Subscription.create { t.exit }]
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,16 @@
|
|
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/virtual_time_scheduler'
|
4
|
+
require 'rx_ruby/internal/priority_queue'
|
5
|
+
|
6
|
+
module RxRuby
|
7
|
+
|
8
|
+
# Provides a virtual time scheduler that uses Time for absolute time and Number for relative time.
|
9
|
+
class HistoricalScheduler < VirtualTimeScheduler
|
10
|
+
|
11
|
+
def initialize(clock = Time.at(0))
|
12
|
+
super
|
13
|
+
@clock = clock
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,68 @@
|
|
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/concurrency/local_scheduler'
|
6
|
+
require 'rx_ruby/subscriptions/single_assignment_subscription'
|
7
|
+
|
8
|
+
module RxRuby
|
9
|
+
|
10
|
+
# Represents an object that schedules units of work to run immediately on the current thread.
|
11
|
+
class ImmediateScheduler < LocalScheduler
|
12
|
+
|
13
|
+
include Singleton
|
14
|
+
|
15
|
+
# Schedules an action to be executed.
|
16
|
+
def schedule_with_state(state, action)
|
17
|
+
raise ArgumentError.new 'action cannot be nil' unless action
|
18
|
+
action.call AsyncLockScheduler.new, state
|
19
|
+
end
|
20
|
+
|
21
|
+
def schedule_relative_with_state(state, due_time, action)
|
22
|
+
raise ArgumentError.new 'action cannot be nil' unless action
|
23
|
+
|
24
|
+
dt = RxRuby::Scheduler.normalize due_time
|
25
|
+
sleep dt if dt > 0
|
26
|
+
action.call AsyncLockScheduler.new, state
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
class AsyncLockScheduler < LocalScheduler
|
32
|
+
|
33
|
+
def initialize
|
34
|
+
@gate = nil
|
35
|
+
end
|
36
|
+
|
37
|
+
def schedule_with_state(state, action)
|
38
|
+
m = SingleAssignmentSubscription.new
|
39
|
+
|
40
|
+
@gate = AsyncLock.new if @gate.nil?
|
41
|
+
|
42
|
+
@gate.wait do
|
43
|
+
m.subscription = action.call self, state unless m.unsubscribed?
|
44
|
+
end
|
45
|
+
|
46
|
+
m
|
47
|
+
end
|
48
|
+
|
49
|
+
def schedule_relative_with_state(state, due_time, action)
|
50
|
+
return self.schedule_with_state state, action if due_time <= 0
|
51
|
+
|
52
|
+
m = SingleAssignmentSubscription.new
|
53
|
+
|
54
|
+
timer = Time.new
|
55
|
+
|
56
|
+
@gate = AsyncLock.new if @gate.nil?
|
57
|
+
|
58
|
+
@gate.wait do
|
59
|
+
sleep_time = Time.new - timer
|
60
|
+
sleep sleep_time if sleep_time > 0
|
61
|
+
m.subscription = action.call self, state unless m.unsubscribed?
|
62
|
+
end
|
63
|
+
|
64
|
+
m
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
@@ -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 'rx_ruby/concurrency/scheduler'
|
4
|
+
|
5
|
+
module RxRuby
|
6
|
+
# Abstract base class for machine-local schedulers, using the local system clock for time-based operations.
|
7
|
+
class LocalScheduler
|
8
|
+
|
9
|
+
include Scheduler
|
10
|
+
|
11
|
+
# Gets the scheduler's notion of current time.
|
12
|
+
def now
|
13
|
+
Time.now
|
14
|
+
end
|
15
|
+
|
16
|
+
# Schedules an action to be executed.
|
17
|
+
def schedule_with_state(state, action)
|
18
|
+
raise 'action cannot be nil' unless action
|
19
|
+
|
20
|
+
schedule_relative_with_state(state, 0, action)
|
21
|
+
end
|
22
|
+
|
23
|
+
# Schedules an action to be executed at dueTime.
|
24
|
+
def schedule_absolute_with_state(state, due_time, action)
|
25
|
+
raise 'action cannot be nil' unless action
|
26
|
+
|
27
|
+
schedule_relative_with_state(state, (due_time - self.now), action)
|
28
|
+
end
|
29
|
+
|
30
|
+
def schedule_relative_with_state(state, due_time, action)
|
31
|
+
raise ArgumentError.new 'action cannot be nil' unless action
|
32
|
+
|
33
|
+
dt = RxRuby::Scheduler.normalize due_time
|
34
|
+
sleep dt if dt > 0
|
35
|
+
action.call(self, state)
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,74 @@
|
|
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
|
+
|
5
|
+
# Provides periodic scheduling capabilities
|
6
|
+
module PeriodicScheduler
|
7
|
+
|
8
|
+
# Schedules a periodic piece of work by dynamically discovering the scheduler's capabilities.
|
9
|
+
def schedule_periodic(period, action)
|
10
|
+
raise 'action cannot be nil' unless action
|
11
|
+
raise 'period cannot be less than zero' if period < 0
|
12
|
+
|
13
|
+
self.schedule_periodic_with_state(action, period, lambda {|a|
|
14
|
+
a.call
|
15
|
+
return a
|
16
|
+
})
|
17
|
+
end
|
18
|
+
|
19
|
+
# Schedules a periodic piece of work
|
20
|
+
def schedule_periodic_with_state(state, due_time, action)
|
21
|
+
raise 'action cannot be nil' unless action
|
22
|
+
raise 'due_time cannot be less than zero' if due_time < 0
|
23
|
+
|
24
|
+
state1 = state
|
25
|
+
gate = Mutex.new
|
26
|
+
|
27
|
+
PeriodicTimer.new due_time do
|
28
|
+
gate.synchronize do
|
29
|
+
state1 = action.call state1
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
# Internal timer
|
37
|
+
class PeriodicTimer
|
38
|
+
def initialize(seconds, &action)
|
39
|
+
@seconds = seconds
|
40
|
+
@unsubscribed = false
|
41
|
+
@gate = Mutex.new
|
42
|
+
|
43
|
+
self.run_loop(&action)
|
44
|
+
end
|
45
|
+
|
46
|
+
def unsubscribe
|
47
|
+
@gate.synchronize do
|
48
|
+
@unsubscribed = true unless @unsubscribed
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def time_block
|
53
|
+
start_time = Time.new
|
54
|
+
yield
|
55
|
+
Time.new - start_time
|
56
|
+
end
|
57
|
+
|
58
|
+
def run_loop
|
59
|
+
Thread.new do
|
60
|
+
should_run = true
|
61
|
+
|
62
|
+
elapsed = 0
|
63
|
+
while should_run
|
64
|
+
sleep @seconds - elapsed
|
65
|
+
elapsed = time_block { yield }
|
66
|
+
@gate.synchronize do
|
67
|
+
should_run = !@unsubscribed
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,42 @@
|
|
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/single_assignment_subscription'
|
4
|
+
|
5
|
+
module RxRuby
|
6
|
+
|
7
|
+
# Represents a scheduled work item based on the materialization of an scheduler.schedule method call.
|
8
|
+
class ScheduledItem
|
9
|
+
|
10
|
+
include Comparable
|
11
|
+
|
12
|
+
attr_reader :due_time
|
13
|
+
|
14
|
+
def initialize(scheduler, state, due_time, &action)
|
15
|
+
@scheduler = scheduler
|
16
|
+
@state = state
|
17
|
+
@action = action
|
18
|
+
@due_time = due_time
|
19
|
+
@subscription = SingleAssignmentSubscription.new
|
20
|
+
end
|
21
|
+
|
22
|
+
# Gets whether the work item has received a cancellation request.
|
23
|
+
def cancelled?
|
24
|
+
@subscription.unsubscribed?
|
25
|
+
end
|
26
|
+
|
27
|
+
# Invokes the work item.
|
28
|
+
def invoke
|
29
|
+
@subscription.subscription = @action.call @scheduler, @state unless @subscription.unsubscribed?
|
30
|
+
end
|
31
|
+
|
32
|
+
def <=>(other)
|
33
|
+
return @due_time <=> other.due_time
|
34
|
+
end
|
35
|
+
|
36
|
+
# Cancels the work item by disposing the resource returned by invoke_core as soon as possible.
|
37
|
+
def cancel
|
38
|
+
@subscription.unsubscribe
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,150 @@
|
|
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
|
+
# Module for scheduling actions
|
8
|
+
module Scheduler
|
9
|
+
|
10
|
+
# Gets the current time according to the local machine's system clock.
|
11
|
+
def self.now
|
12
|
+
Time.now
|
13
|
+
end
|
14
|
+
|
15
|
+
# Schedules an action to be executed.
|
16
|
+
def schedule(action)
|
17
|
+
raise 'action cannot be nil' unless action
|
18
|
+
schedule_with_state(action, method(:invoke))
|
19
|
+
end
|
20
|
+
|
21
|
+
# Schedules an action to be executed after the specified relative due time.
|
22
|
+
def schedule_relative(due_time, action)
|
23
|
+
raise 'action cannot be nil' unless action
|
24
|
+
schedule_relative_with_state(action, due_time, method(:invoke))
|
25
|
+
end
|
26
|
+
|
27
|
+
# Schedules an action to be executed at the specified absolute due time.
|
28
|
+
def schedule_absolute(due_time, action)
|
29
|
+
raise 'action cannot be nil' unless action
|
30
|
+
schedule_absolute_with_state(action, due_time, method(:invoke))
|
31
|
+
end
|
32
|
+
|
33
|
+
# Schedules an action to be executed recursively.
|
34
|
+
def schedule_recursive(action)
|
35
|
+
raise 'action cannot be nil' unless action
|
36
|
+
schedule_recursive_with_state(action, lambda {|_action, _self| _action.call(lambda { _self.call(_action) }) })
|
37
|
+
end
|
38
|
+
|
39
|
+
# Schedules an action to be executed recursively.
|
40
|
+
def schedule_recursive_with_state(state, action)
|
41
|
+
raise 'action cannot be nil' unless action
|
42
|
+
schedule_with_state({ :state => state, :action => action}, method(:invoke_recursive))
|
43
|
+
end
|
44
|
+
|
45
|
+
# Schedules an action to be executed recursively after a specified relative due time.
|
46
|
+
def schedule_recursive_relative(due_time, action)
|
47
|
+
raise 'action cannot be nil' unless action
|
48
|
+
schedule_recursive_relative_with_state(action, due_time, lambda {|_action, _self| _action.call(lambda {|dt| _self.call(_action, dt) }) })
|
49
|
+
end
|
50
|
+
|
51
|
+
# Schedules an action to be executed recursively after a specified relative due time.
|
52
|
+
def schedule_recursive_relative_with_state(state, due_time, action)
|
53
|
+
raise 'action cannot be nil' unless action
|
54
|
+
schedule_relative_with_state(
|
55
|
+
{ :state => state, :action => action},
|
56
|
+
due_time,
|
57
|
+
lambda { |sched, pair| invoke_recursive_time(sched, pair, 'schedule_relative_with_state') }
|
58
|
+
)
|
59
|
+
end
|
60
|
+
|
61
|
+
# Schedules an action to be executed recursively after a specified absolute due time.
|
62
|
+
def schedule_recursive_absolute(due_time, action)
|
63
|
+
raise 'action cannot be nil' unless action
|
64
|
+
schedule_recursive_absolute_with_state(action, due_time, lambda {|_action, _self| _action.call(lambda {|dt| _self.call(_action, dt) }) })
|
65
|
+
end
|
66
|
+
|
67
|
+
# Schedules an action to be executed recursively after a specified absolute due time.
|
68
|
+
def schedule_recursive_absolute_with_state(state, due_time, action)
|
69
|
+
raise 'action cannot be nil' unless action
|
70
|
+
schedule_absolute_with_state(
|
71
|
+
{ :state => state, :action => action},
|
72
|
+
due_time,
|
73
|
+
lambda { |sched, pair| invoke_recursive_time(sched, pair, 'schedule_absolute_with_state') }
|
74
|
+
)
|
75
|
+
end
|
76
|
+
|
77
|
+
# Normalizes the specified TimeSpan value to a positive value.
|
78
|
+
def self.normalize(time_span)
|
79
|
+
time_span < 0 ? 0 : time_span
|
80
|
+
end
|
81
|
+
|
82
|
+
private
|
83
|
+
|
84
|
+
def invoke(scheduler, action)
|
85
|
+
action.call()
|
86
|
+
Subscription.empty
|
87
|
+
end
|
88
|
+
|
89
|
+
def invoke_recursive(scheduler, pair)
|
90
|
+
group = CompositeSubscription.new
|
91
|
+
gate = Mutex.new
|
92
|
+
state = pair[:state]
|
93
|
+
action = pair[:action]
|
94
|
+
|
95
|
+
recursive_action = lambda {|state1|
|
96
|
+
action.call(state1, lambda {|state2|
|
97
|
+
is_added = false
|
98
|
+
is_done = false
|
99
|
+
d = nil
|
100
|
+
d = scheduler.schedule_with_state(state2, lambda do |_, state3|
|
101
|
+
gate.synchronize do
|
102
|
+
if is_added
|
103
|
+
group.delete(d)
|
104
|
+
else
|
105
|
+
is_done = true
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
recursive_action.call(state3)
|
110
|
+
Subscription.empty
|
111
|
+
end)
|
112
|
+
|
113
|
+
gate.synchronize do
|
114
|
+
unless is_done
|
115
|
+
group.push(d)
|
116
|
+
is_added = true
|
117
|
+
end
|
118
|
+
end
|
119
|
+
})
|
120
|
+
}
|
121
|
+
|
122
|
+
recursive_action.call(state)
|
123
|
+
group
|
124
|
+
end
|
125
|
+
|
126
|
+
def invoke_recursive_time(scheduler, pair, method)
|
127
|
+
group = CompositeSubscription.new
|
128
|
+
gate = Mutex.new
|
129
|
+
state = pair[:state]
|
130
|
+
action = pair[:action]
|
131
|
+
|
132
|
+
recursive_action = ->(state1) do
|
133
|
+
internal_action = ->(state2, due_time1) do
|
134
|
+
|
135
|
+
d = scheduler.send(method, state2, due_time1, lambda do |_, state3|
|
136
|
+
gate.synchronize do
|
137
|
+
group.delete(d)
|
138
|
+
end
|
139
|
+
recursive_action.call(state3)
|
140
|
+
Subscription.empty
|
141
|
+
end)
|
142
|
+
end
|
143
|
+
action.call(state1, internal_action)
|
144
|
+
end
|
145
|
+
|
146
|
+
recursive_action.call(state)
|
147
|
+
group
|
148
|
+
end
|
149
|
+
end
|
150
|
+
end
|