in_threads 0.0.4 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,11 @@
1
+ /pkg/
2
+
3
+ /doc/
4
+ /rdoc/
5
+ /.yardoc/
6
+ /coverage/
7
+
8
+ Makefile
9
+ *.o
10
+ *.bundle
11
+ /tmp/
data/LICENSE.txt CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2010 Ivan Kuchin
1
+ Copyright (c) 2010-2011 Ivan Kuchin
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining
4
4
  a copy of this software and associated documentation files (the
data/README.markdown CHANGED
@@ -1,42 +1,35 @@
1
- # progress
1
+ # in_threads
2
2
 
3
- http://github.com/toy/in_threads
3
+ Easily execute ruby code in parallel.
4
4
 
5
- ## DESCRIPTION:
5
+ ## Installation
6
6
 
7
- Easily execute ruby code in parallel
7
+ gem install in_threads
8
8
 
9
- ## SYNOPSIS:
9
+ ## Usage
10
10
 
11
11
  By default there is maximum of 10 simultaneous threads
12
12
 
13
- urls.in_threads.each do |url|
14
- url.save_to_disk
15
- end
16
-
17
13
  urls.in_threads.map do |url|
18
14
  url.fetch
19
15
  end
20
16
 
17
+ urls.in_threads.each do |url|
18
+ url.save_to_disk
19
+ end
20
+
21
21
  numbers.in_threads(2).map do |number|
22
-
23
22
  # whery long and complicated formula
24
23
  # using only 2 threads
25
24
  end
26
25
 
27
- You can use any Enumerable method but it is up to you if this is good
26
+ You can use any Enumerable method, but some of them can not use threads (`inject`, `reduce`) or don't use blocks (`to_a`, `entries`, `drop`, `take`, `first`, `include?`, `member?`) or have both problems depending on usage type (`min`, `max`, `minmax`, `sort`)
28
27
 
29
28
  urls.in_threads.any?(&:ok?)
30
29
  urls.in_threads.all?(&:ok?)
31
-
32
- ## REQUIREMENTS:
33
-
34
- ruby )))
35
-
36
- ## INSTALL:
37
-
38
- sudo gem install in_threads
30
+ urls.in_threads.none?(&:error?)
31
+ urls.in_threads.grep(/example\.com/, &:fetch)
39
32
 
40
33
  ## Copyright
41
34
 
42
- Copyright (c) 2010 Ivan Kuchin. See LICENSE.txt for details.
35
+ Copyright (c) 2010-2011 Ivan Kuchin. See LICENSE.txt for details.
data/in_threads.gemspec CHANGED
@@ -1,57 +1,19 @@
1
- # Generated by jeweler
2
- # DO NOT EDIT THIS FILE DIRECTLY
3
- # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4
- # -*- encoding: utf-8 -*-
1
+ # encoding: UTF-8
5
2
 
6
3
  Gem::Specification.new do |s|
7
- s.name = %q{in_threads}
8
- s.version = "0.0.4"
4
+ s.name = 'in_threads'
5
+ s.version = '1.0.0'
6
+ s.summary = %q{Execute ruby code in parallel}
7
+ s.homepage = "http://github.com/toy/#{s.name}"
8
+ s.authors = ['Ivan Kuchin']
9
+ s.license = 'MIT'
9
10
 
10
- s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
- s.authors = ["Ivan Kuchin"]
12
- s.date = %q{2010-12-15}
13
- s.extra_rdoc_files = [
14
- "LICENSE.txt",
15
- "README.markdown"
16
- ]
17
- s.files = [
18
- ".tmignore",
19
- "LICENSE.txt",
20
- "README.markdown",
21
- "Rakefile",
22
- "VERSION",
23
- "in_threads.gemspec",
24
- "lib/in_threads.rb",
25
- "spec/in_threads_spec.rb",
26
- "spec/spec_helper.rb"
27
- ]
28
- s.homepage = %q{http://github.com/toy/in_threads}
29
- s.licenses = ["MIT"]
30
- s.require_paths = ["lib"]
31
- s.rubygems_version = %q{1.3.7}
32
- s.summary = %q{Execute ruby blocks in parallel}
33
- s.test_files = [
34
- "spec/in_threads_spec.rb",
35
- "spec/spec_helper.rb"
36
- ]
11
+ s.rubyforge_project = s.name
37
12
 
38
- if s.respond_to? :specification_version then
39
- current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
40
- s.specification_version = 3
13
+ s.files = `git ls-files`.split("\n")
14
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
15
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
16
+ s.require_paths = %w[lib]
41
17
 
42
- if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
43
- s.add_development_dependency(%q<jeweler>, ["~> 1.5.1"])
44
- s.add_development_dependency(%q<rake-gem-ghost>, [">= 0"])
45
- s.add_development_dependency(%q<rspec>, [">= 0"])
46
- else
47
- s.add_dependency(%q<jeweler>, ["~> 1.5.1"])
48
- s.add_dependency(%q<rake-gem-ghost>, [">= 0"])
49
- s.add_dependency(%q<rspec>, [">= 0"])
50
- end
51
- else
52
- s.add_dependency(%q<jeweler>, ["~> 1.5.1"])
53
- s.add_dependency(%q<rake-gem-ghost>, [">= 0"])
54
- s.add_dependency(%q<rspec>, [">= 0"])
55
- end
18
+ s.add_development_dependency 'rspec'
56
19
  end
57
-
data/lib/in_threads.rb CHANGED
@@ -2,37 +2,137 @@ require 'thread'
2
2
  require 'thwait'
3
3
 
4
4
  module Enumerable
5
- def in_threads(max_threads = 10)
6
- InThreads.new(self, max_threads)
5
+ # Run enumerable method blocks in threads
6
+ def in_threads(thread_count = 10, &block)
7
+ InThreads.new(self, thread_count, &block)
7
8
  end
8
9
  end
9
10
 
11
+ # TODO: create my own ThreadsWait with blackjack and hookers?
12
+ # TODO: create class methods for connecting Enumerable method to runner
13
+ # TODO: run_in_threads_inconsecutive for `all?`, `any?`, `none?` and `one?`
14
+ # TODO: all ruby1.9.3 methods
15
+ # TODO: better way of handling grep?
16
+ # TODO: check method presence if Enumerable before connectin to runner
17
+
10
18
  class InThreads
11
- def initialize(object, max_threads)
12
- @threads = []
13
- @object = object
14
- @max_threads = max_threads
19
+ (
20
+ instance_methods.map(&:to_s) -
21
+ %w[__id__ __send__ class inspect instance_of? is_a? kind_of? nil? object_id respond_to? send]
22
+ ).each{ |name| undef_method name }
23
+ (private_instance_methods.map(&:to_s) - %w[initialize]).each{ |name| undef_method name }
24
+
25
+ attr_reader :enumerable, :thread_count
26
+ def initialize(enumerable, thread_count = 10, &block)
27
+ @enumerable, @thread_count = enumerable, thread_count
28
+ each(&block) if block
29
+ end
30
+
31
+ def in_threads(thread_count = 10, &block)
32
+ self.class.new(enumerable, thread_count, &block)
33
+ end
34
+
35
+ %w[
36
+ each
37
+ all? any? none? one?
38
+ detect find find_index drop_while take_while
39
+ partition find_all select reject count
40
+ collect map group_by max_by min_by minmax_by sort_by
41
+ ].each do |name|
42
+ class_eval <<-RUBY
43
+ def #{name}(*args, &block)
44
+ run_in_threads_consecutive(enumerable, :#{name}, *args, &block)
45
+ end
46
+ RUBY
47
+ end
48
+
49
+ %w[
50
+ reverse_each
51
+ each_with_index enum_with_index
52
+ each_cons each_slice enum_cons enum_slice
53
+ zip
54
+ cycle
55
+ ].each do |name|
56
+ class_eval <<-RUBY
57
+ def #{name}(*args, &block)
58
+ run_in_threads_block_result_irrelevant(enumerable, :#{name}, *args, &block)
59
+ end
60
+ RUBY
15
61
  end
16
62
 
17
- def map(*args, &block)
18
- run_in_threads(:map, *args, &block)
19
- @threads.map(&:value)
63
+ def grep(*args, &block)
64
+ if block
65
+ run_in_threads_consecutive(enumerable.grep(*args), :map, &block)
66
+ else
67
+ enumerable.grep(*args)
68
+ end
20
69
  end
21
70
 
22
- def method_missing(method, *args, &block)
23
- run_in_threads(method, *args, &block)
71
+ %w[
72
+ inject reduce
73
+ max min minmax sort
74
+ entries to_a
75
+ drop take
76
+ first
77
+ include? member?
78
+ ].each do |name|
79
+ class_eval <<-RUBY
80
+ def #{name}(*args, &block)
81
+ enumerable.#{name}(*args, &block)
82
+ end
83
+ RUBY
24
84
  end
25
85
 
26
86
  private
27
87
 
28
- def run_in_threads(method, *args, &block)
29
- @object.send(method, *args) do |*args|
30
- while @threads.count(&:alive?) >= @max_threads
31
- ThreadsWait.new(*@threads).next_wait
88
+ def run_in_threads_block_result_irrelevant(enumerable, method, *args, &block)
89
+ if block
90
+ waiter = ThreadsWait.new
91
+ begin
92
+ enumerable.send(method, *args) do |*block_args|
93
+ waiter.next_wait if waiter.threads.length >= thread_count
94
+ waiter.join_nowait([Thread.new(*block_args, &block)])
95
+ end
96
+ ensure
97
+ waiter.all_waits
98
+ end
99
+ else
100
+ enumerable.send(method, *args)
101
+ end
102
+ end
103
+
104
+ def run_in_threads_consecutive(enumerable, method, *args, &block)
105
+ if block
106
+ begin
107
+ queue = Queue.new
108
+ runner = Thread.new(enumerable) do |enumerable|
109
+ threads = []
110
+ begin
111
+ enumerable.each do |object|
112
+ if threads.length >= thread_count
113
+ threads = threads.select(&:alive?)
114
+ if threads.length >= thread_count
115
+ ThreadsWait.new(*threads).next_wait
116
+ end
117
+ end
118
+ break if Thread.current[:stop]
119
+ thread = Thread.new(object, &block)
120
+ threads << thread
121
+ queue << thread
122
+ end
123
+ ensure
124
+ threads.map(&:join)
125
+ end
126
+ end
127
+ enumerable.send(method, *args) do |*block_args|
128
+ queue.pop.value
129
+ end
130
+ ensure
131
+ runner[:stop] = true
132
+ runner.join
32
133
  end
33
- @threads << Thread.new(*args, &block)
134
+ else
135
+ enumerable.send(method, *args)
34
136
  end
35
- ensure
36
- @threads.map(&:join)
37
137
  end
38
138
  end
@@ -1,57 +1,355 @@
1
1
  require File.dirname(__FILE__) + '/spec_helper.rb'
2
2
 
3
- describe InThreads do
4
- before :each do
5
- srand 1
6
- @a = (1..30).map{ |i| mock(:"e#{i}", :hello => nil, :value => i, :rand => rand * 0.01) }
7
- @sleepy_prock = proc{ |e| sleep(e.rand); e.hello; e.value }
8
- @sleepy_prock_a = proc{ |e| sleep(e.inject{ |sum, e| e.rand }); e.hash }
3
+ class Item
4
+ def initialize(i)
5
+ @i, @rand = i, rand
9
6
  end
10
7
 
8
+ class MiddleMatcher
9
+ def ===(item)
10
+ raise "#{item.inspect} is not an Item" unless item.is_a?(Item)
11
+ (0.25..0.75) === item.instance_variable_get(:@rand)
12
+ end
13
+ end
14
+
15
+ def work
16
+ sleep @rand * 0.008
17
+ end
18
+
19
+ def value
20
+ work; @rand
21
+ end
22
+
23
+ def check?
24
+ value < 0.5
25
+ end
26
+
27
+ def touch_n_value(*args)
28
+ touch(*args); value
29
+ end
30
+
31
+ def touch_n_check?(*args)
32
+ touch(*args); check?
33
+ end
34
+ end
35
+
36
+ class ValueItem < Item
37
+ def initialize(i, value)
38
+ super(i)
39
+ @value = value
40
+ end
41
+
42
+ def value
43
+ work; @value
44
+ end
45
+
46
+ def check?
47
+ !!value
48
+ end
49
+ end
50
+
51
+ def enum_methods(methods)
52
+ (Enumerable.instance_methods.map(&:to_s) & methods)
53
+ end
54
+
55
+ describe "in_threads" do
56
+ let(:enum){ 30.times.map{ |i| Item.new(i) } }
57
+ let(:speed_coef){ 0.666 } # small coefficient, should be more if sleep time coefficient is bigger
58
+
11
59
  def measure
12
60
  start = Time.now
13
61
  yield
14
62
  Time.now - start
15
63
  end
16
64
 
17
- it "should execute block for each element" do
18
- @a.each{ |e| e.should_receive(:hello) }
19
- @a.in_threads.each(&:hello)
65
+ describe "in_threads" do
66
+ it "should not change existing instance" do
67
+ threaded = enum.in_threads(10)
68
+ proc{ threaded.in_threads(20) }.should_not change(threaded, :thread_count)
69
+ end
70
+
71
+ it "should create new instance with different title when called on WithProgress" do
72
+ threaded = enum.in_threads(10)
73
+ tthreaded = threaded.in_threads(20)
74
+ threaded.thread_count.should == 10
75
+ tthreaded.thread_count.should == 20
76
+ tthreaded.class.should == threaded.class
77
+ tthreaded.object_id.should_not == threaded.object_id
78
+ tthreaded.enumerable.should == threaded.enumerable
79
+ end
20
80
  end
21
81
 
22
- it "should not run simulanteously more threads" do
23
- @mutex = Mutex.new
24
- @threads = 0
25
- (1..100).to_a.in_threads(10).each do |i|
26
- (0..10).include?(@threads).should be_true
27
- @mutex.synchronize{ @threads += 1 }
28
- (0..10).include?(@threads).should be_true
29
- sleep 1 + rand * 1
30
- (0..10).include?(@threads).should be_true
31
- @mutex.synchronize{ @threads -= 1 }
32
- (0..10).include?(@threads).should be_true
82
+ describe "each" do
83
+ it "should return same enum after running" do
84
+ enum.in_threads.each(&:value).should == enum
85
+ end
86
+
87
+ it "should execute block for each element" do
88
+ enum.each{ |o| o.should_receive(:touch).once }
89
+ enum.in_threads.each(&:touch)
90
+ end
91
+
92
+ it "should run faster with threads" do
93
+ measure{ enum.in_threads.each(&:work) }.should < measure{ enum.each(&:work) } * speed_coef
94
+ end
95
+
96
+ it "should run faster with more threads" do
97
+ measure{ enum.in_threads(20).each(&:work) }.should < measure{ enum.in_threads(2).each(&:work) } * speed_coef
98
+ end
99
+
100
+ it "should return same enum without block" do
101
+ enum.in_threads.each.to_a.should == enum.each.to_a
33
102
  end
34
103
  end
35
104
 
36
- it "should run faster than without threads" do
37
- (measure{ @a.in_threads.each(&@sleepy_prock) } * 2).should be < measure{ @a.each(&@sleepy_prock) }
105
+ enum_methods(%w[each_with_index enum_with_index]).each do |method|
106
+ describe method do
107
+ let(:runner){ proc{ |o, i| o.value } }
108
+
109
+ it "should return same result with threads" do
110
+ enum.in_threads.send(method, &runner).should == enum.send(method, &runner)
111
+ end
112
+
113
+ it "should fire same objects" do
114
+ enum.send(method){ |o, i| o.should_receive(:touch).with(i).once }
115
+ enum.in_threads.send(method){ |o, i| o.touch_n_value(i) }
116
+ end
117
+
118
+ it "should run faster with threads" do
119
+ measure{ enum.in_threads.send(method, &runner) }.should < measure{ enum.send(method, &runner) } * speed_coef
120
+ end
121
+
122
+ it "should return same enum without block" do
123
+ enum.in_threads.send(method).to_a.should == enum.send(method).to_a
124
+ end
125
+ end
38
126
  end
39
127
 
40
- it "should run not much slower than max of block running times if ran simultaneously" do
41
- measure{ (1..95).in_threads(100).each{ |i| sleep(i * 0.01) } }.should be < 1.0
128
+ describe "reverse_each" do
129
+ it "should return same result with threads" do
130
+ enum.in_threads.reverse_each(&:value).should == enum.reverse_each(&:value)
131
+ end
132
+
133
+ it "should fire same objects in reverse order" do
134
+ @order = mock('order', :touch => nil)
135
+ @order.should_receive(:touch).with(enum.last).ordered
136
+ @order.should_receive(:touch).with(enum[enum.length / 2]).ordered
137
+ @order.should_receive(:touch).with(enum.first).ordered
138
+ enum.reverse_each{ |o| o.should_receive(:touch).once }
139
+ @mutex = Mutex.new
140
+ enum.in_threads.reverse_each do |o|
141
+ @mutex.synchronize{ @order.touch(o) }
142
+ o.touch_n_value
143
+ end
144
+ end
145
+
146
+ it "should run faster with threads" do
147
+ measure{ enum.in_threads.reverse_each(&:value) }.should < measure{ enum.reverse_each(&:value) } * speed_coef
148
+ end
149
+
150
+ it "should return same enum without block" do
151
+ enum.in_threads.reverse_each.to_a.should == enum.reverse_each.to_a
152
+ end
42
153
  end
43
154
 
44
- it "should run faster when ran with more threads" do
45
- (measure{ @a.in_threads(20).each(&@sleepy_prock) } * 2).should be < measure{ @a.in_threads(2).each(&@sleepy_prock) }
155
+ %w[
156
+ all? any? none? one?
157
+ detect find find_index drop_while take_while
158
+ ].each do |method|
159
+ describe method do
160
+ let(:enum){ 100.times.map{ |i| ValueItem.new(i, i % 2 == 1) } }
161
+
162
+ it "should return same result with threads" do
163
+ enum.in_threads.send(method, &:check?).should == enum.send(method, &:check?)
164
+ end
165
+
166
+ it "should fire same objects but not all" do
167
+ a = []
168
+ enum.send(method) do |o|
169
+ a << o
170
+ o.check?
171
+ end
172
+
173
+ @a = []
174
+ @mutex = Mutex.new
175
+ enum.in_threads.send(method){ |o| @mutex.synchronize{ @a << o }; o.check? }
176
+
177
+ @a.length.should >= a.length
178
+ @a.length.should <= enum.length / 2
179
+ end
180
+
181
+ it "should run faster with threads" do
182
+ value = %w[all? drop_while take_while].include?(method)
183
+ enum = 30.times.map{ |i| ValueItem.new(i, value) }
184
+ measure{ enum.in_threads.send(method, &:check?) }.should < measure{ enum.send(method, &:check?) } * speed_coef
185
+ end
186
+ end
46
187
  end
47
188
 
48
- %w(each map any? all? none?).each do |method|
49
- it "should return same as without thread for #{method}" do
50
- @a.in_threads.send(method, &@sleepy_prock).should == @a.send(method, &@sleepy_prock)
189
+ %w[partition find_all select reject count].each do |method|
190
+ describe method do
191
+ it "should return same result with threads" do
192
+ enum.in_threads.send(method, &:check?).should == enum.send(method, &:check?)
193
+ end
194
+
195
+ it "should fire same objects" do
196
+ enum.send(method){ |o| o.should_receive(:touch).once }
197
+ enum.in_threads.send(method, &:touch_n_check?)
198
+ end
199
+
200
+ it "should run faster with threads" do
201
+ measure{ enum.in_threads.send(method, &:check?) }.should < measure{ enum.send(method, &:check?) } * speed_coef
202
+ end
203
+ end
204
+ end
205
+
206
+ %w[collect map group_by max_by min_by minmax_by sort_by].each do |method|
207
+ describe method do
208
+ it "should return same result with threads" do
209
+ enum.in_threads.send(method, &:value).should == enum.send(method, &:value)
210
+ end
211
+
212
+ it "should fire same objects" do
213
+ enum.send(method){ |o| o.should_receive(:touch).once; 0 }
214
+ enum.in_threads.send(method, &:touch_n_value)
215
+ end
216
+
217
+ it "should run faster with threads" do
218
+ measure{ enum.in_threads.send(method, &:value) }.should < measure{ enum.send(method, &:value) } * speed_coef
219
+ end
220
+ end
221
+ end
222
+
223
+ enum_methods(%w[each_cons each_slice enum_slice enum_cons]).each do |method|
224
+ describe method do
225
+ let(:runner){ proc{ |a| a.each(&:value) } }
226
+
227
+ it "should fire same objects" do
228
+ enum.send(method, 3){ |a| a.first.should_receive(:touch).with(a).once }
229
+ enum.in_threads.send(method, 3){ |a| a.first.touch_n_value(a) }
230
+ end
231
+
232
+ it "should return same with block" do
233
+ enum.in_threads.send(method, 3, &runner).should == enum.send(method, 3, &runner)
234
+ end
235
+
236
+ it "should run faster with threads" do
237
+ measure{ enum.in_threads.send(method, 3, &runner) }.should < measure{ enum.send(method, 3, &runner) } * speed_coef
238
+ end
239
+
240
+ it "should return same without block" do
241
+ enum.in_threads.send(method, 3).to_a.should == enum.send(method, 3).to_a
242
+ end
243
+ end
244
+ end
245
+
246
+ describe "zip" do
247
+ let(:runner){ proc{ |a| a.each(&:value) } }
248
+
249
+ it "should fire same objects" do
250
+ enum.zip(enum, enum){ |a| a.first.should_receive(:touch).with(a).once }
251
+ enum.in_threads.zip(enum, enum){ |a| a.first.touch_n_value(a) }
252
+ end
253
+
254
+ it "should return same with block" do
255
+ enum.in_threads.zip(enum, enum, &runner).should == enum.zip(enum, enum, &runner)
256
+ end
257
+
258
+ it "should run faster with threads" do
259
+ measure{ enum.in_threads.zip(enum, enum, &runner) }.should < measure{ enum.zip(enum, enum, &runner) } * speed_coef
260
+ end
261
+
262
+ it "should return same without block" do
263
+ enum.in_threads.zip(enum, enum).should == enum.zip(enum, enum)
264
+ end
265
+ end
266
+
267
+ describe "cycle" do
268
+ it "should fire same objects" do
269
+ enum.cycle(1){ |o| o.should_receive(:touch).exactly(3).times }
270
+ enum.in_threads.cycle(3, &:touch_n_value)
271
+ end
272
+
273
+ it "should run faster with threads" do
274
+ measure{ enum.in_threads.cycle(3, &:work) }.should < measure{ enum.cycle(3, &:work) } * speed_coef
275
+ end
276
+
277
+ it "should return same enum without block" do
278
+ enum.in_threads.cycle(3).to_a.should == enum.cycle(3).to_a
279
+ end
280
+ end
281
+
282
+ describe "grep" do
283
+ let(:matcher){ Item::MiddleMatcher.new }
284
+
285
+ it "should fire same objects" do
286
+ enum.each{ |o| o.should_receive(:touch).exactly(matcher === o ? 1 : 0).times }
287
+ enum.in_threads.grep(matcher, &:touch_n_value)
288
+ end
289
+
290
+ it "should return same with block" do
291
+ enum.in_threads.grep(matcher, &:value).should == enum.grep(matcher, &:value)
292
+ end
293
+
294
+ it "should run faster with threads" do
295
+ measure{ enum.in_threads.grep(matcher, &:value) }.should < measure{ enum.grep(matcher, &:value) } * speed_coef
296
+ end
297
+
298
+ it "should return same without block" do
299
+ enum.in_threads.grep(matcher).should == enum.grep(matcher)
51
300
  end
52
301
  end
53
302
 
54
- it "should return same as without thread for .each_slice" do
55
- @a.in_threads.each_slice(2, &@sleepy_prock_a).should == @a.each_slice(2, &@sleepy_prock_a)
303
+ context "unthreaded" do
304
+ %w[inject reduce].each do |method|
305
+ describe method do
306
+ it "should return same result" do
307
+ combiner = proc{ |memo, o| memo + o.value }
308
+ enum.in_threads.send(method, 0, &combiner).should == enum.send(method, 0, &combiner)
309
+ end
310
+ end
311
+ end
312
+
313
+ %w[max min minmax sort].each do |method|
314
+ describe method do
315
+ it "should return same result" do
316
+ comparer = proc{ |a, b| a.value <=> b.value }
317
+ enum.in_threads.send(method, &comparer).should == enum.send(method, &comparer)
318
+ end
319
+ end
320
+ end
321
+
322
+ %w[to_a entries].each do |method|
323
+ describe method do
324
+ it "should return same result" do
325
+ enum.in_threads.send(method).should == enum.send(method)
326
+ end
327
+ end
328
+ end
329
+
330
+ %w[drop take].each do |method|
331
+ describe method do
332
+ it "should return same result" do
333
+ enum.in_threads.send(method, 2).should == enum.send(method, 2)
334
+ end
335
+ end
336
+ end
337
+
338
+ %w[first].each do |method|
339
+ describe method do
340
+ it "should return same result" do
341
+ enum.in_threads.send(method).should == enum.send(method)
342
+ enum.in_threads.send(method, 3).should == enum.send(method, 3)
343
+ end
344
+ end
345
+ end
346
+
347
+ %w[include? member?].each do |method|
348
+ describe method do
349
+ it "should return same result" do
350
+ enum.in_threads.send(method, enum[10]).should == enum.send(method, enum[10])
351
+ end
352
+ end
353
+ end
56
354
  end
57
355
  end
metadata CHANGED
@@ -2,12 +2,12 @@
2
2
  name: in_threads
3
3
  version: !ruby/object:Gem::Version
4
4
  hash: 23
5
- prerelease: false
5
+ prerelease:
6
6
  segments:
7
+ - 1
7
8
  - 0
8
9
  - 0
9
- - 4
10
- version: 0.0.4
10
+ version: 1.0.0
11
11
  platform: ruby
12
12
  authors:
13
13
  - Ivan Kuchin
@@ -15,43 +15,12 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2010-12-15 00:00:00 +03:00
19
- default_executable:
18
+ date: 2011-12-05 00:00:00 Z
20
19
  dependencies:
21
- - !ruby/object:Gem::Dependency
22
- name: jeweler
23
- prerelease: false
24
- requirement: &id001 !ruby/object:Gem::Requirement
25
- none: false
26
- requirements:
27
- - - ~>
28
- - !ruby/object:Gem::Version
29
- hash: 1
30
- segments:
31
- - 1
32
- - 5
33
- - 1
34
- version: 1.5.1
35
- type: :development
36
- version_requirements: *id001
37
- - !ruby/object:Gem::Dependency
38
- name: rake-gem-ghost
39
- prerelease: false
40
- requirement: &id002 !ruby/object:Gem::Requirement
41
- none: false
42
- requirements:
43
- - - ">="
44
- - !ruby/object:Gem::Version
45
- hash: 3
46
- segments:
47
- - 0
48
- version: "0"
49
- type: :development
50
- version_requirements: *id002
51
20
  - !ruby/object:Gem::Dependency
52
21
  name: rspec
53
22
  prerelease: false
54
- requirement: &id003 !ruby/object:Gem::Requirement
23
+ requirement: &id001 !ruby/object:Gem::Requirement
55
24
  none: false
56
25
  requirements:
57
26
  - - ">="
@@ -61,27 +30,23 @@ dependencies:
61
30
  - 0
62
31
  version: "0"
63
32
  type: :development
64
- version_requirements: *id003
33
+ version_requirements: *id001
65
34
  description:
66
35
  email:
67
36
  executables: []
68
37
 
69
38
  extensions: []
70
39
 
71
- extra_rdoc_files:
72
- - LICENSE.txt
73
- - README.markdown
40
+ extra_rdoc_files: []
41
+
74
42
  files:
75
- - .tmignore
43
+ - .gitignore
76
44
  - LICENSE.txt
77
45
  - README.markdown
78
- - Rakefile
79
- - VERSION
80
46
  - in_threads.gemspec
81
47
  - lib/in_threads.rb
82
48
  - spec/in_threads_spec.rb
83
49
  - spec/spec_helper.rb
84
- has_rdoc: true
85
50
  homepage: http://github.com/toy/in_threads
86
51
  licenses:
87
52
  - MIT
@@ -110,11 +75,12 @@ required_rubygems_version: !ruby/object:Gem::Requirement
110
75
  version: "0"
111
76
  requirements: []
112
77
 
113
- rubyforge_project:
114
- rubygems_version: 1.3.7
78
+ rubyforge_project: in_threads
79
+ rubygems_version: 1.8.11
115
80
  signing_key:
116
81
  specification_version: 3
117
- summary: Execute ruby blocks in parallel
82
+ summary: Execute ruby code in parallel
118
83
  test_files:
119
84
  - spec/in_threads_spec.rb
120
85
  - spec/spec_helper.rb
86
+ has_rdoc:
data/.tmignore DELETED
@@ -1 +0,0 @@
1
- /*.gemspec
data/Rakefile DELETED
@@ -1,25 +0,0 @@
1
- require 'rake'
2
- require 'jeweler'
3
- require 'rake/gem_ghost_task'
4
- require 'rspec/core/rake_task'
5
-
6
- name = 'in_threads'
7
-
8
- Jeweler::Tasks.new do |gem|
9
- gem.name = name
10
- gem.summary = %Q{Execute ruby blocks in parallel}
11
- gem.homepage = "http://github.com/toy/#{name}"
12
- gem.license = 'MIT'
13
- gem.authors = ['Ivan Kuchin']
14
- gem.add_development_dependency 'jeweler', '~> 1.5.1'
15
- gem.add_development_dependency 'rake-gem-ghost'
16
- gem.add_development_dependency 'rspec'
17
- end
18
- Jeweler::RubygemsDotOrgTasks.new
19
- Rake::GemGhostTask.new
20
-
21
- RSpec::Core::RakeTask.new(:spec) do |spec|
22
- spec.rspec_opts = ['--colour --format progress']
23
- spec.pattern = 'spec/**/*_spec.rb'
24
- end
25
- task :default => :spec
data/VERSION DELETED
@@ -1 +0,0 @@
1
- 0.0.4