ActionTimer 0.0.1

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.
File without changes
data/LICENSE ADDED
@@ -0,0 +1,165 @@
1
+ GNU LESSER GENERAL PUBLIC LICENSE
2
+ Version 3, 29 June 2007
3
+
4
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
5
+ Everyone is permitted to copy and distribute verbatim copies
6
+ of this license document, but changing it is not allowed.
7
+
8
+
9
+ This version of the GNU Lesser General Public License incorporates
10
+ the terms and conditions of version 3 of the GNU General Public
11
+ License, supplemented by the additional permissions listed below.
12
+
13
+ 0. Additional Definitions.
14
+
15
+ As used herein, "this License" refers to version 3 of the GNU Lesser
16
+ General Public License, and the "GNU GPL" refers to version 3 of the GNU
17
+ General Public License.
18
+
19
+ "The Library" refers to a covered work governed by this License,
20
+ other than an Application or a Combined Work as defined below.
21
+
22
+ An "Application" is any work that makes use of an interface provided
23
+ by the Library, but which is not otherwise based on the Library.
24
+ Defining a subclass of a class defined by the Library is deemed a mode
25
+ of using an interface provided by the Library.
26
+
27
+ A "Combined Work" is a work produced by combining or linking an
28
+ Application with the Library. The particular version of the Library
29
+ with which the Combined Work was made is also called the "Linked
30
+ Version".
31
+
32
+ The "Minimal Corresponding Source" for a Combined Work means the
33
+ Corresponding Source for the Combined Work, excluding any source code
34
+ for portions of the Combined Work that, considered in isolation, are
35
+ based on the Application, and not on the Linked Version.
36
+
37
+ The "Corresponding Application Code" for a Combined Work means the
38
+ object code and/or source code for the Application, including any data
39
+ and utility programs needed for reproducing the Combined Work from the
40
+ Application, but excluding the System Libraries of the Combined Work.
41
+
42
+ 1. Exception to Section 3 of the GNU GPL.
43
+
44
+ You may convey a covered work under sections 3 and 4 of this License
45
+ without being bound by section 3 of the GNU GPL.
46
+
47
+ 2. Conveying Modified Versions.
48
+
49
+ If you modify a copy of the Library, and, in your modifications, a
50
+ facility refers to a function or data to be supplied by an Application
51
+ that uses the facility (other than as an argument passed when the
52
+ facility is invoked), then you may convey a copy of the modified
53
+ version:
54
+
55
+ a) under this License, provided that you make a good faith effort to
56
+ ensure that, in the event an Application does not supply the
57
+ function or data, the facility still operates, and performs
58
+ whatever part of its purpose remains meaningful, or
59
+
60
+ b) under the GNU GPL, with none of the additional permissions of
61
+ this License applicable to that copy.
62
+
63
+ 3. Object Code Incorporating Material from Library Header Files.
64
+
65
+ The object code form of an Application may incorporate material from
66
+ a header file that is part of the Library. You may convey such object
67
+ code under terms of your choice, provided that, if the incorporated
68
+ material is not limited to numerical parameters, data structure
69
+ layouts and accessors, or small macros, inline functions and templates
70
+ (ten or fewer lines in length), you do both of the following:
71
+
72
+ a) Give prominent notice with each copy of the object code that the
73
+ Library is used in it and that the Library and its use are
74
+ covered by this License.
75
+
76
+ b) Accompany the object code with a copy of the GNU GPL and this license
77
+ document.
78
+
79
+ 4. Combined Works.
80
+
81
+ You may convey a Combined Work under terms of your choice that,
82
+ taken together, effectively do not restrict modification of the
83
+ portions of the Library contained in the Combined Work and reverse
84
+ engineering for debugging such modifications, if you also do each of
85
+ the following:
86
+
87
+ a) Give prominent notice with each copy of the Combined Work that
88
+ the Library is used in it and that the Library and its use are
89
+ covered by this License.
90
+
91
+ b) Accompany the Combined Work with a copy of the GNU GPL and this license
92
+ document.
93
+
94
+ c) For a Combined Work that displays copyright notices during
95
+ execution, include the copyright notice for the Library among
96
+ these notices, as well as a reference directing the user to the
97
+ copies of the GNU GPL and this license document.
98
+
99
+ d) Do one of the following:
100
+
101
+ 0) Convey the Minimal Corresponding Source under the terms of this
102
+ License, and the Corresponding Application Code in a form
103
+ suitable for, and under terms that permit, the user to
104
+ recombine or relink the Application with a modified version of
105
+ the Linked Version to produce a modified Combined Work, in the
106
+ manner specified by section 6 of the GNU GPL for conveying
107
+ Corresponding Source.
108
+
109
+ 1) Use a suitable shared library mechanism for linking with the
110
+ Library. A suitable mechanism is one that (a) uses at run time
111
+ a copy of the Library already present on the user's computer
112
+ system, and (b) will operate properly with a modified version
113
+ of the Library that is interface-compatible with the Linked
114
+ Version.
115
+
116
+ e) Provide Installation Information, but only if you would otherwise
117
+ be required to provide such information under section 6 of the
118
+ GNU GPL, and only to the extent that such information is
119
+ necessary to install and execute a modified version of the
120
+ Combined Work produced by recombining or relinking the
121
+ Application with a modified version of the Linked Version. (If
122
+ you use option 4d0, the Installation Information must accompany
123
+ the Minimal Corresponding Source and Corresponding Application
124
+ Code. If you use option 4d1, you must provide the Installation
125
+ Information in the manner specified by section 6 of the GNU GPL
126
+ for conveying Corresponding Source.)
127
+
128
+ 5. Combined Libraries.
129
+
130
+ You may place library facilities that are a work based on the
131
+ Library side by side in a single library together with other library
132
+ facilities that are not Applications and are not covered by this
133
+ License, and convey such a combined library under terms of your
134
+ choice, if you do both of the following:
135
+
136
+ a) Accompany the combined library with a copy of the same work based
137
+ on the Library, uncombined with any other library facilities,
138
+ conveyed under the terms of this License.
139
+
140
+ b) Give prominent notice with the combined library that part of it
141
+ is a work based on the Library, and explaining where to find the
142
+ accompanying uncombined form of the same work.
143
+
144
+ 6. Revised Versions of the GNU Lesser General Public License.
145
+
146
+ The Free Software Foundation may publish revised and/or new versions
147
+ of the GNU Lesser General Public License from time to time. Such new
148
+ versions will be similar in spirit to the present version, but may
149
+ differ in detail to address new problems or concerns.
150
+
151
+ Each version is given a distinguishing version number. If the
152
+ Library as you received it specifies that a certain numbered version
153
+ of the GNU Lesser General Public License "or any later version"
154
+ applies to it, you have the option of following the terms and
155
+ conditions either of that published version or of any later version
156
+ published by the Free Software Foundation. If the Library as you
157
+ received it does not specify a version number of the GNU Lesser
158
+ General Public License, you may choose any version of the GNU Lesser
159
+ General Public License ever published by the Free Software Foundation.
160
+
161
+ If the Library as you received it specifies that a proxy can decide
162
+ whether future versions of the GNU Lesser General Public License shall
163
+ apply, that proxy's public statement of acceptance of any version is
164
+ permanent authorization for you to choose that version for the
165
+ Library.
data/README ADDED
@@ -0,0 +1,48 @@
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~ ADDED
@@ -0,0 +1,48 @@
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
@@ -0,0 +1,13 @@
1
+ spec = Gem::Specification.new do |s|
2
+ s.name = 'ActionTimer'
3
+ s.author = %q(spox)
4
+ s.email = %q(spox@modspox.com)
5
+ s.version = '0.0.1'
6
+ s.summary = %q(Simple timer for a complex world)
7
+ s.platform = Gem::Platform::RUBY
8
+ s.has_rdoc = true
9
+ s.files = Dir['**/*']
10
+ s.require_paths = %w(lib)
11
+ s.add_dependency 'ActionPool'
12
+ s.required_ruby_version = '>= 1.8.6'
13
+ end
@@ -0,0 +1 @@
1
+ require 'actiontimer/Timer.rb'
@@ -0,0 +1,73 @@
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
+ @timer = timer
17
+ @completed = false
18
+ @wait_remaining = @period
19
+ @owner = nil
20
+ end
21
+
22
+ # o:: Object that added this action
23
+ # Adds an owner for this action. Useful
24
+ # for clearing all actions for a given
25
+ # object from the timer
26
+ def owner=(o)
27
+ @owner = o
28
+ end
29
+
30
+ # amount:: amount of time that has passed
31
+ # Decrement remaining wait time by given amount
32
+ def tick(amount)
33
+ @wait_remaining = @wait_remaining - amount if @wait_remaining > 0
34
+ @wait_remaining = 0 if @wait_remaining < 0
35
+ @completed = true if @once && @wait_remaining <= 0
36
+ end
37
+
38
+ # Time remaning before Action is due
39
+ def remaining
40
+ @wait_remaining <= 0 ? 0 : @wait_remaining
41
+ end
42
+
43
+ # new_time:: new period
44
+ # Resets the wait period between runs
45
+ def reset_period(new_time)
46
+ @period = new_time.to_f
47
+ @wait_remaining = @period
48
+ @timer.wakeup
49
+ end
50
+
51
+ # Action is ready to be destroyed
52
+ def is_complete?
53
+ @completed
54
+ end
55
+
56
+ # Used for scheduling with Timer. Resets the interval
57
+ # and returns itself
58
+ def schedule
59
+ @wait_remaining = @period
60
+ return self
61
+ end
62
+
63
+ # Is action due for execution
64
+ def due?
65
+ @wait_remaining <= 0
66
+ end
67
+
68
+ # Run the action
69
+ def run
70
+ @data.nil? ? @block.call : @block.call(@data)
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,69 @@
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
@@ -0,0 +1,21 @@
1
+ module ActionTimer
2
+
3
+ class AlreadyRunning < Exception
4
+ end
5
+
6
+ class NotRunning < Exception
7
+ end
8
+
9
+ class InvalidType < Exception
10
+ attr_reader :given
11
+ attr_reader :expected
12
+ def initialize(g,e)
13
+ @given = given
14
+ @expected = e
15
+ end
16
+
17
+ def to_s
18
+ "Given type: #{g} Expected type: #{e}"
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,28 @@
1
+ require 'logger'
2
+
3
+ module ActionTimer
4
+
5
+ class LogHelper
6
+
7
+ def initialize(logger=nil)
8
+ @logger = logger
9
+ end
10
+
11
+ def info(m)
12
+ @logger.info(m) unless @logger.nil?
13
+ end
14
+
15
+ def warn(m)
16
+ @logger.warn(m) unless @logger.nil?
17
+ end
18
+
19
+ def fatal(m)
20
+ @logger.fatal(m) unless @logger.nil?
21
+ end
22
+
23
+ def error(m)
24
+ @logger.error(m) unless @logger.nil?
25
+ end
26
+ end
27
+
28
+ end
@@ -0,0 +1,139 @@
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
+ @pool = pool.nil? ? ActionPool::Pool.new : pool
16
+ @logger = LogHelper.new(logger)
17
+ start
18
+ end
19
+
20
+ # Forcibly wakes the timer early
21
+ def wakeup
22
+ return unless @awake_lock.try_lock
23
+ @timer_thread.wakeup if @timer_thread.status == 'sleep'
24
+ @awake_lock.unlock
25
+ end
26
+
27
+ # period:: amount of time between runs
28
+ # once:: only run this action once
29
+ # data:: data to pass to block
30
+ # owner:: owner of Action
31
+ # func:: block to be executed
32
+ # Add a new action to block
33
+ def add(period, once=false, data=nil, owner=nil, &func)
34
+ action = Action.new(self, period, once, data, &func)
35
+ action.owner = owner unless owner.nil?
36
+ @add_lock.synchronize{ @new_actions << action }
37
+ wakeup
38
+ return action
39
+ end
40
+
41
+ # actions:: Array of actions
42
+ # Add multiple Actions to the timer at once
43
+ def mass_add(actions)
44
+ raise InvalidType.new(Array, actions.class) unless actions.is_a?(Array)
45
+ actions.each do |action|
46
+ raise InvalidType.new(ActionTimer::Action, action.class) unless action.is_a?(Action)
47
+ end
48
+ @add_lock.synchronize{ @new_actions = @new_actions + actions }
49
+ wakeup
50
+ end
51
+
52
+ # action:: Action to remove from timer
53
+ # Remove given action from timer
54
+ def remove(action)
55
+ raise InvalidType.new(ActionTimer::Action, action.class) unless action.is_a?(Action)
56
+ @actions.delete(action)
57
+ wakeup
58
+ end
59
+
60
+ # Start the timer
61
+ def start
62
+ raise AlreadyRunning.new unless @timer_thread.nil?
63
+ @timer_thread = Thread.new do
64
+ begin
65
+ until @stop_timer do
66
+ to_sleep = get_min_sleep
67
+ if((to_sleep.nil? || to_sleep > 0) && @new_actions.empty?)
68
+ @awake_lock.unlock if @awake_lock.locked?
69
+ actual_sleep = to_sleep.nil? ? sleep : sleep(to_sleep)
70
+ @awake_lock.lock
71
+ else
72
+ actual_sleep = 0
73
+ end
74
+ tick(actual_sleep)
75
+ add_waiting_actions
76
+ end
77
+ rescue Object => boom
78
+ @logger.fatal("Timer encountered an unexpected error: #{boom}\n#{boom.backtrace.join("\n")}")
79
+ end
80
+ end
81
+ end
82
+
83
+ # Stop the timer
84
+ def stop
85
+ @stop_timer = true
86
+ wakeup
87
+ @timer_thread.join
88
+ end
89
+
90
+ # owner:: owner actions to remove
91
+ # Clears timer of actions. If an owner is supplied
92
+ # only actions owned by owner will be removed
93
+ def clear(owner=nil)
94
+ if(owner.nil?)
95
+ @actions.clear
96
+ @new_actions.clear
97
+ else
98
+ @actions.each{|a| @actions.delete(a) if a.owner == owner}
99
+ end
100
+ wakeup
101
+ end
102
+
103
+ private
104
+
105
+ def get_min_sleep
106
+ min = @actions.map{|a|a.remaining}.sort[0]
107
+ unless(min.nil? || min > 0)
108
+ @actions.each{|a|@actions.delete(a) if a.remaining == 0} # kill stuck actions
109
+ min = get_min_sleep
110
+ end
111
+ return min
112
+ end
113
+
114
+ def add_waiting_actions
115
+ @add_lock.synchronize do
116
+ @actions = @actions + @new_actions
117
+ @new_actions.clear
118
+ end
119
+ end
120
+
121
+ def tick(time_passed)
122
+ @actions.each do |action|
123
+ action.tick(time_passed)
124
+ if(action.due?)
125
+ remove(action) if action.is_complete?
126
+ action = action.schedule
127
+ @pool.process do
128
+ begin
129
+ action.run
130
+ rescue Object => boom
131
+ @logger.error("Timer caught an error while running action: #{boom}\n#{boom.backtrace.join("\n")}")
132
+ end
133
+ end
134
+ end
135
+ end
136
+ end
137
+
138
+ end
139
+ end
@@ -0,0 +1,140 @@
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
metadata ADDED
@@ -0,0 +1,75 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ActionTimer
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - spox
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-04-15 00:00:00 -07:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: ActionPool
17
+ type: :runtime
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: "0"
24
+ version:
25
+ description:
26
+ email: spox@modspox.com
27
+ executables: []
28
+
29
+ extensions: []
30
+
31
+ extra_rdoc_files: []
32
+
33
+ files:
34
+ - README~
35
+ - actiontimer.gemspec
36
+ - lib
37
+ - lib/actiontimer
38
+ - lib/actiontimer/Action.rb
39
+ - lib/actiontimer/LogHelper.rb
40
+ - lib/actiontimer/Exceptions.rb
41
+ - lib/actiontimer/Action.rb~
42
+ - lib/actiontimer/Timer.rb~
43
+ - lib/actiontimer/Timer.rb
44
+ - lib/actiontimer.rb
45
+ - LICENSE
46
+ - README
47
+ - ActionTimer-0.0.1.gem
48
+ has_rdoc: true
49
+ homepage:
50
+ post_install_message:
51
+ rdoc_options: []
52
+
53
+ require_paths:
54
+ - lib
55
+ required_ruby_version: !ruby/object:Gem::Requirement
56
+ requirements:
57
+ - - ">="
58
+ - !ruby/object:Gem::Version
59
+ version: 1.8.6
60
+ version:
61
+ required_rubygems_version: !ruby/object:Gem::Requirement
62
+ requirements:
63
+ - - ">="
64
+ - !ruby/object:Gem::Version
65
+ version: "0"
66
+ version:
67
+ requirements: []
68
+
69
+ rubyforge_project:
70
+ rubygems_version: 1.3.1
71
+ signing_key:
72
+ specification_version: 2
73
+ summary: Simple timer for a complex world
74
+ test_files: []
75
+