ActionTimer 0.0.1

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