ActionTimer 0.0.1 → 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.
- data/CHANGELOG +7 -0
- data/README.rdoc +46 -0
- data/actiontimer.gemspec +13 -1
- data/lib/actiontimer/Timer.rb +48 -11
- data/tests/run_tests.rb +129 -0
- metadata +19 -13
- data/ActionTimer-0.0.1.gem +0 -0
- data/README +0 -48
- data/README~ +0 -48
- data/lib/actiontimer/Action.rb~ +0 -69
- data/lib/actiontimer/Timer.rb~ +0 -140
data/CHANGELOG
ADDED
data/README.rdoc
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
== ActionTimer: Simple timing for a complex world
|
2
|
+
|
3
|
+
ActionTimer is a helper for timed events. It allows for single and recurring actions to be executed in an efficient manner. It makes use of a single thread to keep time on registered actions and uses an ActionPool to execute actions. Simple and effective.
|
4
|
+
|
5
|
+
==== useful links
|
6
|
+
* {trac site}[http://dev.modspox.com/trac/actiontimer]
|
7
|
+
* {RDocs}[http://dev.modspox.com/~sine/ActionTimer]
|
8
|
+
|
9
|
+
=== install (easy):
|
10
|
+
|
11
|
+
gem install --include-dependencies ActionTimer
|
12
|
+
|
13
|
+
=== install (less easy):
|
14
|
+
|
15
|
+
git clone http://github.com/spox/actiontimer.git
|
16
|
+
cd actiontimer
|
17
|
+
gem build actiontimer.gemspec
|
18
|
+
gem install ActionTimer-x.x.x.gem
|
19
|
+
|
20
|
+
=== Simple example of using the timer:
|
21
|
+
|
22
|
+
require 'actiontimer'
|
23
|
+
|
24
|
+
timer = ActionTimer::Timer.new
|
25
|
+
|
26
|
+
timer.add(10){puts "#{Time.now}: This is timed every 10 seconds"}
|
27
|
+
timer.add(15){puts "#{Time.now}: This is timed every 15 seconds"}
|
28
|
+
loop do
|
29
|
+
puts "#{Time.now}: Main loop that sleeps for 5 seconds"
|
30
|
+
sleep(5)
|
31
|
+
end
|
32
|
+
|
33
|
+
==== Output:
|
34
|
+
|
35
|
+
2009-04-13 17:41:39 -0700: Main loop that sleeps for 5 seconds
|
36
|
+
2009-04-13 17:41:44 -0700: Main loop that sleeps for 5 seconds
|
37
|
+
2009-04-13 17:41:49 -0700: This is timed every 10 seconds
|
38
|
+
2009-04-13 17:41:49 -0700: Main loop that sleeps for 5 seconds
|
39
|
+
2009-04-13 17:41:54 -0700: This is timed every 15 seconds
|
40
|
+
2009-04-13 17:41:54 -0700: Main loop that sleeps for 5 seconds
|
41
|
+
2009-04-13 17:41:59 -0700: This is timed every 10 seconds
|
42
|
+
2009-04-13 17:41:59 -0700: Main loop that sleeps for 5 seconds
|
43
|
+
2009-04-13 17:42:04 -0700: Main loop that sleeps for 5 seconds
|
44
|
+
2009-04-13 17:42:09 -0700: This is timed every 10 seconds
|
45
|
+
2009-04-13 17:42:09 -0700: This is timed every 15 seconds
|
46
|
+
2009-04-13 17:42:09 -0700: Main loop that sleeps for 5 seconds
|
data/actiontimer.gemspec
CHANGED
@@ -2,12 +2,24 @@ spec = Gem::Specification.new do |s|
|
|
2
2
|
s.name = 'ActionTimer'
|
3
3
|
s.author = %q(spox)
|
4
4
|
s.email = %q(spox@modspox.com)
|
5
|
-
s.version = '0.0.
|
5
|
+
s.version = '0.0.2'
|
6
6
|
s.summary = %q(Simple timer for a complex world)
|
7
7
|
s.platform = Gem::Platform::RUBY
|
8
8
|
s.has_rdoc = true
|
9
|
+
s.rdoc_options = %w(--title ActionTimer --main README.rdoc --line-numbers --inline-source)
|
10
|
+
s.extra_rdoc_files = %w(README.rdoc LICENSE CHANGELOG)
|
9
11
|
s.files = Dir['**/*']
|
10
12
|
s.require_paths = %w(lib)
|
11
13
|
s.add_dependency 'ActionPool'
|
12
14
|
s.required_ruby_version = '>= 1.8.6'
|
15
|
+
s.homepage = %q(http://dev.modspox.com/trac/ActionTimer)
|
16
|
+
description = []
|
17
|
+
File.open("README.rdoc") do |file|
|
18
|
+
file.each do |line|
|
19
|
+
line.chomp!
|
20
|
+
break if line.empty?
|
21
|
+
description << "#{line.gsub(/\[\d\]/, '')}"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
s.description = description[1..-1].join(" ")
|
13
25
|
end
|
data/lib/actiontimer/Timer.rb
CHANGED
@@ -5,20 +5,29 @@ module ActionTimer
|
|
5
5
|
class Timer
|
6
6
|
# pool:: ActionPool for processing actions
|
7
7
|
# Creates a new timer
|
8
|
-
|
8
|
+
# Argument hash: {:pool, :logger, :auto_start}
|
9
|
+
def initialize(args={}, extra=nil)
|
10
|
+
auto_start = true
|
11
|
+
if(args.is_a?(Hash))
|
12
|
+
@pool = args[:pool] ? args[:pool] : ActionPool::Pool.new
|
13
|
+
@logger = LogHelper.new(args[:logger])
|
14
|
+
auto_start = args.has_key?(:auto_start) ? args[:auto_start] : true
|
15
|
+
else
|
16
|
+
@pool = args.is_a?(ActionPool::Pool) ? args : ActionPool::Pool.new
|
17
|
+
@logger = LogHelper.new(extra)
|
18
|
+
end
|
9
19
|
@actions = []
|
10
20
|
@new_actions = []
|
11
21
|
@timer_thread = nil
|
12
22
|
@stop_timer = false
|
13
23
|
@add_lock = Mutex.new
|
14
24
|
@awake_lock = Mutex.new
|
15
|
-
|
16
|
-
@logger = LogHelper.new(logger)
|
17
|
-
start
|
25
|
+
start if auto_start
|
18
26
|
end
|
19
27
|
|
20
28
|
# Forcibly wakes the timer early
|
21
29
|
def wakeup
|
30
|
+
raise NotRunning.new unless running?
|
22
31
|
return unless @awake_lock.try_lock
|
23
32
|
@timer_thread.wakeup if @timer_thread.status == 'sleep'
|
24
33
|
@awake_lock.unlock
|
@@ -34,7 +43,7 @@ module ActionTimer
|
|
34
43
|
action = Action.new(self, period, once, data, &func)
|
35
44
|
action.owner = owner unless owner.nil?
|
36
45
|
@add_lock.synchronize{ @new_actions << action }
|
37
|
-
wakeup
|
46
|
+
wakeup if running?
|
38
47
|
return action
|
39
48
|
end
|
40
49
|
|
@@ -46,7 +55,7 @@ module ActionTimer
|
|
46
55
|
raise InvalidType.new(ActionTimer::Action, action.class) unless action.is_a?(Action)
|
47
56
|
end
|
48
57
|
@add_lock.synchronize{ @new_actions = @new_actions + actions }
|
49
|
-
wakeup
|
58
|
+
wakeup if running?
|
50
59
|
end
|
51
60
|
|
52
61
|
# action:: Action to remove from timer
|
@@ -54,12 +63,13 @@ module ActionTimer
|
|
54
63
|
def remove(action)
|
55
64
|
raise InvalidType.new(ActionTimer::Action, action.class) unless action.is_a?(Action)
|
56
65
|
@actions.delete(action)
|
57
|
-
wakeup
|
66
|
+
wakeup if running?
|
58
67
|
end
|
59
68
|
|
60
69
|
# Start the timer
|
61
70
|
def start
|
62
71
|
raise AlreadyRunning.new unless @timer_thread.nil?
|
72
|
+
@stop_timer = false
|
63
73
|
@timer_thread = Thread.new do
|
64
74
|
begin
|
65
75
|
until @stop_timer do
|
@@ -75,16 +85,33 @@ module ActionTimer
|
|
75
85
|
add_waiting_actions
|
76
86
|
end
|
77
87
|
rescue Object => boom
|
88
|
+
@timer_thread = nil
|
89
|
+
clean_actions
|
78
90
|
@logger.fatal("Timer encountered an unexpected error: #{boom}\n#{boom.backtrace.join("\n")}")
|
79
91
|
end
|
80
92
|
end
|
81
93
|
end
|
82
94
|
|
83
|
-
#
|
95
|
+
# Pause the timer in its current state.
|
96
|
+
def pause
|
97
|
+
@stop_timer = true
|
98
|
+
if(running?)
|
99
|
+
wakeup
|
100
|
+
@timer_thread.join
|
101
|
+
end
|
102
|
+
@timer_thread = nil
|
103
|
+
end
|
104
|
+
|
105
|
+
# Stop the timer. Unlike pause, this will completely
|
106
|
+
# stop the timer and remove all actions from the timer
|
84
107
|
def stop
|
85
108
|
@stop_timer = true
|
86
|
-
|
87
|
-
|
109
|
+
if(running?)
|
110
|
+
wakeup
|
111
|
+
clean_actions
|
112
|
+
@timer_thread.join
|
113
|
+
end
|
114
|
+
@timer_thread = nil
|
88
115
|
end
|
89
116
|
|
90
117
|
# owner:: owner actions to remove
|
@@ -100,6 +127,11 @@ module ActionTimer
|
|
100
127
|
wakeup
|
101
128
|
end
|
102
129
|
|
130
|
+
# Is timer currently running?
|
131
|
+
def running?
|
132
|
+
return !@timer_thread.nil?
|
133
|
+
end
|
134
|
+
|
103
135
|
private
|
104
136
|
|
105
137
|
def get_min_sleep
|
@@ -122,7 +154,7 @@ module ActionTimer
|
|
122
154
|
@actions.each do |action|
|
123
155
|
action.tick(time_passed)
|
124
156
|
if(action.due?)
|
125
|
-
|
157
|
+
@actions.delete(action) if action.is_complete?
|
126
158
|
action = action.schedule
|
127
159
|
@pool.process do
|
128
160
|
begin
|
@@ -135,5 +167,10 @@ module ActionTimer
|
|
135
167
|
end
|
136
168
|
end
|
137
169
|
|
170
|
+
def clean_actions
|
171
|
+
@actions.clear
|
172
|
+
@new_actions.clear
|
173
|
+
end
|
174
|
+
|
138
175
|
end
|
139
176
|
end
|
data/tests/run_tests.rb
ADDED
@@ -0,0 +1,129 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
require 'actiontimer'
|
3
|
+
|
4
|
+
class TimerTests < Test::Unit::TestCase
|
5
|
+
def setup
|
6
|
+
@timer = ActionTimer::Timer.new
|
7
|
+
end
|
8
|
+
|
9
|
+
# Simple test of basic repetitive action
|
10
|
+
def test_basic
|
11
|
+
result = 0
|
12
|
+
@timer.add(2){ result += 1 }
|
13
|
+
sleep(5)
|
14
|
+
assert_equal(2, result)
|
15
|
+
end
|
16
|
+
|
17
|
+
# Check the the running? method properly reports
|
18
|
+
def test_running
|
19
|
+
@timer.add(1){ 1 + 1}
|
20
|
+
assert(@timer.running?)
|
21
|
+
@timer.pause
|
22
|
+
assert(!@timer.running?)
|
23
|
+
@timer.start
|
24
|
+
assert(@timer.running?)
|
25
|
+
@timer.stop
|
26
|
+
assert(!@timer.running?)
|
27
|
+
end
|
28
|
+
|
29
|
+
# Check that a single iterative action is only
|
30
|
+
# completed once
|
31
|
+
def test_once
|
32
|
+
result = 0
|
33
|
+
@timer.add(1, true){ result += 1 }
|
34
|
+
sleep(3)
|
35
|
+
assert_equal(1, result)
|
36
|
+
end
|
37
|
+
|
38
|
+
# Check that timer can be paused and restarted
|
39
|
+
# without registered actions being effected
|
40
|
+
def test_pause
|
41
|
+
result = 0
|
42
|
+
@timer.add(1){ result += 1 }
|
43
|
+
sleep(3.1)
|
44
|
+
@timer.pause
|
45
|
+
sleep(2)
|
46
|
+
@timer.start
|
47
|
+
sleep(2.1)
|
48
|
+
assert_equal(5, result)
|
49
|
+
end
|
50
|
+
|
51
|
+
# Check that data can be passed to the block
|
52
|
+
# properly when created
|
53
|
+
def test_data
|
54
|
+
result = 0
|
55
|
+
@timer.add(1, true, 3){|a| result = a}
|
56
|
+
sleep(2)
|
57
|
+
assert_equal(3, result)
|
58
|
+
end
|
59
|
+
|
60
|
+
# Check that the timer's auto starting mechanism
|
61
|
+
# can be disabled
|
62
|
+
def test_auto_start
|
63
|
+
timer = ActionTimer::Timer.new(:auto_start => false)
|
64
|
+
timer.add(1){ 1+1 }
|
65
|
+
assert(!timer.running?)
|
66
|
+
timer.start
|
67
|
+
assert(timer.running?)
|
68
|
+
end
|
69
|
+
|
70
|
+
# Check that the actions can be cleared out of the
|
71
|
+
# timer and the timer is still left in a "running"
|
72
|
+
# state.
|
73
|
+
def test_clear
|
74
|
+
result = 0
|
75
|
+
@timer.add(1){ result += 1 }
|
76
|
+
sleep(3)
|
77
|
+
@timer.clear
|
78
|
+
sleep(2)
|
79
|
+
assert_equal(2, result)
|
80
|
+
assert(@timer.running?)
|
81
|
+
end
|
82
|
+
|
83
|
+
# Check that the timer throws an exception when it
|
84
|
+
# is instructed to wakeup while not running
|
85
|
+
def test_wakeup
|
86
|
+
@timer.stop
|
87
|
+
assert_raise(ActionTimer::NotRunning){ @timer.wakeup }
|
88
|
+
end
|
89
|
+
|
90
|
+
# Check that the timer throws an exception when it
|
91
|
+
# is instructed to start but is already running
|
92
|
+
def test_start
|
93
|
+
assert_raise(ActionTimer::AlreadyRunning){ @timer.start }
|
94
|
+
end
|
95
|
+
|
96
|
+
# Check that multiple actions can be added at once
|
97
|
+
def test_mass_add
|
98
|
+
result = 0
|
99
|
+
actions = []
|
100
|
+
actions << ActionTimer::Action.new(@timer, 1){ result += 1}
|
101
|
+
actions << ActionTimer::Action.new(@timer, 3){ result += 1}
|
102
|
+
actions << ActionTimer::Action.new(@timer, 5){ result += 1}
|
103
|
+
@timer.mass_add(actions)
|
104
|
+
sleep(5.3)
|
105
|
+
assert_equal(7, result)
|
106
|
+
end
|
107
|
+
|
108
|
+
# Check that an action can be properly removed from
|
109
|
+
# the timer
|
110
|
+
def test_remove
|
111
|
+
result = 0
|
112
|
+
action = @timer.add(1){result += 1}
|
113
|
+
sleep(2.1)
|
114
|
+
@timer.remove(action)
|
115
|
+
sleep(2)
|
116
|
+
assert_equal(2, result)
|
117
|
+
end
|
118
|
+
|
119
|
+
# Check that an action's period can be dynamically
|
120
|
+
# reset
|
121
|
+
def test_action_reset
|
122
|
+
result = 0
|
123
|
+
action = @timer.add(1){ result += 1}
|
124
|
+
sleep(2.1)
|
125
|
+
action.reset_period(3)
|
126
|
+
sleep(3.1)
|
127
|
+
assert_equal(result, 3)
|
128
|
+
end
|
129
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ActionTimer
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- spox
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-
|
12
|
+
date: 2009-05-20 00:00:00 -07:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
@@ -22,34 +22,40 @@ dependencies:
|
|
22
22
|
- !ruby/object:Gem::Version
|
23
23
|
version: "0"
|
24
24
|
version:
|
25
|
-
description:
|
25
|
+
description: ""
|
26
26
|
email: spox@modspox.com
|
27
27
|
executables: []
|
28
28
|
|
29
29
|
extensions: []
|
30
30
|
|
31
|
-
extra_rdoc_files:
|
32
|
-
|
31
|
+
extra_rdoc_files:
|
32
|
+
- README.rdoc
|
33
|
+
- LICENSE
|
34
|
+
- CHANGELOG
|
33
35
|
files:
|
34
|
-
-
|
36
|
+
- tests
|
37
|
+
- tests/run_tests.rb
|
35
38
|
- actiontimer.gemspec
|
39
|
+
- README.rdoc
|
36
40
|
- lib
|
37
41
|
- lib/actiontimer
|
38
42
|
- lib/actiontimer/Action.rb
|
39
43
|
- lib/actiontimer/LogHelper.rb
|
40
44
|
- lib/actiontimer/Exceptions.rb
|
41
|
-
- lib/actiontimer/Action.rb~
|
42
|
-
- lib/actiontimer/Timer.rb~
|
43
45
|
- lib/actiontimer/Timer.rb
|
44
46
|
- lib/actiontimer.rb
|
45
47
|
- LICENSE
|
46
|
-
-
|
47
|
-
- ActionTimer-0.0.1.gem
|
48
|
+
- CHANGELOG
|
48
49
|
has_rdoc: true
|
49
|
-
homepage:
|
50
|
+
homepage: http://dev.modspox.com/trac/ActionTimer
|
50
51
|
post_install_message:
|
51
|
-
rdoc_options:
|
52
|
-
|
52
|
+
rdoc_options:
|
53
|
+
- --title
|
54
|
+
- ActionTimer
|
55
|
+
- --main
|
56
|
+
- README.rdoc
|
57
|
+
- --line-numbers
|
58
|
+
- --inline-source
|
53
59
|
require_paths:
|
54
60
|
- lib
|
55
61
|
required_ruby_version: !ruby/object:Gem::Requirement
|
data/ActionTimer-0.0.1.gem
DELETED
File without changes
|
data/README
DELETED
@@ -1,48 +0,0 @@
|
|
1
|
-
== ActionTimer ==
|
2
|
-
~ Simple timing for a complex world ~
|
3
|
-
|
4
|
-
ActionTimer is a helper for timed events. It
|
5
|
-
allows for single and recurring actions to
|
6
|
-
be executed in an efficient manner. It makes
|
7
|
-
use of a single thread to keep time on registered
|
8
|
-
actions and uses an ActionPool to execute
|
9
|
-
actions. Simple and effective.
|
10
|
-
|
11
|
-
install (easy):
|
12
|
-
|
13
|
-
gem install ActionTimer
|
14
|
-
|
15
|
-
install (less easy):
|
16
|
-
|
17
|
-
git clone http://github.com/spox/actiontimer.git
|
18
|
-
cd actiontimer
|
19
|
-
gem build actiontimer.gemspec
|
20
|
-
gem install ActionTimer-x.x.x.gem
|
21
|
-
|
22
|
-
Simple example of using the timer:
|
23
|
-
|
24
|
-
require 'actiontimer'
|
25
|
-
|
26
|
-
timer = ActionTimer::Timer.new
|
27
|
-
|
28
|
-
timer.add(10){puts "#{Time.now}: This is timed every 10 seconds"}
|
29
|
-
timer.add(15){puts "#{Time.now}: This is timed every 15 seconds"}
|
30
|
-
loop do
|
31
|
-
puts "#{Time.now}: Main loop that sleeps for 5 seconds"
|
32
|
-
sleep(5)
|
33
|
-
end
|
34
|
-
|
35
|
-
Output:
|
36
|
-
|
37
|
-
2009-04-13 17:41:39 -0700: Main loop that sleeps for 5 seconds
|
38
|
-
2009-04-13 17:41:44 -0700: Main loop that sleeps for 5 seconds
|
39
|
-
2009-04-13 17:41:49 -0700: This is timed every 10 seconds
|
40
|
-
2009-04-13 17:41:49 -0700: Main loop that sleeps for 5 seconds
|
41
|
-
2009-04-13 17:41:54 -0700: This is timed every 15 seconds
|
42
|
-
2009-04-13 17:41:54 -0700: Main loop that sleeps for 5 seconds
|
43
|
-
2009-04-13 17:41:59 -0700: This is timed every 10 seconds
|
44
|
-
2009-04-13 17:41:59 -0700: Main loop that sleeps for 5 seconds
|
45
|
-
2009-04-13 17:42:04 -0700: Main loop that sleeps for 5 seconds
|
46
|
-
2009-04-13 17:42:09 -0700: This is timed every 10 seconds
|
47
|
-
2009-04-13 17:42:09 -0700: This is timed every 15 seconds
|
48
|
-
2009-04-13 17:42:09 -0700: Main loop that sleeps for 5 seconds
|
data/README~
DELETED
@@ -1,48 +0,0 @@
|
|
1
|
-
== ActionTimer ==
|
2
|
-
~ Simple timing for a complex world ~
|
3
|
-
|
4
|
-
ActionTimer is a helper for timed events. It
|
5
|
-
allows for single and recurring actions to
|
6
|
-
be executed in an efficient manner. It makes
|
7
|
-
use of a single thread to keep time on registered
|
8
|
-
actions and uses an ActionPool to execute
|
9
|
-
actions. Simple and effective.
|
10
|
-
|
11
|
-
install (easy):
|
12
|
-
|
13
|
-
gem install ActionTimer
|
14
|
-
|
15
|
-
install (less easy):
|
16
|
-
|
17
|
-
git clone http://github.com/spox/actiontimer.git
|
18
|
-
cd actiontimer
|
19
|
-
gem build actiontimer.gemspec
|
20
|
-
gem install ActionTimer-x.x.x.gem
|
21
|
-
|
22
|
-
Simple example of using the timer:
|
23
|
-
|
24
|
-
require 'actiontimer'
|
25
|
-
|
26
|
-
timer = ActionTimer::Timer.new
|
27
|
-
|
28
|
-
timer.add(10){puts "#{Time.now}: This is timed every 10 seconds"}
|
29
|
-
timer.add(15){puts "#{Time.now}: This is timed every 15 seconds"}
|
30
|
-
loop do
|
31
|
-
puts "#{Time.now}: Main loop that sleeps for 5 seconds"
|
32
|
-
sleep(5)
|
33
|
-
end
|
34
|
-
|
35
|
-
Output:
|
36
|
-
|
37
|
-
2009-04-13 13:41:39 -0700: Main loop that sleeps for 5 seconds
|
38
|
-
2009-04-13 13:41:44 -0700: Main loop that sleeps for 5 seconds
|
39
|
-
2009-04-13 13:41:49 -0700: This is timed every 10 seconds
|
40
|
-
2009-04-13 13:41:49 -0700: Main loop that sleeps for 5 seconds
|
41
|
-
2009-04-13 13:41:54 -0700: This is timed every 15 seconds
|
42
|
-
2009-04-13 13:41:54 -0700: Main loop that sleeps for 5 seconds
|
43
|
-
2009-04-13 13:41:59 -0700: This is timed every 10 seconds
|
44
|
-
2009-04-13 13:41:59 -0700: Main loop that sleeps for 5 seconds
|
45
|
-
2009-04-13 13:42:04 -0700: Main loop that sleeps for 5 seconds
|
46
|
-
2009-04-13 13:42:09 -0700: This is timed every 10 seconds
|
47
|
-
2009-04-13 13:42:09 -0700: This is timed every 15 seconds
|
48
|
-
2009-04-13 13:42:09 -0700: Main loop that sleeps for 5 seconds
|
data/lib/actiontimer/Action.rb~
DELETED
@@ -1,69 +0,0 @@
|
|
1
|
-
module ActionTimer
|
2
|
-
class Action
|
3
|
-
|
4
|
-
attr_accessor :owner
|
5
|
-
|
6
|
-
# timer:: Timer this action resides within
|
7
|
-
# period:: amount of time between runs
|
8
|
-
# once:: only run this action once
|
9
|
-
# data:: data to pass to block
|
10
|
-
# block:: block to be executed
|
11
|
-
def initialize(timer, period, once=false, data=nil, &block)
|
12
|
-
@period = period.to_f
|
13
|
-
@block = block
|
14
|
-
@data = data
|
15
|
-
@once = once
|
16
|
-
@due = false
|
17
|
-
@timer = timer
|
18
|
-
@completed = false
|
19
|
-
@wait_remaining = @period
|
20
|
-
@owner = nil
|
21
|
-
end
|
22
|
-
|
23
|
-
# o:: Object that added this action
|
24
|
-
# Adds an owner for this action. Useful
|
25
|
-
# for clearing all actions for a given
|
26
|
-
# object from the timer
|
27
|
-
def owner=(o)
|
28
|
-
@owner = o
|
29
|
-
end
|
30
|
-
|
31
|
-
# amount:: amount of time that has passed
|
32
|
-
# Decrement remaining wait time by given amount
|
33
|
-
def tick(amount)
|
34
|
-
@wait_remaining = @wait_remaining - amount if @wait_remaining > 0
|
35
|
-
@wait_remaining = 0 if @wait_remaining < 0
|
36
|
-
@completed = true if @once && @wait_remaining <= 0
|
37
|
-
end
|
38
|
-
|
39
|
-
# Time remaning before Action is due
|
40
|
-
def remaining
|
41
|
-
@wait_remaining <= 0 ? 0 : @wait_remaining
|
42
|
-
end
|
43
|
-
|
44
|
-
# new_time:: new period
|
45
|
-
# Resets the wait period between runs
|
46
|
-
def reset_period(new_time)
|
47
|
-
@period = new_time.to_f
|
48
|
-
@wait_remaining = @period
|
49
|
-
@timer.wakeup
|
50
|
-
end
|
51
|
-
|
52
|
-
# Action is ready to be destroyed
|
53
|
-
def is_complete?
|
54
|
-
@completed
|
55
|
-
end
|
56
|
-
|
57
|
-
# Used for scheduling with Timer. Resets the interval
|
58
|
-
# and returns itself
|
59
|
-
def schedule
|
60
|
-
@wait_remaining = @period
|
61
|
-
return self
|
62
|
-
end
|
63
|
-
|
64
|
-
# Run the action
|
65
|
-
def run
|
66
|
-
@data.nil? ? @block.call : @block.call(@data)
|
67
|
-
end
|
68
|
-
end
|
69
|
-
end
|
data/lib/actiontimer/Timer.rb~
DELETED
@@ -1,140 +0,0 @@
|
|
1
|
-
require 'actionpool'
|
2
|
-
['Action', 'Exceptions', 'LogHelper'].each{|f| require "actiontimer/#{f}"}
|
3
|
-
|
4
|
-
module ActionTimer
|
5
|
-
class Timer
|
6
|
-
# pool:: ActionPool for processing actions
|
7
|
-
# Creates a new timer
|
8
|
-
def initialize(pool=nil, logger=nil)
|
9
|
-
@actions = []
|
10
|
-
@new_actions = []
|
11
|
-
@timer_thread = nil
|
12
|
-
@stop_timer = false
|
13
|
-
@add_lock = Mutex.new
|
14
|
-
@awake_lock = Mutex.new
|
15
|
-
@new_actions = Queue.new
|
16
|
-
@pool = pool.nil? ? ActionPool::Pool.new : pool
|
17
|
-
@logger = LogHelper.new(logger)
|
18
|
-
start
|
19
|
-
end
|
20
|
-
|
21
|
-
# Forcibly wakes the timer early
|
22
|
-
def wakeup
|
23
|
-
return unless @awake_lock.try_lock
|
24
|
-
@timer_thread.wakeup if @timer_thread.status == 'sleep'
|
25
|
-
@awake_lock.unlock
|
26
|
-
end
|
27
|
-
|
28
|
-
# period:: amount of time between runs
|
29
|
-
# once:: only run this action once
|
30
|
-
# data:: data to pass to block
|
31
|
-
# owner:: owner of Action
|
32
|
-
# func:: block to be executed
|
33
|
-
# Add a new action to block
|
34
|
-
def add(period, once=false, data=nil, owner=nil, &func)
|
35
|
-
action = Action.new(self, period, once, data, &func)
|
36
|
-
action.owner = owner unless owner.nil?
|
37
|
-
@add_lock.synchronize{ @new_actions << action }
|
38
|
-
wakeup
|
39
|
-
return action
|
40
|
-
end
|
41
|
-
|
42
|
-
# actions:: Array of actions
|
43
|
-
# Add multiple Actions to the timer at once
|
44
|
-
def mass_add(actions)
|
45
|
-
raise InvalidType.new(Array, actions.class) unless actions.is_a?(Array)
|
46
|
-
actions.each do |action|
|
47
|
-
raise InvalidType.new(ActionTimer::Action, action.class) unless action.is_a?(Action)
|
48
|
-
end
|
49
|
-
@add_lock.synchronize{ @new_actions = @new_actions + actions }
|
50
|
-
wakeup
|
51
|
-
end
|
52
|
-
|
53
|
-
# action:: Action to remove from timer
|
54
|
-
# Remove given action from timer
|
55
|
-
def remove(action)
|
56
|
-
raise InvalidType.new(ActionTimer::Action, action.class) unless action.is_a?(Action)
|
57
|
-
@actions.delete(action)
|
58
|
-
wakeup
|
59
|
-
end
|
60
|
-
|
61
|
-
# Start the timer
|
62
|
-
def start
|
63
|
-
raise AlreadyRunning.new unless @timer_thread.nil?
|
64
|
-
@timer_thread = Thread.new do
|
65
|
-
begin
|
66
|
-
until @stop_timer do
|
67
|
-
to_sleep = get_min_sleep
|
68
|
-
if((to_sleep.nil? || to_sleep > 0) && @new_actions.empty?)
|
69
|
-
@awake_lock.unlock if @awake_lock.locked?
|
70
|
-
actual_sleep = to_sleep.nil? ? sleep : sleep(to_sleep)
|
71
|
-
@awake_lock.lock
|
72
|
-
else
|
73
|
-
actual_sleep = 0
|
74
|
-
end
|
75
|
-
tick(actual_sleep)
|
76
|
-
add_waiting_actions
|
77
|
-
end
|
78
|
-
rescue Object => boom
|
79
|
-
@logger.fatal("Timer encountered an unexpected error: #{boom}\n#{boom.backtrace.join("\n")}")
|
80
|
-
end
|
81
|
-
end
|
82
|
-
end
|
83
|
-
|
84
|
-
# Stop the timer
|
85
|
-
def stop
|
86
|
-
@stop_timer = true
|
87
|
-
wakeup
|
88
|
-
@timer_thread.join
|
89
|
-
end
|
90
|
-
|
91
|
-
# owner:: owner actions to remove
|
92
|
-
# Clears timer of actions. If an owner is supplied
|
93
|
-
# only actions owned by owner will be removed
|
94
|
-
def clear(owner=nil)
|
95
|
-
if(owner.nil?)
|
96
|
-
@actions.clear
|
97
|
-
@new_actions.clear
|
98
|
-
else
|
99
|
-
@actions.each{|a| @actions.delete(a) if a.owner == owner}
|
100
|
-
end
|
101
|
-
wakeup
|
102
|
-
end
|
103
|
-
|
104
|
-
private
|
105
|
-
|
106
|
-
def get_min_sleep
|
107
|
-
min = @actions.map{|a|a.remaining}.sort[0]
|
108
|
-
unless(min.nil? || min > 0)
|
109
|
-
@actions.each{|a|@actions.delete(a) if a.remaining == 0} # kill stuck actions
|
110
|
-
min = get_min_sleep
|
111
|
-
end
|
112
|
-
return min
|
113
|
-
end
|
114
|
-
|
115
|
-
def add_waiting_actions
|
116
|
-
@add_lock.synchronize do
|
117
|
-
@actions = @actions + @new_actions
|
118
|
-
@new_actions.clear
|
119
|
-
end
|
120
|
-
end
|
121
|
-
|
122
|
-
def tick(time_passed)
|
123
|
-
@actions.each do |action|
|
124
|
-
action.tick(time_passed)
|
125
|
-
if(action.due?)
|
126
|
-
remove(action) if action.is_complete?
|
127
|
-
action = action.schedule
|
128
|
-
@pool.process do
|
129
|
-
begin
|
130
|
-
action.run
|
131
|
-
rescue Object => boom
|
132
|
-
@logger.error("Timer caught an error while running action: #{boom}\n#{boom.backtrace.join("\n")}")
|
133
|
-
end
|
134
|
-
end
|
135
|
-
end
|
136
|
-
end
|
137
|
-
end
|
138
|
-
|
139
|
-
end
|
140
|
-
end
|