splib 1.4.2 → 1.4.3

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 CHANGED
@@ -1,3 +1,10 @@
1
+ 1.4.3
2
+ * Added new Splib.sleep to return actual sleep times that are useful
3
+ * Added Monitor#try_lock
4
+ * Modify locking behavior on Monitor#signal and Monitor#broadcast
5
+ * Updates to Monitor#wait when used with a timeout
6
+ * Added some simple checking to remove dead threads that fail to release their lock
7
+ * CodeReloader.reload_code returns new holder instead of gutted holder
1
8
  1.4.2
2
9
  * Modify Float#within_delta? to use #between? like any
3
10
  reasonable person would
@@ -21,14 +21,14 @@ The Spox Library is collection of helper methods and classes.
21
21
 
22
22
  This library has been tested on:
23
23
 
24
- * Ruby 1.8.6-p376
25
- * Ruby 1.8.7-p248
26
- * Ruby 1.9.1-p383
27
- * JRuby 1.4
24
+ * Ruby 1.8.6-p399
25
+ * Ruby 1.8.7-p249
26
+ * Ruby 1.9.1-p378
27
+ * JRuby 1.4.0
28
28
 
29
29
  === Usage
30
30
 
31
- The Spox Library has various things located within it. The Splib#load method will allow you to load individual parts of the library, or the entire thing into your program. Lets take a quick look at some of the things available from this library.
31
+ The Spox Library has various things located within it. The Splib#load method will allow you to load individual parts of the library, or the entire thing, into your program. Lets take a quick look at some of the things available from this library.
32
32
 
33
33
  ==== URL Shorteners
34
34
 
@@ -185,7 +185,75 @@ monitor does its best to ensure your threads stay where they are supposed.
185
185
  [:foobar, :foo]
186
186
  [:foobar, :foo, :bar]
187
187
 
188
- ==== TODO: Write examples for CodeReloader and RandomIterator
188
+ The monitor also provides simple wait timers. See the following code:
189
+
190
+ require 'splib'
191
+ Splib.load :Monitor
192
+
193
+ monitor = Splib::Monitor.new
194
+ a = Queue.new
195
+ 5.times{ Thread.new{ monitor.wait(0.1); a << 1; } }
196
+ sleep(0.2)
197
+ puts "Size: #{a.size}"
198
+
199
+ Here we have five threads waiting with a timeout. Nicely, the monitor only uses
200
+ a single thread for timing, instead of generating a new thread for each timeout.
201
+
202
+ ==== Sleep
203
+
204
+ Make getting an actual amount of sleeping a bit easier:
205
+
206
+ require 'splib'
207
+ Splib.load :Sleep
208
+
209
+ puts Kernel.sleep(0.01)
210
+ puts Splib.sleep(0.01)
211
+
212
+ =>
213
+ 0
214
+ 0.00228595733642578
215
+
216
+ ==== CodeReloader
217
+
218
+ Easily reload code into a module:
219
+
220
+ First, assume that file.rb starts out with the following contents:
221
+
222
+ class Foo
223
+ def test
224
+ puts 'Test'
225
+ end
226
+ end
227
+
228
+ Then, after the Splib.load_code call, we modify the file to contain:
229
+
230
+ class Foo
231
+ def untest
232
+ puts 'UnTest'
233
+ end
234
+ end
235
+
236
+ Okay, now we proceed:
237
+
238
+ require 'splib'
239
+ Splib.load :CodeReloader, :Constants
240
+
241
+ mod = Splib.load_code('file.rb')
242
+ foo = Splib.find_const('Foo', [mod]).new
243
+ p foo.respond_to?(:test)
244
+ puts foo.test
245
+ mod = Splib.reload_code(mod)
246
+ foo = Splib.find_const('Foo', [mod]).new
247
+ p foo.respond_to?(:test)
248
+ p foo.respond_to?(:untest)
249
+ puts foo.untest
250
+
251
+ =>
252
+ true
253
+ Test
254
+ false
255
+ true
256
+ UnTest
189
257
 
190
258
  == Last remarks
191
259
 
data/Rakefile CHANGED
@@ -15,7 +15,7 @@ spec = Gem::Specification.new do |s|
15
15
  s.name = 'splib'
16
16
  s.author = 'spox'
17
17
  s.email = 'spox@modspox.com'
18
- s.version = '1.4.2'
18
+ s.version = '1.4.3'
19
19
  s.summary = 'Spox Library'
20
20
  s.platform = Gem::Platform::RUBY
21
21
  s.files = %w(LICENSE README.rdoc CHANGELOG Rakefile) + Dir.glob("{bin,lib,spec,test}/**/*")
@@ -8,6 +8,7 @@ module Splib
8
8
  :HumanIdealRandomIterator,
9
9
  :Monitor,
10
10
  :PriorityQueue,
11
+ :Sleep,
11
12
  :UrlShorteners
12
13
  ]
13
14
  # args:: name of library to load
@@ -43,10 +43,7 @@ module Splib
43
43
  # Reload the code within the module
44
44
  def self.reload_code(holder)
45
45
  raise ArgumentError.new('Expecting a module containing loaded code') unless holder.respond_to?(:path)
46
- holder.constants.each do |const|
47
- holder.send(:remove_const, const)
48
- end
49
- self.load_code(holder.path, holder)
46
+ self.load_code(holder.path)
50
47
  end
51
48
 
52
49
  # path:: path to ruby code
@@ -3,7 +3,12 @@ require 'timeout'
3
3
  module Splib
4
4
 
5
5
  @@processes = []
6
- Kernel.at_exit{@@processes.each{|p| Process.kill('KILL', pro.pid) }}
6
+ @@owner ||= Thread.current
7
+ Kernel.at_exit do
8
+ if(Thread.current == @@owner)
9
+ @@processes.each{|pro| Process.kill('KILL', pro.pid) }
10
+ end
11
+ end
7
12
 
8
13
  # Returns current array of running Processes
9
14
  def self.running_procs
@@ -1,37 +1,42 @@
1
1
  require 'thread'
2
2
 
3
3
  module Splib
4
-
4
+ Splib.load :Sleep
5
+ # Basic exception to wakeup a monitor timer
6
+ class Wakeup < Exception
7
+ end
5
8
  class Monitor
9
+ # Create a new Monitor
6
10
  def initialize
7
11
  @threads = []
8
12
  @locks = []
9
13
  @lock_owner = nil
10
14
  @timers = {}
15
+ @timer = start_timer
16
+ @stop = false
17
+ Kernel.at_exit do
18
+ if(@timer)
19
+ @stop = true
20
+ @timer.raise Wakeup.new
21
+ end
22
+ end
11
23
  end
24
+
12
25
  # timeout:: Wait for given amount of time
13
26
  # Park a thread here
14
27
  def wait(timeout=nil)
28
+ raise 'This thread is already a registered sleeper' if @threads.include?(Thread.current)
29
+ Thread.exclusive{ @threads << Thread.current }
15
30
  if(timeout)
16
- timout = timeout.to_f
17
- @timers[Thread.current] = Thread.new(Thread.current) do |t|
18
- time = 0.0
19
- until(time >= timeout) do
20
- s = Time.now.to_f
21
- sleep(timeout - time)
22
- time += Time.now.to_f - s
23
- end
24
- t.wakeup
25
- end
31
+ timeout = timeout.to_f
32
+ Thread.exclusive{ @timers[Thread.current] = timeout }
33
+ @timer.raise Wakeup.new
26
34
  end
27
- @threads << Thread.current
28
35
  Thread.stop
29
- @threads.delete(Thread.current)
30
- if(timeout)
31
- if(@timers[Thread.current].alive?)
32
- @timers[Thread.current].kill
33
- end
34
- @timers.delete(Thread.current)
36
+ Thread.exclusive{ @threads.delete(Thread.current) }
37
+ if(timeout && @timers.has_key?(Thread.current))
38
+ Thread.exclusive{ @timers.delete(Thread.current) }
39
+ @timer.raise Wakeup.new
35
40
  end
36
41
  true
37
42
  end
@@ -50,17 +55,22 @@ module Splib
50
55
  # Wake up earliest thread
51
56
  def signal
52
57
  synchronize do
53
- t = @threads.shift
54
- t.wakeup if t && t.alive?
58
+ while(t = @threads.shift)
59
+ if(t && t.alive? && t.stop?)
60
+ t.wakeup
61
+ break
62
+ else
63
+ next
64
+ end
65
+ end
55
66
  end
56
67
  end
57
68
  # Wake up all threads
58
69
  def broadcast
59
70
  synchronize do
60
- @threads.each do |t|
61
- t.wakeup if t.alive?
71
+ @threads.dup.each do |t|
72
+ t.wakeup if t.alive? && t.stop?
62
73
  end
63
- @threads.clear
64
74
  end
65
75
  end
66
76
  # Number of threads waiting
@@ -69,58 +79,135 @@ module Splib
69
79
  end
70
80
  # Lock the monitor
71
81
  def lock
72
- if(Thread.exclusive{do_lock})
73
- until(owner?(Thread.current)) do
74
- Thread.stop
75
- end
82
+ Thread.exclusive{ do_lock }
83
+ until(owner?(Thread.current)) do
84
+ Thread.stop
76
85
  end
77
86
  end
78
87
  # Unlock the monitor
79
88
  def unlock
80
- Thread.exclusive{ do_unlock }
89
+ do_unlock
90
+ end
91
+ # Attempt to lock. Returns true if lock is aquired and false if not.
92
+ def try_lock
93
+ locked = false
94
+ Thread.exclusive do
95
+ clean
96
+ unless(locked?(false))
97
+ do_lock
98
+ locked = true
99
+ else
100
+ locked = owner?(Thread.current)
101
+ end
102
+ end
103
+ locked
81
104
  end
105
+ # cln:: Clean dead threads
82
106
  # Is monitor locked
83
- def locked?
84
- @locks.size > 0
107
+ def locked?(cln=true)
108
+ Thread.exclusive{clean} if cln
109
+ @locks.size > 0 || @lock_owner
85
110
  end
86
111
  # Lock the monitor, execute block and unlock the monitor
87
112
  def synchronize
88
113
  result = nil
89
- Thread.exclusive do
90
- do_lock
91
- result = yield
92
- do_unlock
93
- end
114
+ lock
115
+ result = yield
116
+ do_unlock
94
117
  result
95
118
  end
96
119
 
97
120
  private
98
121
 
122
+
123
+ # This is a simple helper method to help keep threads from ending
124
+ # up stuck waiting for a lock when a thread locks the monitor and
125
+ # then decides to die without unlocking. It is only called when
126
+ # new locks are attempted or a check is made if the monitor is
127
+ # currently locked.
128
+ def clean
129
+ @locks.delete_if{|t|!t.alive?}
130
+ if(@lock_owner && !@lock_owner.alive?)
131
+ @lock_owner = @locks.empty? ? nil : @locks.shift
132
+ @lock_owner.wakeup if @lock_owner && !owner?(Thread.current)
133
+ end
134
+ end
135
+
136
+ # Check if the givin thread is the current owner
99
137
  def owner?(t)
100
138
  @lock_owner == t
101
139
  end
102
140
 
141
+ # Aquire monitor lock or be queued for lock
142
+ # NOTE: To make this method more generic and useful, it does
143
+ # not perform a Thread.exclusive, and as such this method should
144
+ # only be called from within a Thread.exclusive{}
103
145
  def do_lock
104
- stop = false
146
+ clean
105
147
  if(@lock_owner)
106
- @locks << Thread.current
107
- stop = true
148
+ if(owner?(Thread.current))
149
+ @locks.unshift(Thread.current)
150
+ else
151
+ @locks << Thread.current
152
+ end
108
153
  else
109
154
  @lock_owner = Thread.current
110
155
  end
111
- stop
156
+ true
112
157
  end
113
158
 
159
+ # Unlock the monitor
114
160
  def do_unlock
115
161
  unless(owner?(Thread.current))
116
162
  raise ThreadError.new("Thread #{Thread.current} is not the current owner: #{@lock_owner}")
117
163
  end
118
- unless(@locks.empty?)
164
+ Thread.exclusive do
119
165
  @locks.delete_if{|t|!t.alive?}
120
- @lock_owner = @locks.shift
121
- @lock_owner.wakeup
122
- else
123
- @lock_owner = nil
166
+ unless(@locks.empty?)
167
+ old_owner = @lock_owner
168
+ @lock_owner = @locks.shift
169
+ @lock_owner.wakeup unless old_owner == @lock_owner
170
+ else
171
+ @lock_owner = nil
172
+ end
173
+ end
174
+ end
175
+
176
+ # Starts the timer for waiting threads with a timeout
177
+ def start_timer
178
+ @timer = Thread.new do
179
+ begin
180
+ until(@stop) do
181
+ cur = []
182
+ t = 0
183
+ Thread.exclusive do
184
+ t = @timers.values.min
185
+ cur = @timers.dup
186
+ end
187
+ t = 0 if !t.nil? && t < 0
188
+ a = 0
189
+ begin
190
+ a = Splib.sleep(t)
191
+ rescue Wakeup
192
+ # do nothing of importance
193
+ ensure
194
+ next if t.nil?
195
+ Thread.exclusive do
196
+ cur.each_pair do |thread, value|
197
+ value -= a
198
+ if(value <= 0)
199
+ thread.wakeup
200
+ @timers.delete(thread)
201
+ else
202
+ @timers[thread] = value
203
+ end
204
+ end
205
+ end
206
+ end
207
+ end
208
+ rescue
209
+ retry
210
+ end
124
211
  end
125
212
  end
126
213
  end
@@ -1,7 +1,8 @@
1
- require 'thread'
1
+ Splib.load :Monitor
2
+
2
3
  module Splib
3
4
  # Exception raised when queue is empty
4
- class EmptyQueue < Exception
5
+ class EmptyQueue < RuntimeError
5
6
  end
6
7
  # This class provides some simple logic for item output. It is
7
8
  # basically a priority based queue with some round robin thrown
@@ -19,7 +20,7 @@ module Splib
19
20
  @whocares = whocares
20
21
  @target_queues = {}
21
22
  @queues = {:PRIORITY => [], :NEW => [], :NORMAL => [], :WHOCARES => []}
22
- @lock = Mutex.new
23
+ @lock = Splib::Monitor.new
23
24
  end
24
25
 
25
26
  # target:: target queue
@@ -42,6 +43,7 @@ module Splib
42
43
  add_queue(:NORMAL, @target_queues[target])
43
44
  end
44
45
  end
46
+ @lock.signal
45
47
  end
46
48
  item
47
49
  end
@@ -54,6 +56,7 @@ module Splib
54
56
  @target_queues[:internal_prio] = [] unless @target_queues[:internal_prio]
55
57
  @target_queues[:internal_prio] << message
56
58
  add_queue(:PRIORITY, @target_queues[:internal_prio])
59
+ @lock.signal
57
60
  end
58
61
  message
59
62
  end
@@ -77,8 +80,15 @@ module Splib
77
80
  end
78
81
  end
79
82
  end
80
- raise EmptyQueue.new('Queue is currently empty') if m.nil? && @raise
81
- return m
83
+ unless(m)
84
+ if(@raise)
85
+ raise EmptyQueue.new('Queue is currently empty')
86
+ else
87
+ @lock.wait_while{ empty? }
88
+ m = pop
89
+ end
90
+ end
91
+ m
82
92
  end
83
93
 
84
94
  # Returns true if queue is empty
@@ -87,6 +97,7 @@ module Splib
87
97
  end
88
98
 
89
99
  alias :push :prioritized_queue
100
+ alias :<< :direct_queue
90
101
 
91
102
  private
92
103
 
@@ -0,0 +1,10 @@
1
+ module Splib
2
+ class << self
3
+ # secs:: Number of seconds to sleep (Use float to provide better actual sleep time)
4
+ def sleep(secs=nil)
5
+ start = Time.now.to_f
6
+ secs.nil? ? Kernel.sleep : Kernel.sleep(secs)
7
+ Time.now.to_f - start
8
+ end
9
+ end
10
+ end
@@ -28,7 +28,7 @@ class CodeReloaderTest < Test::Unit::TestCase
28
28
  assert(!obj.respond_to?(:feebar))
29
29
  assert_equal('hello world', obj.foobar)
30
30
  FileUtils.cp @s2, @s
31
- Splib.reload_code(holder)
31
+ holder = Splib.reload_code(holder)
32
32
  klass = Splib.find_const('Fu::Bar', [holder])
33
33
  obj = klass.new
34
34
  assert(obj.respond_to?(:feebar))
@@ -4,26 +4,27 @@ require 'test/unit'
4
4
  class ExecTest < Test::Unit::TestCase
5
5
  def setup
6
6
  Splib.load :Exec
7
+ Splib.load :Sleep
7
8
  end
8
9
 
9
10
  def test_exec
10
11
  assert_raise(IOError) do
11
- Splib.exec('echo test', 10, 1)
12
+ Splib.exec('/bin/sh -c "echo test"', 10, 1)
12
13
  end
13
14
  assert_raise(Timeout::Error) do
14
- Splib.exec('while [ true ]; do true; done;', 1)
15
+ Splib.exec('/bin/sh -c "while [ true ]; do true; done;"', 1)
15
16
  end
16
- assert_equal("test\n", Splib.exec('echo test'))
17
+ assert_equal("test\n", Splib.exec('/bin/sh -c "echo test"'))
17
18
  end
18
19
 
19
20
  def test_running
20
21
  output = nil
21
22
  Thread.new do
22
- output = Splib.exec('ruby -e \'sleep(0.4); puts "done"\'')
23
+ output = Splib.exec('/bin/sh -c "sleep 0.4; echo done"')
23
24
  end
24
- sleep(0.1)
25
+ Kernel.sleep(0.1)
25
26
  assert_equal(1, Splib.running_procs.size)
26
- sleep(0.5)
27
+ Kernel.sleep(0.5)
27
28
  assert_equal("done\n", output)
28
29
  assert_equal(0, Splib.running_procs.size)
29
30
  end
@@ -2,15 +2,16 @@ require 'splib'
2
2
  require 'test/unit'
3
3
 
4
4
  class MonitorTest < Test::Unit::TestCase
5
+ Splib.load :Monitor
6
+ Splib.load :Sleep
5
7
  def setup
6
- Splib.load :Monitor
7
8
  @monitor = Splib::Monitor.new
8
9
  end
9
10
 
10
11
  def test_wait
11
12
  t = []
12
13
  5.times{ t << Thread.new{ @monitor.wait } }
13
- sleep(0.01) # give threads a chance to wait
14
+ Splib.sleep(0.1) # give threads a chance to wait
14
15
  t.each do |thread|
15
16
  assert(thread.alive?)
16
17
  assert(thread.stop?)
@@ -19,139 +20,174 @@ class MonitorTest < Test::Unit::TestCase
19
20
 
20
21
  def test_wait_timeout
21
22
  t = []
22
- o = []
23
- 5.times{|i| t << Thread.new{ @monitor.wait((i+1)/100.0); o << 1 } }
24
- sleep(0.011)
25
- Thread.pass
26
- assert(!t.shift.alive?)
27
- assert_equal(1, o.size)
28
- sleep(0.1)
23
+ o = Queue.new
24
+ 5.times{ t << Thread.new{ @monitor.wait(0.1); o << 1 } }
25
+ Splib.sleep(0.3)
29
26
  assert_equal(5, o.size)
30
- t.each do |th|
31
- assert(!th.alive?)
32
- end
33
27
  end
34
28
 
35
29
  def test_signal
36
- output = []
30
+ output = Queue.new
37
31
  t = []
38
32
  5.times{ t << Thread.new{ @monitor.wait; output << 1 } }
39
- sleep(0.01)
33
+ Splib.sleep(0.01)
40
34
  t.each do |thread|
41
35
  assert(thread.alive?)
42
36
  assert(thread.stop?)
43
37
  end
44
38
  assert(output.empty?)
45
39
  @monitor.signal
46
- sleep(0.01)
40
+ Splib.sleep(0.01)
47
41
  assert_equal(4, t.select{|th|th.alive?}.size)
48
42
  assert_equal(1, output.size)
49
43
  assert_equal(1, output.pop)
50
44
  end
51
45
 
52
46
  def test_broadcast
53
- output = []
47
+ output = Queue.new
54
48
  t = []
55
49
  5.times{ t << Thread.new{ @monitor.wait; output << 1 } }
56
- sleep(0.01)
50
+ Splib.sleep(0.01)
57
51
  t.each do |thread|
58
52
  assert(thread.alive?)
59
53
  assert(thread.stop?)
60
54
  end
55
+ assert_equal(5, t.size)
61
56
  assert(output.empty?)
62
57
  @monitor.broadcast
63
- sleep(0.01)
58
+ Splib.sleep(0.1)
64
59
  assert_equal(5, output.size)
65
60
  5.times{ assert_equal(1, output.pop) }
66
61
  assert_equal(5, t.select{|th|!th.alive?}.size)
67
62
  end
68
63
 
64
+ def test_synchronize_broadcast
65
+ output = Queue.new
66
+ t = []
67
+ 5.times{ t << Thread.new{ @monitor.wait; output << 1 } }
68
+ Splib.sleep(0.01)
69
+ t.each do |thread|
70
+ assert(thread.alive?)
71
+ assert(thread.stop?)
72
+ end
73
+ assert_equal(5, t.size)
74
+ assert(output.empty?)
75
+ @monitor.synchronize{ @monitor.broadcast }
76
+ Splib.sleep(0.1)
77
+ assert_equal(5, output.size)
78
+ 5.times{ assert_equal(1, output.pop) }
79
+ assert_equal(5, t.select{|th|!th.alive?}.size)
80
+ end
81
+
82
+ def test_multi_lock
83
+ @monitor.synchronize do
84
+ @monitor.synchronize do
85
+ @monitor.lock
86
+ @monitor.synchronize do
87
+ true
88
+ end
89
+ @monitor.unlock
90
+ end
91
+ end
92
+ end
93
+
69
94
  def test_wait_while
70
95
  stop = true
71
96
  t = Thread.new{ @monitor.wait_while{ stop } }
72
- sleep(0.01)
97
+ Splib.sleep(0.01)
73
98
  assert(t.alive?)
74
99
  assert(t.stop?)
75
100
  @monitor.signal
76
- sleep(0.01)
101
+ Splib.sleep(0.01)
77
102
  assert(t.alive?)
78
103
  assert(t.stop?)
79
104
  @monitor.broadcast
80
- sleep(0.01)
105
+ Splib.sleep(0.01)
81
106
  assert(t.alive?)
82
107
  assert(t.stop?)
83
108
  stop = false
84
109
  @monitor.signal
85
- sleep(0.01)
110
+ Splib.sleep(0.01)
86
111
  assert(!t.alive?)
87
112
  assert(t.stop?)
88
113
  end
89
114
 
90
115
  def test_wait_until
91
116
  stop = false
92
- t = Thread.new{ @monitor.wait_until{ stop } }
93
- sleep(0.01)
117
+ done = false
118
+ t = Thread.new{ @monitor.wait_until{ stop }; done = true; }
119
+ Splib.sleep(0.01)
94
120
  assert(t.alive?)
95
121
  assert(t.stop?)
96
122
  @monitor.signal
97
- sleep(0.01)
123
+ Splib.sleep(0.01)
98
124
  assert(t.alive?)
99
125
  assert(t.stop?)
100
126
  @monitor.broadcast
101
- sleep(0.01)
127
+ Splib.sleep(0.01)
102
128
  assert(t.alive?)
103
129
  assert(t.stop?)
104
130
  stop = true
105
131
  @monitor.signal
106
- sleep(0.01)
107
- assert(!t.alive?)
108
- assert(t.stop?)
132
+ Splib.sleep(0.1)
133
+ assert(done)
109
134
  end
110
135
 
111
136
  def test_waiters
112
137
  t = []
113
138
  (rand(20)+1).times{ t << Thread.new{ @monitor.wait } }
114
- sleep(0.01)
139
+ Splib.sleep(0.1)
115
140
  assert_equal(t.size, @monitor.waiters)
116
141
  @monitor.broadcast
117
- sleep(0.01)
142
+ Splib.sleep(0.1)
118
143
  assert_equal(0, @monitor.waiters)
119
144
  end
120
145
 
121
146
  def test_lock_unlock
122
147
  t = []
123
148
  output = []
124
- 3.times{|i| t << Thread.new{ @monitor.lock; sleep((i+1)/100.0); output << i; @monitor.unlock;}}
125
- sleep(0.011)
149
+ 3.times{|i| t << Thread.new{ @monitor.lock; Splib.sleep(0.1); output << i; @monitor.unlock;}}
150
+ Splib.sleep(0.12)
126
151
  assert_equal(1, output.size)
127
- sleep(0.021)
152
+ Splib.sleep(0.12)
128
153
  assert_equal(2, output.size)
129
- sleep(0.031)
154
+ Splib.sleep(0.12)
130
155
  assert_equal(3, output.size)
131
156
  assert(!t.any?{|th|th.alive?})
132
157
  3.times{|i|assert_equal(i, output.shift)}
133
158
  end
134
-
159
+
135
160
  def test_lock_unlock_wakeup
136
161
  complete = false
137
- t1 = Thread.new{@monitor.lock; sleep(0.1); @monitor.unlock}
162
+ t1 = Thread.new{@monitor.lock; Splib.sleep(0.1); @monitor.unlock}
163
+ Splib.sleep(0.01)
138
164
  t2 = Thread.new{@monitor.lock; complete = true; @monitor.unlock}
139
165
  assert(!complete)
140
166
  assert(t1.alive?)
141
167
  t2.wakeup
142
168
  Thread.pass
143
169
  assert(!complete)
144
- sleep(0.11)
170
+ Splib.sleep(0.15)
145
171
  assert(complete)
146
172
  end
147
173
 
148
174
  def synchronize
149
175
  t = []
150
176
  output = []
151
- 5.times{|i| t << Thread.new{ @monitor.lock; sleep(i/100.0); output << i; @monitor.unlock;}}
177
+ 5.times{|i| t << Thread.new{ @monitor.lock; Splib.sleep(i/100.0); output << i; @monitor.unlock;}}
152
178
  @monitor.synchronize{ output << :done }
153
- sleep(0.5)
179
+ Splib.sleep(0.5)
154
180
  assert_equal(6, output.size)
155
181
  end
156
182
 
183
+ def test_try_lock
184
+ assert(@monitor.try_lock)
185
+ assert(@monitor.locked?)
186
+ assert(@monitor.try_lock)
187
+ Thread.new{ assert(!@monitor.try_lock) }
188
+ @monitor.unlock
189
+ assert(!@monitor.locked?)
190
+ Thread.new{ assert(@monitor.try_lock); @monitor.unlock }
191
+ end
192
+
157
193
  end
@@ -42,4 +42,32 @@ class PriorityQueueTest < Test::Unit::TestCase
42
42
  assert_equal('last', queue.pop)
43
43
  assert(queue.empty?)
44
44
  end
45
+
46
+ def test_raise
47
+ queue = Splib::PriorityQueue.new(:raise_on_empty)
48
+ assert_raise(Splib::EmptyQueue){ queue.pop }
49
+ end
50
+
51
+ def test_waiters
52
+ queue = Splib::PriorityQueue.new
53
+ q = Queue.new
54
+ t = Thread.new{ q << queue.pop; }
55
+ assert(t.alive?)
56
+ queue << :item1
57
+ sleep(0.1)
58
+ assert_equal(:item1, q.pop)
59
+ t = []
60
+ 5.times{ t << Thread.new{ q << queue.pop } }
61
+ sleep(0.1)
62
+ assert_equal(5, t.find_all{|x|x.alive?}.size)
63
+ queue << :item2
64
+ sleep(0.1)
65
+ assert_equal(1, q.size)
66
+ queue.push(:foo, :item3)
67
+ sleep(0.1)
68
+ assert_equal(2, q.size)
69
+ 3.times{ queue << :item4 }
70
+ sleep(0.1)
71
+ assert_equal(5, q.size)
72
+ end
45
73
  end
@@ -0,0 +1,24 @@
1
+ $:.unshift File.join(File.dirname(__FILE__),'..','lib')
2
+
3
+ require 'test/unit'
4
+ require 'splib'
5
+
6
+ class SleepTest < Test::Unit::TestCase
7
+ def setup
8
+ Splib.load :Sleep
9
+ end
10
+
11
+ def test_sleep_valid
12
+ assert(Splib.sleep(0.5).between?(0.45, 0.55))
13
+ assert(Splib.sleep(0.05).between?(0.04, 0.06))
14
+ end
15
+
16
+ def test_sleep_invalid
17
+ assert_raise(TypeError) do
18
+ Splib.sleep(:foo)
19
+ end
20
+ assert_raise(ArgumentError) do
21
+ Splib.sleep(-1)
22
+ end
23
+ end
24
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: splib
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.4.2
4
+ version: 1.4.3
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: 2010-01-29 00:00:00 -08:00
12
+ date: 2010-04-06 00:00:00 -07:00
13
13
  default_executable:
14
14
  dependencies: []
15
15
 
@@ -27,7 +27,7 @@ files:
27
27
  - README.rdoc
28
28
  - CHANGELOG
29
29
  - Rakefile
30
- - lib/splib.rb
30
+ - lib/splib
31
31
  - lib/splib/Array.rb
32
32
  - lib/splib/PriorityQueue.rb
33
33
  - lib/splib/UrlShorteners.rb
@@ -38,7 +38,10 @@ files:
38
38
  - lib/splib/HumanIdealRandomIterator.rb
39
39
  - lib/splib/Monitor.rb
40
40
  - lib/splib/Conversions.rb
41
+ - lib/splib/Sleep.rb
42
+ - lib/splib.rb
41
43
  - spec/dummy.rb
44
+ - test/cases
42
45
  - test/cases/Array.rb
43
46
  - test/cases/PriorityQueue.rb
44
47
  - test/cases/UrlShorteners.rb
@@ -49,13 +52,12 @@ files:
49
52
  - test/cases/HumanIdealRandomIterator.rb
50
53
  - test/cases/Monitor.rb
51
54
  - test/cases/Conversions.rb
55
+ - test/cases/Sleep.rb
52
56
  - test/run_tests.rb
53
57
  - test/samplecode2.rb
54
58
  - test/samplecode1.rb
55
- has_rdoc: true
59
+ has_rdoc: false
56
60
  homepage: http://github.com/spox/splib
57
- licenses: []
58
-
59
61
  post_install_message:
60
62
  rdoc_options:
61
63
  - --title
@@ -80,9 +82,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
80
82
  requirements: []
81
83
 
82
84
  rubyforge_project:
83
- rubygems_version: 1.3.5
85
+ rubygems_version: 1.3.1
84
86
  signing_key:
85
- specification_version: 3
87
+ specification_version: 2
86
88
  summary: Spox Library
87
89
  test_files: []
88
90