rx_ruby 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- 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
|