stud 0.0.21 → 0.0.22
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/stud/interval.rb +80 -8
- data/lib/stud/task.rb +27 -3
- metadata +4 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a6052e9a657a08c734e6ca7326edc7e86e402305
|
4
|
+
data.tar.gz: 9c681e29d45145e0df76800b6821d198c3003c57
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3ac208ff1766b0f2827e8239e4739d344bbedff9dd6f9e6d84d4ffba3fd3314e7db6dffda9bea63ee3f61499d1dc1865058837762adb9ad29e9bcdbfb42878f9
|
7
|
+
data.tar.gz: 07308bf3b065d429e16802786e4f571321cb31735b784d207619410b63b8d58c0d41ff6d5ee83f327fe602605b74eeb27bcd4aead1cb9d3ab7b9e286f5463fdf
|
data/lib/stud/interval.rb
CHANGED
@@ -1,5 +1,8 @@
|
|
1
|
-
require "
|
1
|
+
require "thread"
|
2
|
+
|
2
3
|
module Stud
|
4
|
+
STUD_STOP_REQUESTED = :stud_stop_requested
|
5
|
+
|
3
6
|
# This implementation tries to keep clock more accurately.
|
4
7
|
# Prior implementations still permitted skew, where as this one
|
5
8
|
# will attempt to correct for skew.
|
@@ -9,30 +12,99 @@ module Stud
|
|
9
12
|
def self.interval(time, opts = {}, &block)
|
10
13
|
start = Time.now
|
11
14
|
while true
|
12
|
-
break if Task.interrupted?
|
13
15
|
if opts[:sleep_then_run]
|
14
16
|
start = sleep_for_interval(time, start)
|
17
|
+
break if stop?
|
15
18
|
block.call
|
16
19
|
else
|
17
20
|
block.call
|
18
21
|
start = sleep_for_interval(time, start)
|
22
|
+
break if stop?
|
19
23
|
end
|
20
24
|
end # loop forever
|
21
25
|
end # def interval
|
22
26
|
|
27
|
+
def interval(time, opts = {}, &block)
|
28
|
+
Stud.interval(time, opts, &block)
|
29
|
+
end # def interval
|
30
|
+
|
31
|
+
# stop! instructs interval to stop and exit its execution loop before going to
|
32
|
+
# sleep between block executions.
|
33
|
+
# NOW the tricky part is: this is typically an operation that will be called
|
34
|
+
# from another thread than the thread running the interval loop in which case
|
35
|
+
# the target parameter must be set to the Thread object which is running the
|
36
|
+
# interval loop.
|
37
|
+
# Note that the stop logic is compatible with Stud::Task so if interval is run
|
38
|
+
# inside a Stud::Task, calling Stud::Task#stop! will stop the interval the same
|
39
|
+
# way as calling stop! on the interval itself.
|
40
|
+
# @param target [Thread] the target thread to stop, defaut to Thread.current
|
41
|
+
def self.stop!(target = Thread.current)
|
42
|
+
# setting/getting threalocal var is thread safe in JRuby
|
43
|
+
target[STUD_STOP_REQUESTED] = true
|
44
|
+
target.wakeup
|
45
|
+
nil
|
46
|
+
end
|
47
|
+
|
48
|
+
# stop? returns true if stop! has been called
|
49
|
+
# @param target [Thread] the target thread to check for stop, defaut to Thread.current
|
50
|
+
# @return [Boolean] true if the stop! has been called
|
51
|
+
def self.stop?(target = Thread.current)
|
52
|
+
# setting/getting threalocal var is thread safe in JRuby
|
53
|
+
target[STUD_STOP_REQUESTED]
|
54
|
+
end
|
55
|
+
|
56
|
+
class << Stud
|
57
|
+
# also support Stud.interrupted? for backward compatibility.
|
58
|
+
alias_method :interrupted?, :stop?
|
59
|
+
end
|
60
|
+
|
61
|
+
# stoppable_sleep will try to sleep for the given duration seconds (which may be any number,
|
62
|
+
# including a Float with fractional seconds). an optional stop_condition_block can be supplied
|
63
|
+
# to verify for sleep interruption if the block returns a truthy value. if not block is supplied
|
64
|
+
# it will check for the Stud.stop? condition. this check will be performed at 1s interval
|
65
|
+
# by default or you can supply a different stop_condition_interval.
|
66
|
+
#
|
67
|
+
# note that to achieve this, stoppable_sleep will actually perform a series of incremental sleeps
|
68
|
+
# but will try accurately spend the requested duration period in the overall stoppable_sleep method call.
|
69
|
+
# in other words this means that the duration supplied will be accurate for the time spent in
|
70
|
+
# the stoppable_sleep method not the actual total time spent in the underlying multiple sleep calls.
|
71
|
+
#
|
72
|
+
# @param duration [Numeric] sleep time in (fractional) seconds
|
73
|
+
# @param stop_condition_interval [Numeric] optional interval in (fractional) seconds to perform the sleep interruption verification, default is 1s
|
74
|
+
# @param stop_condition_block [Proc] optional sleep interruption code block that must evaluate to a truthy value, default is to use Stud.stop?
|
75
|
+
# @return [Numeric] the actual duration in (fractional) seconds spent in stoppable_sleep
|
76
|
+
def self.stoppable_sleep(duration, stop_condition_interval = 1.0, &stop_condition_block)
|
77
|
+
sleep_start = Time.now
|
78
|
+
|
79
|
+
# default to using Stud.stop? as the condition block
|
80
|
+
stop_condition_block ||= lambda { stop? }
|
81
|
+
|
82
|
+
while (remaining_duration = (duration - (Time.now - sleep_start))) >= stop_condition_interval
|
83
|
+
# sleep X if there is more than X remaining to sleep in relation to the loop start time
|
84
|
+
sleep(stop_condition_interval)
|
85
|
+
|
86
|
+
return(Time.now - sleep_start) if stop_condition_block.call
|
87
|
+
end
|
88
|
+
|
89
|
+
# here we know we have less than 1s reminding to sleep,
|
90
|
+
sleep(remaining_duration) if remaining_duration > 0.0
|
91
|
+
|
92
|
+
Time.now - sleep_start
|
93
|
+
end
|
94
|
+
|
95
|
+
private
|
96
|
+
|
23
97
|
def self.sleep_for_interval(time, start)
|
24
98
|
duration = Time.now - start
|
25
|
-
|
99
|
+
|
100
|
+
# sleep only if the duration was less than the time interval
|
26
101
|
if duration < time
|
27
|
-
|
102
|
+
stoppable_sleep(time - duration)
|
28
103
|
start += time
|
29
104
|
else
|
30
|
-
#
|
105
|
+
# duration exceeded interval time, reset the clock and do not sleep.
|
31
106
|
start = Time.now
|
32
107
|
end
|
33
108
|
end
|
34
109
|
|
35
|
-
def interval(time, opts = {}, &block)
|
36
|
-
return Stud.interval(time, opts, &block)
|
37
|
-
end # def interval
|
38
110
|
end # module Stud
|
data/lib/stud/task.rb
CHANGED
@@ -1,7 +1,19 @@
|
|
1
1
|
require "thread"
|
2
|
+
require "stud/interval"
|
2
3
|
|
3
4
|
module Stud
|
5
|
+
|
6
|
+
# A Task spawns a thread to execute the given block. execution completion and result retrieval is
|
7
|
+
# done using the Task#wait method. A Task is run once and the thread exists upon block completion.
|
8
|
+
# A task and its underlying thread are not reusable.
|
9
|
+
#
|
10
|
+
# Task does not provide a mean to force-interrupt a running task, it only provides the #stop!
|
11
|
+
# method to signal the task for a stop request. The task or code block can use the #stop? method
|
12
|
+
# to check for a stop request. Note that the #stop! and #stop? methods are thread safe.
|
4
13
|
class Task
|
14
|
+
# provide access to the underlying thread if ever needed.
|
15
|
+
attr_reader :thread
|
16
|
+
|
5
17
|
def initialize(*args, &block)
|
6
18
|
# A queue to receive the result of the block
|
7
19
|
# TODO(sissel): Don't use a queue, just store it in an instance variable.
|
@@ -17,6 +29,10 @@ module Stud
|
|
17
29
|
end # thread
|
18
30
|
end # def initialize
|
19
31
|
|
32
|
+
# wait waits for the task thread to complete and return the block return value
|
33
|
+
# if the block raises an exception, this exception is propagated in this
|
34
|
+
# wait method.
|
35
|
+
# @return [Object, Exception] block return value
|
20
36
|
def wait
|
21
37
|
@thread.join
|
22
38
|
reason, result = @queue.pop
|
@@ -29,12 +45,20 @@ module Stud
|
|
29
45
|
end
|
30
46
|
end # def wait
|
31
47
|
|
48
|
+
# stop! requests the task to stop. the Thread#wakeup method is also
|
49
|
+
# called so that a sleeping task is waked up and has a chance to verify
|
50
|
+
# the stop request using the #stop? method. also see Stud.stop!
|
32
51
|
def stop!
|
33
|
-
|
52
|
+
Stud.stop!(@thread)
|
34
53
|
end
|
35
54
|
|
36
|
-
|
37
|
-
|
55
|
+
# stop? returns true if this task stop! has been called
|
56
|
+
# See Stud.stop?
|
57
|
+
# @return [Boolean] true if the stop! has been called
|
58
|
+
def stop?
|
59
|
+
Stud.stop?(@thread)
|
38
60
|
end
|
61
|
+
alias_method :interrupted?, :stop?
|
62
|
+
|
39
63
|
end # class Task
|
40
64
|
end # module Stud
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: stud
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.22
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jordan Sissel
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-
|
11
|
+
date: 2015-09-17 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rspec
|
@@ -77,8 +77,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
77
77
|
version: '0'
|
78
78
|
requirements: []
|
79
79
|
rubyforge_project:
|
80
|
-
rubygems_version: 2.4.
|
80
|
+
rubygems_version: 2.4.6
|
81
81
|
signing_key:
|
82
82
|
specification_version: 4
|
83
83
|
summary: stud - common code techniques
|
84
84
|
test_files: []
|
85
|
+
has_rdoc:
|