stud 0.0.21 → 0.0.22
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 +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:
|