thread 0.1.7 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 3b410457cd8caaa3227527d9365650d3a02f8203
4
- data.tar.gz: 0430247c137897d69e59a88a6f57943cd58f46d5
3
+ metadata.gz: 6f1ac6a92f77e49dec38a35d8f17c607568f2702
4
+ data.tar.gz: 794e057cc2b9ea319f1051e13d7d69f7f61a92dd
5
5
  SHA512:
6
- metadata.gz: c55851e31ce9cc4897006df956bb3e5cff13418e9a294f0168cfdcf36e1deb4ccdf51b3559c53a513ad8d63d6836c23374c46db4ae26e3f061a1089db55a1754
7
- data.tar.gz: e91d1f1c0e483f2ed59bbe6966a1fd3604d2b8c082d6356e461d46233094c8d5c1415cf40b506ec22fd08027226af374d11a49621ebe0c74339021a5d7b857cc
6
+ metadata.gz: a8be737ccd11509f373d5a7c3d78a2e29fc1a0d6d414cac1a357ed4ee0472fa53f753de7f1cc4015cf453db34ddf42441f700c136566c8d17f65ce78a19ec810
7
+ data.tar.gz: 30461440ad2c050a41688c12e90bb7ce16df3bd706edb9f51d4bee4dd63dfa906f3e301da044f14be826f28a5ef740f9a2172495a17d6ab2122fb609d31fe2c5
@@ -5,6 +5,7 @@ rvm:
5
5
  - 1.9.3
6
6
  - 2.0.0
7
7
  - 2.1.0
8
+ - 2.2.1
8
9
  - ruby-head
9
10
  - jruby
10
- - rbx
11
+ - rbx
data/README.md CHANGED
@@ -174,7 +174,7 @@ require 'thread/pool'
174
174
  require 'thread/future'
175
175
 
176
176
  pool = Thread.pool 4
177
- f = pool {
177
+ f = pool.future {
178
178
  sleep 5
179
179
  42
180
180
  }
@@ -226,4 +226,4 @@ end
226
226
  3. Verify new and old specs are green (`rake`)
227
227
  4. Commit your changes (`git commit -am 'Add some feature'`)
228
228
  5. Push to the branch (`git push origin my-new-feature`)
229
- 6. Create a new Pull Request
229
+ 6. Create a new Pull Request
@@ -16,7 +16,7 @@ require 'thread'
16
16
  # messages are safe to be consumed.
17
17
  class Thread::Channel
18
18
  # Create a channel with optional initial messages and optional channel guard.
19
- def initialize (messages = [], &block)
19
+ def initialize(messages = [], &block)
20
20
  @messages = []
21
21
  @mutex = Mutex.new
22
22
  @check = block
@@ -30,7 +30,7 @@ class Thread::Channel
30
30
  #
31
31
  # If there's a guard, the value is passed to it, if the guard returns a falsy value
32
32
  # an ArgumentError exception is raised and the message is not sent.
33
- def send (what)
33
+ def send(what)
34
34
  if @check && !@check.call(what)
35
35
  raise ArgumentError, 'guard mismatch'
36
36
  end
@@ -47,7 +47,7 @@ class Thread::Channel
47
47
  # Receive a message, if there are none the call blocks until there's one.
48
48
  #
49
49
  # If a block is passed, it's used as guard to match to a message.
50
- def receive (&block)
50
+ def receive(&block)
51
51
  message = nil
52
52
  found = false
53
53
 
@@ -83,7 +83,7 @@ class Thread::Channel
83
83
  # Receive a message, if there are none the call returns nil.
84
84
  #
85
85
  # If a block is passed, it's used as guard to match to a message.
86
- def receive! (&block)
86
+ def receive!(&block)
87
87
  if block
88
88
  @messages.delete_at(@messages.find_index(&block))
89
89
  else
@@ -91,7 +91,7 @@ class Thread::Channel
91
91
  end
92
92
  end
93
93
 
94
- private
94
+ private
95
95
  def cond?
96
96
  instance_variable_defined? :@cond
97
97
  end
@@ -103,7 +103,7 @@ end
103
103
 
104
104
  class Thread
105
105
  # Helper to create a channel.
106
- def self.channel (*args, &block)
106
+ def self.channel(*args, &block)
107
107
  Thread::Channel.new(*args, &block)
108
108
  end
109
109
  end
@@ -18,7 +18,7 @@ class Thread::Every
18
18
  Restart = Class.new(Exception)
19
19
 
20
20
  # Create an every with the given seconds and block.
21
- def initialize (every, &block)
21
+ def initialize(every, &block)
22
22
  raise ArgumentError, 'no block given' unless block
23
23
 
24
24
  @every = every
@@ -67,14 +67,14 @@ class Thread::Every
67
67
  end
68
68
 
69
69
  # @private
70
- def self.finalizer (thread)
70
+ def self.finalizer(thread)
71
71
  proc {
72
72
  thread.raise Cancel.new
73
73
  }
74
74
  end
75
75
 
76
76
  # Change the number of seconds between each call.
77
- def every (seconds)
77
+ def every(seconds)
78
78
  @every = seconds
79
79
 
80
80
  restart
@@ -144,7 +144,7 @@ class Thread::Every
144
144
  end
145
145
 
146
146
  # Gets the current every value.
147
- def value (timeout = nil)
147
+ def value(timeout = nil)
148
148
  @mutex.synchronize {
149
149
  if @old
150
150
  cond.wait(@mutex, *timeout)
@@ -172,7 +172,7 @@ class Thread::Every
172
172
  }
173
173
  end
174
174
 
175
- private
175
+ private
176
176
  def cond?
177
177
  instance_variable_defined? :@cond
178
178
  end
@@ -184,14 +184,14 @@ end
184
184
 
185
185
  class Thread
186
186
  # Helper to create an every
187
- def self.every (every, &block)
187
+ def self.every(every, &block)
188
188
  Thread::Every.new(every, &block)
189
189
  end
190
190
  end
191
191
 
192
192
  module Kernel
193
193
  # Helper to create an every
194
- def every (every, &block)
194
+ def every(every, &block)
195
195
  Thread::Every.new(every, &block)
196
196
  end
197
197
  end
@@ -17,7 +17,7 @@ class Thread::Future
17
17
  Cancel = Class.new(Exception)
18
18
 
19
19
  # Create a future with the passed block and optionally using the passed pool.
20
- def initialize (pool = nil, &block)
20
+ def initialize(pool = nil, &block)
21
21
  raise ArgumentError, 'no block given' unless block
22
22
 
23
23
  @mutex = Mutex.new
@@ -38,7 +38,7 @@ class Thread::Future
38
38
  end
39
39
 
40
40
  # @private
41
- def self.finalizer (thread)
41
+ def self.finalizer(thread)
42
42
  proc {
43
43
  thread.raise Cancel.new
44
44
  }
@@ -92,7 +92,7 @@ class Thread::Future
92
92
  #
93
93
  # An optional timeout can be passed which will return nil if nothing has been
94
94
  # delivered.
95
- def value (timeout = nil)
95
+ def value(timeout = nil)
96
96
  raise @exception if exception?
97
97
 
98
98
  return @value if delivered?
@@ -111,7 +111,7 @@ class Thread::Future
111
111
  alias ~ value
112
112
 
113
113
  # Do the same as {#value}, but return nil in case of exception.
114
- def value! (timeout = nil)
114
+ def value!(timeout = nil)
115
115
  begin
116
116
  value(timeout)
117
117
  rescue Exception
@@ -121,7 +121,7 @@ class Thread::Future
121
121
 
122
122
  alias ! value!
123
123
 
124
- private
124
+ private
125
125
  def cond?
126
126
  instance_variable_defined? :@cond
127
127
  end
@@ -145,20 +145,20 @@ end
145
145
 
146
146
  class Thread
147
147
  # Helper to create a future
148
- def self.future (pool = nil, &block)
148
+ def self.future(pool = nil, &block)
149
149
  Thread::Future.new(pool, &block)
150
150
  end
151
151
  end
152
152
 
153
153
  module Kernel
154
154
  # Helper to create a future.
155
- def future (pool = nil, &block)
155
+ def future(pool = nil, &block)
156
156
  Thread::Future.new(pool, &block)
157
157
  end
158
158
  end
159
159
 
160
160
  class Thread::Pool
161
- def future (&block)
161
+ def future(&block)
162
162
  Thread.future self, &block
163
163
  end
164
164
  end
@@ -20,7 +20,7 @@ class Thread::Pipe
20
20
 
21
21
  # Create a Task which will call the passed function and get input
22
22
  # from the optional parameter and put output in the optional parameter.
23
- def initialize (func, input = Queue.new, output = Queue.new)
23
+ def initialize(func, input = Queue.new, output = Queue.new)
24
24
  @input = input
25
25
  @output = output
26
26
  @handling = false
@@ -54,7 +54,7 @@ class Thread::Pipe
54
54
  # output queue.
55
55
  #
56
56
  # The objects must respond to #enq and #deq, and block on #deq.
57
- def initialize (input = Queue.new, output = Queue.new)
57
+ def initialize(input = Queue.new, output = Queue.new)
58
58
  @tasks = []
59
59
 
60
60
  @input = input
@@ -64,7 +64,7 @@ class Thread::Pipe
64
64
  end
65
65
 
66
66
  # @private
67
- def self.finalizer (tasks)
67
+ def self.finalizer(tasks)
68
68
  proc {
69
69
  tasks.each(&:kill)
70
70
  }
@@ -72,7 +72,7 @@ class Thread::Pipe
72
72
 
73
73
  # Add a task to the pipe, it must respond to #call and #arity,
74
74
  # and #arity must return 1.
75
- def | (func)
75
+ def |(func)
76
76
  if func.arity != 1
77
77
  raise ArgumentError, 'wrong arity'
78
78
  end
@@ -91,7 +91,7 @@ class Thread::Pipe
91
91
  end
92
92
 
93
93
  # Insert data in the pipe.
94
- def enq (data)
94
+ def enq(data)
95
95
  return if @tasks.empty?
96
96
 
97
97
  @input.enq data
@@ -103,7 +103,7 @@ class Thread::Pipe
103
103
  alias << enq
104
104
 
105
105
  # Get an element from the output queue.
106
- def deq (non_block = false)
106
+ def deq(non_block = false)
107
107
  @output.deq(non_block)
108
108
  end
109
109
 
@@ -113,7 +113,7 @@ end
113
113
 
114
114
  class Thread
115
115
  # Helper to create a pipe.
116
- def self.| (func)
116
+ def self.|(func)
117
117
  Pipe.new | func
118
118
  end
119
119
  end
@@ -22,11 +22,11 @@ class Thread::Pool
22
22
  Timeout = Class.new(Exception)
23
23
  Asked = Class.new(Exception)
24
24
 
25
- attr_reader :pool, :timeout, :exception, :thread, :started_at
25
+ attr_reader :pool, :timeout, :exception, :thread, :started_at, :result
26
26
 
27
27
  # Create a task in the given pool which will pass the arguments to the
28
28
  # block.
29
- def initialize (pool, *args, &block)
29
+ def initialize(pool, *args, &block)
30
30
  @pool = pool
31
31
  @arguments = args
32
32
  @block = block
@@ -37,23 +37,34 @@ class Thread::Pool
37
37
  @terminated = false
38
38
  end
39
39
 
40
- def running?; @running; end
41
- def finished?; @finished; end
42
- def timeout?; @timedout; end
43
- def terminated?; @terminated; end
40
+ def running?
41
+ @running
42
+ end
43
+
44
+ def finished?
45
+ @finished
46
+ end
47
+
48
+ def timeout?
49
+ @timedout
50
+ end
51
+
52
+ def terminated?
53
+ @terminated
54
+ end
44
55
 
45
- # Execute the task in the given thread.
46
- def execute (thread)
56
+ # Execute the task.
57
+ def execute
47
58
  return if terminated? || running? || finished?
48
59
 
49
- @thread = thread
60
+ @thread = Thread.current
50
61
  @running = true
51
62
  @started_at = Time.now
52
63
 
53
64
  pool.__send__ :wake_up_timeout
54
65
 
55
66
  begin
56
- @block.call(*@arguments)
67
+ @result = @block.call(*@arguments)
57
68
  rescue Exception => reason
58
69
  if reason.is_a? Timeout
59
70
  @timedout = true
@@ -71,12 +82,12 @@ class Thread::Pool
71
82
  end
72
83
 
73
84
  # Raise an exception in the thread used by the task.
74
- def raise (exception)
85
+ def raise(exception)
75
86
  @thread.raise(exception)
76
87
  end
77
88
 
78
89
  # Terminate the exception with an optionally given exception.
79
- def terminate! (exception = Asked)
90
+ def terminate!(exception = Asked)
80
91
  return if terminated? || finished? || timeout?
81
92
 
82
93
  @terminated = true
@@ -92,10 +103,10 @@ class Thread::Pool
92
103
  end
93
104
 
94
105
  # Timeout the task after the given time.
95
- def timeout_after (time)
106
+ def timeout_after(time)
96
107
  @timeout = time
97
108
 
98
- pool.timeout_for self, time
109
+ pool.__send__ :timeout_for, self, time
99
110
 
100
111
  self
101
112
  end
@@ -110,7 +121,7 @@ class Thread::Pool
110
121
  #
111
122
  # A default block can be passed, which will be used to {#process} the passed
112
123
  # data.
113
- def initialize (min, max = nil, &block)
124
+ def initialize(min, max = nil, &block)
114
125
  @min = min
115
126
  @max = max || min
116
127
  @block = block
@@ -140,7 +151,9 @@ class Thread::Pool
140
151
  end
141
152
 
142
153
  # Check if the pool has been shut down.
143
- def shutdown?; !!@shutdown; end
154
+ def shutdown?
155
+ !!@shutdown
156
+ end
144
157
 
145
158
  # Check if auto trimming is enabled.
146
159
  def auto_trim?
@@ -151,11 +164,15 @@ class Thread::Pool
151
164
  # is reached.
152
165
  def auto_trim!
153
166
  @auto_trim = true
167
+
168
+ self
154
169
  end
155
170
 
156
171
  # Disable auto trimming.
157
172
  def no_auto_trim!
158
173
  @auto_trim = false
174
+
175
+ self
159
176
  end
160
177
 
161
178
  # Check if idle trimming is enabled.
@@ -167,15 +184,19 @@ class Thread::Pool
167
184
  # The minimum number of threads is respeced.
168
185
  def idle_trim!(timeout)
169
186
  @idle_trim = timeout
187
+
188
+ self
170
189
  end
171
190
 
172
191
  # Turn of idle trimming.
173
192
  def no_idle_trim!
174
193
  @idle_trim = nil
194
+
195
+ self
175
196
  end
176
197
 
177
198
  # Resize the pool with the passed arguments.
178
- def resize (min, max = nil)
199
+ def resize(min, max = nil)
179
200
  @min = min
180
201
  @max = max || min
181
202
 
@@ -200,9 +221,9 @@ class Thread::Pool
200
221
  def wait(what = :idle)
201
222
  case what
202
223
  when :done
203
- loop do
224
+ until done?
204
225
  @done_mutex.synchronize {
205
- return self if _done?
226
+ break if _done?
206
227
 
207
228
  @done.wait @done_mutex
208
229
  }
@@ -233,15 +254,7 @@ class Thread::Pool
233
254
  #
234
255
  # If no block is passed the default block will be used if present, an
235
256
  # ArgumentError will be raised otherwise.
236
- def process (*args, &block)
237
- unless block || @block
238
- raise ArgumentError, 'you must pass a block'
239
- end
240
-
241
- wait.process!(*args, &block)
242
- end
243
-
244
- def process! (*args, &block)
257
+ def process(*args, &block)
245
258
  unless block || @block
246
259
  raise ArgumentError, 'you must pass a block'
247
260
  end
@@ -263,11 +276,11 @@ class Thread::Pool
263
276
  task
264
277
  end
265
278
 
266
- alias << process!
279
+ alias << process
267
280
 
268
281
  # Trim the unused threads, if forced threads will be trimmed even if there
269
282
  # are tasks waiting.
270
- def trim (force = false)
283
+ def trim(force = false)
271
284
  @mutex.synchronize {
272
285
  if (force || @waiting > 0) && @spawned - @trim_requests > @min
273
286
  @trim_requests += 1
@@ -302,52 +315,28 @@ class Thread::Pool
302
315
  @cond.broadcast
303
316
  }
304
317
 
305
- join
306
-
307
- if @timeout
308
- @shutdown = :now
309
-
310
- wake_up_timeout
311
-
312
- @timeout.join
313
- end
314
-
315
- self
316
- end
317
-
318
- # Join on all threads in the pool.
319
- def join
320
318
  until @workers.empty?
321
319
  if worker = @workers.first
322
320
  worker.join
323
321
  end
324
322
  end
325
323
 
326
- self
327
- end
328
-
329
- # Define a timeout for a task.
330
- def timeout_for (task, timeout)
331
- unless @timeout
332
- spawn_timeout_thread
333
- end
334
-
335
- @mutex.synchronize {
336
- @timeouts[task] = timeout
324
+ if @timeout
325
+ @shutdown = :now
337
326
 
338
327
  wake_up_timeout
339
- }
328
+
329
+ @timeout.join
330
+ end
340
331
  end
341
332
 
342
333
  # Shutdown the pool after a given amount of time.
343
- def shutdown_after (timeout)
334
+ def shutdown_after(timeout)
344
335
  Thread.new {
345
336
  sleep timeout
346
337
 
347
338
  shutdown
348
339
  }
349
-
350
- self
351
340
  end
352
341
 
353
342
  class << self
@@ -358,6 +347,18 @@ class Thread::Pool
358
347
  end
359
348
 
360
349
  private
350
+ def timeout_for(task, timeout)
351
+ unless @timeout
352
+ spawn_timeout_thread
353
+ end
354
+
355
+ @mutex.synchronize {
356
+ @timeouts[task] = timeout
357
+
358
+ wake_up_timeout
359
+ }
360
+ end
361
+
361
362
  def wake_up_timeout
362
363
  if defined? @pipes
363
364
  @pipes.last.write_nonblock 'x' rescue nil
@@ -401,7 +402,7 @@ private
401
402
  @todo.shift
402
403
  } or break
403
404
 
404
- task.execute(thread)
405
+ task.execute
405
406
 
406
407
  break if @shutdown == :now
407
408
 
@@ -471,7 +472,7 @@ end
471
472
 
472
473
  class Thread
473
474
  # Helper to create a pool.
474
- def self.pool (*args, &block)
475
+ def self.pool(*args, &block)
475
476
  Thread::Pool.new(*args, &block)
476
477
  end
477
478
  end
@@ -17,20 +17,20 @@ class Thread::Process
17
17
  @@processes ||= {}
18
18
  end
19
19
 
20
- def self.register (name, process)
20
+ def self.register(name, process)
21
21
  all[name] = process
22
22
  end
23
23
 
24
- def self.unregister (name)
24
+ def self.unregister(name)
25
25
  all.delete(name)
26
26
  end
27
27
 
28
- def self.[] (name)
28
+ def self.[](name)
29
29
  all[name]
30
30
  end
31
31
 
32
32
  # Create a new process executing the block.
33
- def initialize (&block)
33
+ def initialize(&block)
34
34
  @channel = Thread::Channel.new
35
35
 
36
36
  Thread.new {
@@ -41,7 +41,7 @@ class Thread::Process
41
41
  end
42
42
 
43
43
  # Send a message to the process.
44
- def send (what)
44
+ def send(what)
45
45
  unless @channel
46
46
  raise RuntimeError, 'the process has terminated'
47
47
  end
@@ -53,7 +53,7 @@ class Thread::Process
53
53
 
54
54
  alias << send
55
55
 
56
- private
56
+ private
57
57
  def receive
58
58
  @channel.receive
59
59
  end
@@ -65,7 +65,7 @@ end
65
65
 
66
66
  class Thread
67
67
  # Helper to create a process.
68
- def self.process (&block)
68
+ def self.process(&block)
69
69
  Thread::Process.new(&block)
70
70
  end
71
71
  end
@@ -27,7 +27,7 @@ class Thread::Promise
27
27
  alias realized? delivered?
28
28
 
29
29
  # Deliver a value.
30
- def deliver (value)
30
+ def deliver(value)
31
31
  return self if delivered?
32
32
 
33
33
  @mutex.synchronize {
@@ -46,7 +46,7 @@ class Thread::Promise
46
46
  #
47
47
  # An optional timeout can be passed which will return nil if nothing has been
48
48
  # delivered.
49
- def value (timeout = nil)
49
+ def value(timeout = nil)
50
50
  return @value if delivered?
51
51
 
52
52
  @mutex.synchronize {
@@ -58,7 +58,7 @@ class Thread::Promise
58
58
 
59
59
  alias ~ value
60
60
 
61
- private
61
+ private
62
62
  def cond?
63
63
  instance_variable_defined? :@cond
64
64
  end
@@ -0,0 +1,78 @@
1
+ require 'thread/pool'
2
+
3
+ describe Thread::Pool do
4
+ it 'creates a new pool with the given amount of threads' do
5
+ pool = Thread.pool(4)
6
+
7
+ expect(pool.spawned).to eq(4)
8
+
9
+ pool.shutdown
10
+ end
11
+
12
+ it 'creates a new pool with the given amount of threads without spawning more than min' do
13
+ pool = Thread.pool(4, 8)
14
+
15
+ expect(pool.spawned).to eq(4)
16
+
17
+ pool.shutdown
18
+ end
19
+
20
+ it 'properly reports the backlog length' do
21
+ pool = Thread.pool(2)
22
+
23
+ pool.process { sleep 0.5 }
24
+ pool.process { sleep 0.5 }
25
+ pool.process { sleep 0.5 }
26
+
27
+ sleep 0.25
28
+
29
+ expect(pool.backlog).to eq(1)
30
+
31
+ pool.shutdown
32
+ end
33
+
34
+ it 'properly reports the pool is done' do
35
+ pool = Thread.pool(2)
36
+
37
+ pool.process { sleep 0.25 }
38
+ pool.process { sleep 0.25 }
39
+ pool.process { sleep 0.25 }
40
+
41
+ expect(pool.done?).to be(false)
42
+
43
+ sleep 0.75
44
+
45
+ expect(pool.done?).to be(true)
46
+
47
+ pool.shutdown
48
+ end
49
+
50
+ it 'properly reports the pool is idle' do
51
+ pool = Thread.pool(2)
52
+
53
+ pool.process { sleep 0.25 }
54
+ pool.process { sleep 0.5 }
55
+
56
+ expect(pool.idle?).to be(false)
57
+
58
+ sleep 0.30
59
+
60
+ expect(pool.idle?).to be(true)
61
+
62
+ pool.shutdown
63
+ end
64
+
65
+ it 'properly shutdowns the pool' do
66
+ result = []
67
+ pool = Thread.pool(4)
68
+
69
+ pool.process { sleep 0.1; result << 1 }
70
+ pool.process { sleep 0.2; result << 2 }
71
+ pool.process { sleep 0.3; result << 3 }
72
+ pool.process { sleep 0.4; result << 4 }
73
+
74
+ pool.shutdown
75
+
76
+ expect(result).to eq([1, 2, 3, 4])
77
+ end
78
+ end
@@ -4,7 +4,7 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
4
 
5
5
  Gem::Specification.new do |spec|
6
6
  spec.name = "thread"
7
- spec.version = "0.1.7"
7
+ spec.version = "0.2.0"
8
8
  spec.authors = ["meh."]
9
9
  spec.email = ["meh@schizofreni.co"]
10
10
  spec.summary = %q{Various extensions to the base thread library.}
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: thread
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.7
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - meh.
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-04-08 00:00:00.000000000 Z
11
+ date: 2015-04-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rspec
@@ -67,6 +67,7 @@ files:
67
67
  - spec/thread/every_spec.rb
68
68
  - spec/thread/future_spec.rb
69
69
  - spec/thread/pipe_spec.rb
70
+ - spec/thread/pool_spec.rb
70
71
  - spec/thread/promise_spec.rb
71
72
  - thread.gemspec
72
73
  homepage: http://github.com/meh/ruby-thread
@@ -99,5 +100,6 @@ test_files:
99
100
  - spec/thread/every_spec.rb
100
101
  - spec/thread/future_spec.rb
101
102
  - spec/thread/pipe_spec.rb
103
+ - spec/thread/pool_spec.rb
102
104
  - spec/thread/promise_spec.rb
103
105
  has_rdoc: