in_threads 1.3.1 → 1.4.0
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.
- checksums.yaml +5 -13
- data/.rubocop.yml +19 -3
- data/.travis.yml +21 -18
- data/Gemfile +4 -0
- data/LICENSE.txt +1 -1
- data/README.markdown +78 -20
- data/in_threads.gemspec +3 -3
- data/lib/in_threads.rb +35 -29
- data/spec/in_threads_spec.rb +201 -143
- metadata +16 -17
checksums.yaml
CHANGED
@@ -1,15 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
|
5
|
-
data.tar.gz: !binary |-
|
6
|
-
ZGM4ZTQ3N2YxM2M4NTgxODNiNWUzMTc1NWE5MjJlYWQ0MjE2NTY5Yw==
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 3cd4f7083b8d1d0be3787fb95a747ac290882761
|
4
|
+
data.tar.gz: 7a8b5b3e65d59bcdc03be378a9f8d9f94d1b0535
|
7
5
|
SHA512:
|
8
|
-
metadata.gz:
|
9
|
-
|
10
|
-
OWRkODZkMWE0ZTFmZjU0YjNhY2YyNjQyNmI2MDFkOGE2Y2FlOTIxNzU1ZWUx
|
11
|
-
Zjc1ZDE0NGI5Mjg1MjcxNTgyMmI4NWVkM2UyMTg4NDhjZDExMDc=
|
12
|
-
data.tar.gz: !binary |-
|
13
|
-
OGFmODBhMDljYzNjZDdmYmI5YjBhNmI0NzA4NzgxYTk4OTUwODM5YThhNmQ0
|
14
|
-
MDAzMGU2ZTIwNGU4ZjlmNGZjNDBjNjgxNTZhMTA2NzAwZWJhODQyNDFlODlj
|
15
|
-
YzYyZWIwYjUyOGUzM2ExMGNhOTIwZmI5NWEzODBlN2E2YWU2OTY=
|
6
|
+
metadata.gz: 6d7547364ef110ff2cb51e8e57441028e694bfae5d54e7c44ae63b58599aefa4523fda5531a90af5d0e54dc0415c365b024d6ab585481862ffa4868ca47e6992
|
7
|
+
data.tar.gz: 22b699ee74f26862c5cf7a844d7aaf6f77af5a50d4d7ce0c287c8682fa577b6dbadca1c207282673b9da36d7f68bff90d6bfde0ea343b81ae28dd2835cc31c68
|
data/.rubocop.yml
CHANGED
@@ -3,22 +3,29 @@ AllCops:
|
|
3
3
|
- '*.gemspec'
|
4
4
|
|
5
5
|
Lint/EndAlignment:
|
6
|
-
|
6
|
+
EnforcedStyleAlignWith: variable
|
7
7
|
|
8
8
|
Metrics/AbcSize:
|
9
9
|
Max: 25
|
10
10
|
|
11
|
+
Metrics/BlockLength:
|
12
|
+
Exclude:
|
13
|
+
- 'spec/**/*.rb'
|
14
|
+
|
11
15
|
Metrics/ClassLength:
|
12
16
|
Max: 150
|
13
17
|
|
14
18
|
Metrics/MethodLength:
|
15
19
|
Max: 25
|
16
20
|
|
21
|
+
Performance/RedundantBlockCall:
|
22
|
+
Enabled: false
|
23
|
+
|
17
24
|
Style/AccessModifierIndentation:
|
18
25
|
EnforcedStyle: outdent
|
19
26
|
|
20
27
|
Style/CaseIndentation:
|
21
|
-
|
28
|
+
EnforcedStyle: end
|
22
29
|
|
23
30
|
Style/DotPosition:
|
24
31
|
EnforcedStyle: trailing
|
@@ -38,6 +45,9 @@ Style/IfUnlessModifier:
|
|
38
45
|
Style/IndentHash:
|
39
46
|
EnforcedStyle: consistent
|
40
47
|
|
48
|
+
Style/ParallelAssignment:
|
49
|
+
Enabled: false
|
50
|
+
|
41
51
|
Style/PercentLiteralDelimiters:
|
42
52
|
PreferredDelimiters:
|
43
53
|
'%w': '[]'
|
@@ -46,11 +56,17 @@ Style/PercentLiteralDelimiters:
|
|
46
56
|
Style/Semicolon:
|
47
57
|
AllowAsExpressionSeparator: true
|
48
58
|
|
59
|
+
Style/SignalException:
|
60
|
+
EnforcedStyle: semantic
|
61
|
+
|
49
62
|
Style/SpaceBeforeBlockBraces:
|
50
63
|
EnforcedStyle: no_space
|
51
64
|
|
52
65
|
Style/SpaceInsideHashLiteralBraces:
|
53
66
|
EnforcedStyle: no_space
|
54
67
|
|
55
|
-
Style/
|
68
|
+
Style/TrailingCommaInArguments:
|
69
|
+
EnforcedStyleForMultiline: no_comma
|
70
|
+
|
71
|
+
Style/TrailingCommaInLiteral:
|
56
72
|
EnforcedStyleForMultiline: comma
|
data/.travis.yml
CHANGED
@@ -1,22 +1,25 @@
|
|
1
|
+
sudo: false
|
1
2
|
language: ruby
|
2
3
|
rvm:
|
3
|
-
- 1.8.7
|
4
|
-
- 1.9.
|
5
|
-
-
|
6
|
-
- '2.
|
7
|
-
- '2.
|
8
|
-
- '2.
|
9
|
-
-
|
10
|
-
-
|
11
|
-
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
; else
|
16
|
-
bundle exec rubocop
|
17
|
-
; fi
|
4
|
+
- '1.8.7-p371'
|
5
|
+
- '1.9.3-p551'
|
6
|
+
- '2.0.0-p648'
|
7
|
+
- '2.1.10'
|
8
|
+
- '2.2.6'
|
9
|
+
- '2.3.3'
|
10
|
+
- '2.4.0'
|
11
|
+
- 'ruby-head'
|
12
|
+
- 'jruby-1.7.26'
|
13
|
+
- 'jruby-9.0.5.0'
|
14
|
+
- 'jruby-9.1.5.0'
|
15
|
+
script: bundle exec rspec
|
18
16
|
matrix:
|
19
|
-
fast_finish: true
|
20
17
|
include:
|
21
|
-
- env: RUBOCOP
|
22
|
-
rvm:
|
18
|
+
- env: RUBOCOP=✓
|
19
|
+
rvm: '2.4.0'
|
20
|
+
script: bundle exec rubocop
|
21
|
+
- env: CHECK_RUBIES=✓
|
22
|
+
rvm: '2.4.0'
|
23
|
+
script: bundle exec travis_check_rubies
|
24
|
+
allow_failures:
|
25
|
+
- rvm: 'ruby-head'
|
data/Gemfile
CHANGED
data/LICENSE.txt
CHANGED
data/README.markdown
CHANGED
@@ -2,40 +2,98 @@
|
|
2
2
|
[](https://travis-ci.org/toy/in_threads)
|
3
3
|
[](https://codeclimate.com/github/toy/in_threads)
|
4
4
|
[](https://gemnasium.com/toy/in_threads)
|
5
|
-
[](https://inch-ci.org/github/toy/in_threads)
|
6
6
|
|
7
7
|
# in_threads
|
8
8
|
|
9
|
-
Easily execute
|
9
|
+
Easily execute Ruby code in parallel.
|
10
|
+
|
11
|
+
```ruby
|
12
|
+
urls.in_threads(20).map do |url|
|
13
|
+
HTTP.get(url)
|
14
|
+
end
|
15
|
+
```
|
10
16
|
|
11
17
|
## Installation
|
12
18
|
|
13
|
-
|
19
|
+
Add the gem to your Gemfile...
|
20
|
+
|
21
|
+
```ruby
|
22
|
+
gem 'in_threads'
|
23
|
+
```
|
24
|
+
|
25
|
+
...and install it with [Bundler](http://bundler.io).
|
26
|
+
|
27
|
+
```sh
|
28
|
+
$ bundle install
|
29
|
+
```
|
30
|
+
|
31
|
+
Or, if you don't use Bundler, install it globally:
|
32
|
+
|
33
|
+
```sh
|
34
|
+
$ gem install in_threads
|
35
|
+
```
|
14
36
|
|
15
37
|
## Usage
|
16
38
|
|
17
|
-
|
39
|
+
Let's say you have a list of web pages to download.
|
40
|
+
|
41
|
+
```ruby
|
42
|
+
urls = [
|
43
|
+
"https://google.com",
|
44
|
+
"https://en.wikipedia.org/wiki/Ruby",
|
45
|
+
"https://news.ycombinator.com",
|
46
|
+
"https://github.com/trending"
|
47
|
+
]
|
48
|
+
```
|
49
|
+
|
50
|
+
You can easily download each web page one after the other.
|
51
|
+
|
52
|
+
```ruby
|
53
|
+
urls.each do |url|
|
54
|
+
HTTP.get(url)
|
55
|
+
end
|
56
|
+
```
|
57
|
+
|
58
|
+
However, this is slow, especially for a large number of web pages. Instead,
|
59
|
+
download the web pages in parallel with `in_threads`.
|
60
|
+
|
61
|
+
```ruby
|
62
|
+
require 'in_threads'
|
63
|
+
|
64
|
+
urls.in_threads.each do |url|
|
65
|
+
HTTP.get(url)
|
66
|
+
end
|
67
|
+
```
|
68
|
+
|
69
|
+
By calling `in_threads`, the each web page is downloaded in its own thread,
|
70
|
+
reducing the time by almost 4x.
|
71
|
+
|
72
|
+
By default, no more than 10 threads run at any one time. However, this can be
|
73
|
+
easily overriden.
|
18
74
|
|
19
|
-
|
20
|
-
|
21
|
-
|
75
|
+
```ruby
|
76
|
+
# Read all XML files in a directory
|
77
|
+
Dir['*.xml'].in_threads(100).each do |file|
|
78
|
+
File.read(file)
|
79
|
+
end
|
80
|
+
```
|
22
81
|
|
23
|
-
|
24
|
-
|
25
|
-
end
|
82
|
+
Predicate methods (methods that return `true` or `false` for each object in a
|
83
|
+
collection) are particularly well suited for use with `in_threads`.
|
26
84
|
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
end
|
85
|
+
```ruby
|
86
|
+
# Are all URLs valid?
|
87
|
+
urls.in_threads.all? { |url| HTTP.get(url).status == 200 }
|
31
88
|
|
32
|
-
|
89
|
+
# Are any URLs invalid?
|
90
|
+
urls.in_threads.any? { |url| HTTP.get(url).status == 404 }
|
91
|
+
```
|
33
92
|
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
urls.in_threads.grep(/example\.com/, &:fetch)
|
93
|
+
You can call any `Enumerable` method, but some (`#inject`, `#reduce`, `#max`,
|
94
|
+
`#min`, `#sort`, `#to_a`, and others) cannot run concurrently, and so will
|
95
|
+
simply act as if `in_threads` wasn't used.
|
38
96
|
|
39
97
|
## Copyright
|
40
98
|
|
41
|
-
Copyright (c) 2010-
|
99
|
+
Copyright (c) 2010-2017 Ivan Kuchin. See LICENSE.txt for details.
|
data/in_threads.gemspec
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
Gem::Specification.new do |s|
|
4
4
|
s.name = 'in_threads'
|
5
|
-
s.version = '1.
|
5
|
+
s.version = '1.4.0'
|
6
6
|
s.summary = %q{Execute ruby code in parallel}
|
7
7
|
s.homepage = "http://github.com/toy/#{s.name}"
|
8
8
|
s.authors = ['Ivan Kuchin']
|
@@ -17,7 +17,7 @@ Gem::Specification.new do |s|
|
|
17
17
|
|
18
18
|
s.add_development_dependency 'rspec', '~> 3.0'
|
19
19
|
s.add_development_dependency 'rspec-retry', '~> 0.3'
|
20
|
-
if
|
21
|
-
s.add_development_dependency 'rubocop', '~> 0.
|
20
|
+
if RUBY_VERSION >= '2.0'
|
21
|
+
s.add_development_dependency 'rubocop', '~> 0.47'
|
22
22
|
end
|
23
23
|
end
|
data/lib/in_threads.rb
CHANGED
@@ -57,11 +57,8 @@ class InThreads < SimpleDelegator
|
|
57
57
|
# Add thread to `ThreadsWait`, wait for finishing of one thread if limit
|
58
58
|
# reached
|
59
59
|
def <<(thread)
|
60
|
-
|
61
|
-
|
62
|
-
else
|
63
|
-
@waiter.join_nowait(thread)
|
64
|
-
end
|
60
|
+
@waiter.join_nowait(thread)
|
61
|
+
@waiter.next_wait.join unless @waiter.threads.length < @count
|
65
62
|
end
|
66
63
|
|
67
64
|
# Wait for waiting threads
|
@@ -74,32 +71,23 @@ class InThreads < SimpleDelegator
|
|
74
71
|
class Splitter
|
75
72
|
# Enumerable using Queue
|
76
73
|
class Transfer
|
77
|
-
# Holds one object, for distinguishing eof
|
78
|
-
class Item
|
79
|
-
attr_reader :value
|
80
|
-
|
81
|
-
def initialize(value)
|
82
|
-
@value = value
|
83
|
-
end
|
84
|
-
end
|
85
|
-
|
86
74
|
include Enumerable
|
87
75
|
|
88
76
|
def initialize
|
89
77
|
@queue = Queue.new
|
90
78
|
end
|
91
79
|
|
92
|
-
def <<(
|
93
|
-
@queue <<
|
80
|
+
def <<(args)
|
81
|
+
@queue << args
|
94
82
|
end
|
95
83
|
|
96
84
|
def finish
|
97
85
|
@queue << nil
|
98
86
|
end
|
99
87
|
|
100
|
-
def each
|
101
|
-
while (
|
102
|
-
|
88
|
+
def each(&block)
|
89
|
+
while (args = @queue.pop)
|
90
|
+
block.call(*args)
|
103
91
|
end
|
104
92
|
nil # non reusable
|
105
93
|
end
|
@@ -111,9 +99,9 @@ class InThreads < SimpleDelegator
|
|
111
99
|
def initialize(enumerable, enum_count)
|
112
100
|
@enums = Array.new(enum_count){ Transfer.new }
|
113
101
|
@filler = Thread.new do
|
114
|
-
enumerable.each do |
|
102
|
+
enumerable.each do |*args|
|
115
103
|
@enums.each do |enum|
|
116
|
-
enum <<
|
104
|
+
enum << args
|
117
105
|
end
|
118
106
|
end
|
119
107
|
@enums.each(&:finish)
|
@@ -151,9 +139,8 @@ class InThreads < SimpleDelegator
|
|
151
139
|
methods = Array(options[:for])
|
152
140
|
fail 'no methods provided using :for option' if methods.empty?
|
153
141
|
ignore_undefined = options[:ignore_undefined]
|
154
|
-
enumerable_methods = Enumerable.instance_methods.map(&:to_s)
|
155
142
|
methods.each do |method|
|
156
|
-
next if ignore_undefined && !
|
143
|
+
next if ignore_undefined && !enumerable_method?(method)
|
157
144
|
class_eval <<-RUBY
|
158
145
|
def #{method}(*args, &block)
|
159
146
|
#{runner}(:#{method}, *args, &block)
|
@@ -161,6 +148,13 @@ class InThreads < SimpleDelegator
|
|
161
148
|
RUBY
|
162
149
|
end
|
163
150
|
end
|
151
|
+
|
152
|
+
private
|
153
|
+
|
154
|
+
def enumerable_method?(name)
|
155
|
+
@enumerable_methods ||= Enumerable.instance_methods.map(&:to_sym)
|
156
|
+
@enumerable_methods.include?(name.to_sym)
|
157
|
+
end
|
164
158
|
end
|
165
159
|
|
166
160
|
use :run_in_threads_return_original_enum, :for => %w[each]
|
@@ -176,7 +170,7 @@ class InThreads < SimpleDelegator
|
|
176
170
|
all? any? none? one?
|
177
171
|
detect find find_index drop_while take_while
|
178
172
|
partition find_all select reject count
|
179
|
-
collect map group_by max_by min_by minmax_by sort_by
|
173
|
+
collect map group_by max_by min_by minmax_by sort_by sum uniq
|
180
174
|
flat_map collect_concat
|
181
175
|
], :ignore_undefined => true
|
182
176
|
|
@@ -188,7 +182,7 @@ class InThreads < SimpleDelegator
|
|
188
182
|
first
|
189
183
|
include? member?
|
190
184
|
each_with_object
|
191
|
-
chunk slice_before slice_after slice_when
|
185
|
+
chunk chunk_while slice_before slice_after slice_when
|
192
186
|
].map(&:to_sym)
|
193
187
|
|
194
188
|
# Special case method, works by applying `run_in_threads_consecutive` with
|
@@ -201,6 +195,18 @@ class InThreads < SimpleDelegator
|
|
201
195
|
end
|
202
196
|
end
|
203
197
|
|
198
|
+
if enumerable_method?(:grep_v)
|
199
|
+
# Special case method, works by applying `run_in_threads_consecutive` with
|
200
|
+
# map on enumerable returned by blockless run
|
201
|
+
def grep_v(*args, &block)
|
202
|
+
if block
|
203
|
+
self.class.new(enumerable.grep_v(*args), thread_count).map(&block)
|
204
|
+
else
|
205
|
+
enumerable.grep_v(*args)
|
206
|
+
end
|
207
|
+
end
|
208
|
+
end
|
209
|
+
|
204
210
|
# befriend with progress gem
|
205
211
|
def with_progress(title = nil, length = nil, &block)
|
206
212
|
::Progress::WithProgress.new(self, title, length, &block)
|
@@ -213,7 +219,7 @@ protected
|
|
213
219
|
if block
|
214
220
|
ThreadLimiter.limit(thread_count) do |limiter|
|
215
221
|
enumerable.send(method, *args) do |*block_args|
|
216
|
-
limiter << Thread.new(*block_args
|
222
|
+
limiter << Thread.new{ block.call(*block_args) }
|
217
223
|
end
|
218
224
|
end
|
219
225
|
else
|
@@ -229,9 +235,9 @@ protected
|
|
229
235
|
runner = Thread.new do
|
230
236
|
Thread.current.priority = -1
|
231
237
|
ThreadLimiter.limit(thread_count) do |limiter|
|
232
|
-
enum_a.each do |
|
238
|
+
enum_a.each do |*block_args|
|
233
239
|
break if Thread.current[:stop]
|
234
|
-
thread = Thread.new
|
240
|
+
thread = Thread.new{ block.call(*block_args) }
|
235
241
|
results << thread
|
236
242
|
limiter << thread
|
237
243
|
end
|
@@ -239,7 +245,7 @@ protected
|
|
239
245
|
end
|
240
246
|
|
241
247
|
begin
|
242
|
-
enum_b.send(method, *args) do
|
248
|
+
enum_b.send(method, *args) do
|
243
249
|
results.pop.value
|
244
250
|
end
|
245
251
|
ensure
|
data/spec/in_threads_spec.rb
CHANGED
@@ -18,7 +18,7 @@ class ValueItem
|
|
18
18
|
end
|
19
19
|
|
20
20
|
def ==(other)
|
21
|
-
id == other.id
|
21
|
+
id == other.id if other.is_a?(self.class)
|
22
22
|
end
|
23
23
|
|
24
24
|
def value
|
@@ -67,24 +67,41 @@ class RandItem < ValueItem
|
|
67
67
|
end
|
68
68
|
end
|
69
69
|
|
70
|
+
# Pure class with Enumerable instead of Array
|
71
|
+
class TestEnum
|
72
|
+
include Enumerable
|
73
|
+
|
74
|
+
def initialize(count, &block)
|
75
|
+
@items = Array.new(count){ |i| block[i] }
|
76
|
+
end
|
77
|
+
|
78
|
+
def each(&block)
|
79
|
+
@items.each(&block)
|
80
|
+
self
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
70
84
|
class TestException < StandardError; end
|
71
85
|
|
86
|
+
ENUM_METHODS = Enumerable.instance_methods.map(&:to_s)
|
72
87
|
def describe_enum_method(method, &block)
|
73
|
-
|
74
|
-
|
75
|
-
describe(method, &block)
|
88
|
+
if ENUM_METHODS.include?(method)
|
89
|
+
describe "##{method}", &block
|
76
90
|
else
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
91
|
+
describe "##{method}" do
|
92
|
+
it 'is not defined' do
|
93
|
+
exception_regexp =
|
94
|
+
/^undefined method `#{Regexp.escape(method)}' .*\bInThreads\b/
|
95
|
+
expect{ enum.in_threads.send(method) }.
|
96
|
+
to raise_error(NoMethodError, exception_regexp)
|
97
|
+
end
|
82
98
|
end
|
83
99
|
end
|
84
100
|
end
|
85
101
|
|
86
102
|
describe 'in_threads' do
|
87
|
-
let(:
|
103
|
+
let(:items){ Array.new(30){ |i| RandItem.new(i) } }
|
104
|
+
let(:enum){ TestEnum.new(items) }
|
88
105
|
|
89
106
|
# small coefficient, should be more if sleep time coefficient is bigger
|
90
107
|
let(:speed_coef){ 0.666 }
|
@@ -97,32 +114,32 @@ describe 'in_threads' do
|
|
97
114
|
|
98
115
|
describe 'consistency' do
|
99
116
|
describe 'verifying params' do
|
100
|
-
it '
|
117
|
+
it 'complains about using with non enumerable' do
|
101
118
|
expect{ InThreads.new(1) }.to raise_error(ArgumentError)
|
102
119
|
end
|
103
120
|
|
104
121
|
[1..10, 10.times, {}, []].each do |o|
|
105
|
-
it "
|
122
|
+
it "does not complain about using with #{o.class}" do
|
106
123
|
expect{ InThreads.new(o) }.not_to raise_error
|
107
124
|
end
|
108
125
|
end
|
109
126
|
|
110
|
-
it '
|
127
|
+
it 'complains about using less than 2 threads' do
|
111
128
|
expect{ 10.times.in_threads(1) }.to raise_error(ArgumentError)
|
112
129
|
end
|
113
130
|
|
114
|
-
it '
|
131
|
+
it 'does not complain about using 2 or more threads' do
|
115
132
|
expect{ 10.times.in_threads(2) }.not_to raise_error
|
116
133
|
end
|
117
134
|
end
|
118
135
|
|
119
136
|
describe 'in_threads method' do
|
120
|
-
it '
|
137
|
+
it 'does not change existing instance' do
|
121
138
|
threaded = enum.in_threads(10)
|
122
139
|
expect{ threaded.in_threads(20) }.not_to change(threaded, :thread_count)
|
123
140
|
end
|
124
141
|
|
125
|
-
it '
|
142
|
+
it 'creates new instance with different title when called on '\
|
126
143
|
'WithProgress' do
|
127
144
|
threaded = enum.in_threads(10)
|
128
145
|
tthreaded = threaded.in_threads(20)
|
@@ -135,10 +152,10 @@ describe 'in_threads' do
|
|
135
152
|
end
|
136
153
|
|
137
154
|
describe 'thread count' do
|
138
|
-
let(:
|
155
|
+
let(:items){ Array.new(100){ |i| ValueItem.new(i, i < 50) } }
|
139
156
|
|
140
157
|
%w[each map all?].each do |method|
|
141
|
-
it "
|
158
|
+
it "runs in specified number of threads for #{method}" do
|
142
159
|
@thread_count = 0
|
143
160
|
@max_thread_count = 0
|
144
161
|
@mutex = Mutex.new
|
@@ -161,15 +178,15 @@ describe 'in_threads' do
|
|
161
178
|
|
162
179
|
describe 'underlying enumerable usage' do
|
163
180
|
%w[each map all?].each do |method|
|
164
|
-
it "
|
165
|
-
enum = 100
|
181
|
+
it "calls underlying enumerable.each only once for #{method}" do
|
182
|
+
enum = Array.new(100){ |i| ValueItem.new(i, i < 50) }
|
166
183
|
|
167
184
|
expect(enum).to receive(:each).once.and_call_original
|
168
185
|
enum.in_threads(13).send(method, &:check?)
|
169
186
|
end
|
170
187
|
end
|
171
188
|
|
172
|
-
it '
|
189
|
+
it 'does not yield all elements when not needed' do
|
173
190
|
enum = []
|
174
191
|
def enum.each
|
175
192
|
100.times{ yield 1 }
|
@@ -179,6 +196,37 @@ describe 'in_threads' do
|
|
179
196
|
enum.in_threads(13).all?{ false }
|
180
197
|
end
|
181
198
|
end
|
199
|
+
|
200
|
+
describe 'block arguments' do
|
201
|
+
before do
|
202
|
+
def enum.each
|
203
|
+
yield
|
204
|
+
yield 1
|
205
|
+
yield 2, 3
|
206
|
+
yield 4, 5, 6
|
207
|
+
end
|
208
|
+
end
|
209
|
+
|
210
|
+
it 'passes all to methods ignoring block result' do
|
211
|
+
o = double
|
212
|
+
enum.each do |*args|
|
213
|
+
expect(o).to receive(:notify).with(args)
|
214
|
+
end
|
215
|
+
enum.in_threads.each do |*args|
|
216
|
+
o.notify(args)
|
217
|
+
end
|
218
|
+
end
|
219
|
+
|
220
|
+
it 'passes all to methods using block result' do
|
221
|
+
o = double
|
222
|
+
enum.each do |*args|
|
223
|
+
expect(o).to receive(:notify).with(args)
|
224
|
+
end
|
225
|
+
enum.in_threads.map do |*args|
|
226
|
+
o.notify(args)
|
227
|
+
end
|
228
|
+
end
|
229
|
+
end
|
182
230
|
end
|
183
231
|
|
184
232
|
describe 'methods' do
|
@@ -193,31 +241,31 @@ describe 'in_threads' do
|
|
193
241
|
expect{ block[enum.in_threads(1000)] }.to raise_exception(TestException)
|
194
242
|
end
|
195
243
|
|
196
|
-
describe 'each' do
|
197
|
-
it '
|
244
|
+
describe '#each' do
|
245
|
+
it 'returns same enum after running' do
|
198
246
|
expect(enum.in_threads.each(&:value)).to eq(enum)
|
199
247
|
end
|
200
248
|
|
201
|
-
it '
|
249
|
+
it 'executes block for each element' do
|
202
250
|
enum.each{ |o| expect(o).to receive(:touch).once }
|
203
251
|
enum.in_threads.each(&:touch_n_value)
|
204
252
|
end
|
205
253
|
|
206
|
-
it '
|
254
|
+
it 'runs faster with threads', :retry => 3 do
|
207
255
|
expect(measure{ enum.in_threads.each(&:value) }).
|
208
256
|
to be < measure{ enum.each(&:value) } * speed_coef
|
209
257
|
end
|
210
258
|
|
211
|
-
it '
|
259
|
+
it 'runs faster with more threads', :retry => 3 do
|
212
260
|
expect(measure{ enum.in_threads(10).each(&:value) }).
|
213
261
|
to be < measure{ enum.in_threads(2).each(&:value) } * speed_coef
|
214
262
|
end
|
215
263
|
|
216
|
-
it '
|
264
|
+
it 'returns same enum without block' do
|
217
265
|
expect(enum.in_threads.each.to_a).to eq(enum.each.to_a)
|
218
266
|
end
|
219
267
|
|
220
|
-
it '
|
268
|
+
it 'raises exception in outer thread' do
|
221
269
|
check_test_exception(enum) do |threaded|
|
222
270
|
threaded.each{ fail TestException }
|
223
271
|
end
|
@@ -228,27 +276,27 @@ describe 'in_threads' do
|
|
228
276
|
describe_enum_method method do
|
229
277
|
let(:runner){ proc{ |o, _i| o.value } }
|
230
278
|
|
231
|
-
it '
|
279
|
+
it 'returns same result with threads' do
|
232
280
|
expect(enum.in_threads.send(method, &runner)).
|
233
281
|
to eq(enum.send(method, &runner))
|
234
282
|
end
|
235
283
|
|
236
|
-
it '
|
284
|
+
it 'fires same objects' do
|
237
285
|
enum.send(method){ |o, i| expect(o).to receive(:touch).with(i).once }
|
238
286
|
enum.in_threads.send(method){ |o, i| o.touch_n_value(i) }
|
239
287
|
end
|
240
288
|
|
241
|
-
it '
|
289
|
+
it 'runs faster with threads', :retry => 3 do
|
242
290
|
expect(measure{ enum.in_threads.send(method, &runner) }).
|
243
291
|
to be < measure{ enum.send(method, &runner) } * speed_coef
|
244
292
|
end
|
245
293
|
|
246
|
-
it '
|
294
|
+
it 'returns same enum without block' do
|
247
295
|
expect(enum.in_threads.send(method).to_a).
|
248
296
|
to eq(enum.send(method).to_a)
|
249
297
|
end
|
250
298
|
|
251
|
-
it '
|
299
|
+
it 'raises exception in outer thread' do
|
252
300
|
check_test_exception(enum) do |threaded|
|
253
301
|
threaded.send(method){ fail TestException }
|
254
302
|
end
|
@@ -256,18 +304,18 @@ describe 'in_threads' do
|
|
256
304
|
end
|
257
305
|
end
|
258
306
|
|
259
|
-
describe 'reverse_each' do
|
260
|
-
it '
|
307
|
+
describe '#reverse_each' do
|
308
|
+
it 'returns same result with threads' do
|
261
309
|
expect(enum.in_threads.reverse_each(&:value)).
|
262
310
|
to eq(enum.reverse_each(&:value))
|
263
311
|
end
|
264
312
|
|
265
|
-
it '
|
313
|
+
it 'fires same objects in reverse order' do
|
266
314
|
@order = double('order', :notify => nil)
|
267
|
-
expect(@order).to receive(:notify).with(
|
268
|
-
expect(@order).to receive(:notify).with(
|
269
|
-
expect(@order).to receive(:notify).with(
|
270
|
-
enum.
|
315
|
+
expect(@order).to receive(:notify).with(items.last).ordered
|
316
|
+
expect(@order).to receive(:notify).with(items[items.length / 2]).ordered
|
317
|
+
expect(@order).to receive(:notify).with(items.first).ordered
|
318
|
+
enum.each{ |o| expect(o).to receive(:touch).once }
|
271
319
|
@mutex = Mutex.new
|
272
320
|
enum.in_threads.reverse_each do |o|
|
273
321
|
@mutex.synchronize{ @order.notify(o) }
|
@@ -275,16 +323,16 @@ describe 'in_threads' do
|
|
275
323
|
end
|
276
324
|
end
|
277
325
|
|
278
|
-
it '
|
326
|
+
it 'runs faster with threads', :retry => 3 do
|
279
327
|
expect(measure{ enum.in_threads.reverse_each(&:value) }).
|
280
328
|
to be < measure{ enum.reverse_each(&:value) } * speed_coef
|
281
329
|
end
|
282
330
|
|
283
|
-
it '
|
331
|
+
it 'returns same enum without block' do
|
284
332
|
expect(enum.in_threads.reverse_each.to_a).to eq(enum.reverse_each.to_a)
|
285
333
|
end
|
286
334
|
|
287
|
-
it '
|
335
|
+
it 'raises exception in outer thread' do
|
288
336
|
check_test_exception(enum) do |threaded|
|
289
337
|
threaded.reverse_each{ fail TestException }
|
290
338
|
end
|
@@ -295,15 +343,15 @@ describe 'in_threads' do
|
|
295
343
|
all? any? none? one?
|
296
344
|
detect find find_index drop_while take_while
|
297
345
|
].each do |method|
|
298
|
-
describe method do
|
299
|
-
let(:
|
346
|
+
describe "##{method}" do
|
347
|
+
let(:items){ Array.new(100){ |i| ValueItem.new(i, i.odd?) } }
|
300
348
|
|
301
|
-
it '
|
349
|
+
it 'returns same result with threads' do
|
302
350
|
expect(enum.in_threads.send(method, &:check?)).
|
303
351
|
to eq(enum.send(method, &:check?))
|
304
352
|
end
|
305
353
|
|
306
|
-
it '
|
354
|
+
it 'fires same objects but not all' do
|
307
355
|
a = []
|
308
356
|
enum.send(method) do |o|
|
309
357
|
a << o
|
@@ -318,17 +366,17 @@ describe 'in_threads' do
|
|
318
366
|
end
|
319
367
|
|
320
368
|
expect(@a.length).to be >= a.length
|
321
|
-
expect(@a.length).to be <=
|
369
|
+
expect(@a.length).to be <= items.length * 0.5
|
322
370
|
end
|
323
371
|
|
324
|
-
it '
|
372
|
+
it 'runs faster with threads', :retry => 3 do
|
325
373
|
boolean = %w[all? drop_while take_while].include?(method)
|
326
|
-
enum = 30
|
374
|
+
enum = Array.new(30){ |i| ValueItem.new(i, boolean) }
|
327
375
|
expect(measure{ enum.in_threads.send(method, &:check?) }).
|
328
376
|
to be < measure{ enum.send(method, &:check?) } * speed_coef
|
329
377
|
end
|
330
378
|
|
331
|
-
it '
|
379
|
+
it 'raises exception in outer thread' do
|
332
380
|
check_test_exception(enum) do |threaded|
|
333
381
|
threaded.send(method){ fail TestException }
|
334
382
|
end
|
@@ -337,23 +385,23 @@ describe 'in_threads' do
|
|
337
385
|
end
|
338
386
|
|
339
387
|
%w[partition find_all select reject count].each do |method|
|
340
|
-
describe method do
|
341
|
-
it '
|
388
|
+
describe "##{method}" do
|
389
|
+
it 'returns same result with threads' do
|
342
390
|
expect(enum.in_threads.send(method, &:check?)).
|
343
391
|
to eq(enum.send(method, &:check?))
|
344
392
|
end
|
345
393
|
|
346
|
-
it '
|
394
|
+
it 'fires same objects' do
|
347
395
|
enum.send(method){ |o| expect(o).to receive(:touch).once }
|
348
396
|
enum.in_threads.send(method, &:touch_n_check?)
|
349
397
|
end
|
350
398
|
|
351
|
-
it '
|
399
|
+
it 'runs faster with threads', :retry => 3 do
|
352
400
|
expect(measure{ enum.in_threads.send(method, &:check?) }).
|
353
401
|
to be < measure{ enum.send(method, &:check?) } * speed_coef
|
354
402
|
end
|
355
403
|
|
356
|
-
it '
|
404
|
+
it 'raises exception in outer thread' do
|
357
405
|
check_test_exception(enum) do |threaded|
|
358
406
|
threaded.send(method){ fail TestException }
|
359
407
|
end
|
@@ -361,24 +409,28 @@ describe 'in_threads' do
|
|
361
409
|
end
|
362
410
|
end
|
363
411
|
|
364
|
-
%w[
|
365
|
-
|
366
|
-
|
412
|
+
%w[
|
413
|
+
collect map
|
414
|
+
group_by max_by min_by minmax_by sort_by
|
415
|
+
sum uniq
|
416
|
+
].each do |method|
|
417
|
+
describe_enum_method method do
|
418
|
+
it 'returns same result with threads' do
|
367
419
|
expect(enum.in_threads.send(method, &:value)).
|
368
420
|
to eq(enum.send(method, &:value))
|
369
421
|
end
|
370
422
|
|
371
|
-
it '
|
423
|
+
it 'fires same objects' do
|
372
424
|
enum.send(method){ |o| expect(o).to receive(:touch).once; 0 }
|
373
425
|
enum.in_threads.send(method, &:touch_n_value)
|
374
426
|
end
|
375
427
|
|
376
|
-
it '
|
428
|
+
it 'runs faster with threads', :retry => 3 do
|
377
429
|
expect(measure{ enum.in_threads.send(method, &:value) }).
|
378
430
|
to be < measure{ enum.send(method, &:value) } * speed_coef
|
379
431
|
end
|
380
432
|
|
381
|
-
it '
|
433
|
+
it 'raises exception in outer thread' do
|
382
434
|
check_test_exception(enum) do |threaded|
|
383
435
|
threaded.send(method){ fail TestException }
|
384
436
|
end
|
@@ -390,29 +442,29 @@ describe 'in_threads' do
|
|
390
442
|
describe_enum_method method do
|
391
443
|
let(:runner){ proc{ |a| a.each(&:value) } }
|
392
444
|
|
393
|
-
it '
|
445
|
+
it 'fires same objects' do
|
394
446
|
enum.send(method, 3) do |a|
|
395
447
|
expect(a.first).to receive(:touch).with(a).once
|
396
448
|
end
|
397
449
|
enum.in_threads.send(method, 3){ |a| a.first.touch_n_value(a) }
|
398
450
|
end
|
399
451
|
|
400
|
-
it '
|
452
|
+
it 'returns same with block' do
|
401
453
|
expect(enum.in_threads.send(method, 3, &runner)).
|
402
454
|
to eq(enum.send(method, 3, &runner))
|
403
455
|
end
|
404
456
|
|
405
|
-
it '
|
457
|
+
it 'runs faster with threads', :retry => 3 do
|
406
458
|
expect(measure{ enum.in_threads.send(method, 3, &runner) }).
|
407
459
|
to be < measure{ enum.send(method, 3, &runner) } * speed_coef
|
408
460
|
end
|
409
461
|
|
410
|
-
it '
|
462
|
+
it 'returns same without block' do
|
411
463
|
expect(enum.in_threads.send(method, 3).to_a).
|
412
464
|
to eq(enum.send(method, 3).to_a)
|
413
465
|
end
|
414
466
|
|
415
|
-
it '
|
467
|
+
it 'raises exception in outer thread' do
|
416
468
|
check_test_exception(enum) do |threaded|
|
417
469
|
threaded.send(method, 3){ fail TestException }
|
418
470
|
end
|
@@ -420,10 +472,10 @@ describe 'in_threads' do
|
|
420
472
|
end
|
421
473
|
end
|
422
474
|
|
423
|
-
describe 'zip' do
|
475
|
+
describe '#zip' do
|
424
476
|
let(:runner){ proc{ |a| a.each(&:value) } }
|
425
477
|
|
426
|
-
it '
|
478
|
+
it 'fires same objects' do
|
427
479
|
enum.zip(enum, enum) do |a|
|
428
480
|
expect(a.first).to receive(:touch).with(a).once
|
429
481
|
end
|
@@ -433,119 +485,125 @@ describe 'in_threads' do
|
|
433
485
|
end
|
434
486
|
end
|
435
487
|
|
436
|
-
it '
|
488
|
+
it 'returns same with block' do
|
437
489
|
expect(enum.in_threads.zip(enum, enum, &runner)).
|
438
490
|
to eq(enum.zip(enum, enum, &runner))
|
439
491
|
end
|
440
492
|
|
441
|
-
it '
|
493
|
+
it 'runs faster with threads', :retry => 3 do
|
442
494
|
expect(measure{ enum.in_threads.zip(enum, enum, &runner) }).
|
443
495
|
to be < measure{ enum.zip(enum, enum, &runner) } * speed_coef
|
444
496
|
end
|
445
497
|
|
446
|
-
it '
|
498
|
+
it 'returns same without block' do
|
447
499
|
expect(enum.in_threads.zip(enum, enum)).to eq(enum.zip(enum, enum))
|
448
500
|
end
|
449
501
|
|
450
|
-
it '
|
502
|
+
it 'raises exception in outer thread' do
|
451
503
|
check_test_exception(enum) do |threaded|
|
452
504
|
threaded.zip(enum, enum){ fail TestException }
|
453
505
|
end
|
454
506
|
end
|
455
507
|
end
|
456
508
|
|
457
|
-
describe 'cycle' do
|
458
|
-
it '
|
509
|
+
describe '#cycle' do
|
510
|
+
it 'fires same objects' do
|
459
511
|
enum.cycle(1){ |o| expect(o).to receive(:touch).exactly(3).times }
|
460
512
|
enum.in_threads.cycle(3, &:touch_n_value)
|
461
513
|
end
|
462
514
|
|
463
|
-
it '
|
515
|
+
it 'runs faster with threads', :retry => 3 do
|
464
516
|
expect(measure{ enum.in_threads.cycle(3, &:value) }).
|
465
517
|
to be < measure{ enum.cycle(3, &:value) } * speed_coef
|
466
518
|
end
|
467
519
|
|
468
|
-
it '
|
520
|
+
it 'returns same enum without block' do
|
469
521
|
expect(enum.in_threads.cycle(3).to_a).to eq(enum.cycle(3).to_a)
|
470
522
|
end
|
471
523
|
|
472
|
-
it '
|
524
|
+
it 'raises exception in outer thread' do
|
473
525
|
check_test_exception(enum) do |threaded|
|
474
526
|
threaded.cycle{ fail TestException }
|
475
527
|
end
|
476
528
|
end
|
477
529
|
end
|
478
530
|
|
479
|
-
|
480
|
-
|
481
|
-
|
482
|
-
|
483
|
-
|
484
|
-
|
531
|
+
%w[grep grep_v].each do |method|
|
532
|
+
describe_enum_method method do
|
533
|
+
let(:matcher){ ValueItem::FastCheckMatcher }
|
534
|
+
|
535
|
+
it 'fires same objects' do
|
536
|
+
enum.each do |o|
|
537
|
+
if o.fast_check? == (method == 'grep')
|
538
|
+
expect(o).to receive(:touch)
|
539
|
+
else
|
540
|
+
expect(o).not_to receive(:touch)
|
541
|
+
end
|
542
|
+
end
|
543
|
+
enum.in_threads.send(method, matcher, &:touch_n_value)
|
485
544
|
end
|
486
|
-
enum.in_threads.grep(matcher, &:touch_n_value)
|
487
|
-
end
|
488
545
|
|
489
|
-
|
490
|
-
|
491
|
-
|
492
|
-
|
546
|
+
it 'returns same with block' do
|
547
|
+
expect(enum.in_threads.send(method, matcher, &:value)).
|
548
|
+
to eq(enum.send(method, matcher, &:value))
|
549
|
+
end
|
493
550
|
|
494
|
-
|
495
|
-
|
496
|
-
|
497
|
-
|
551
|
+
it 'runs faster with threads', :retry => 3 do
|
552
|
+
expect(measure{ enum.in_threads.send(method, matcher, &:value) }).
|
553
|
+
to be < measure{ enum.send(method, matcher, &:value) } * speed_coef
|
554
|
+
end
|
498
555
|
|
499
|
-
|
500
|
-
|
501
|
-
|
556
|
+
it 'returns same without block' do
|
557
|
+
expect(enum.in_threads.send(method, matcher)).
|
558
|
+
to eq(enum.send(method, matcher))
|
559
|
+
end
|
502
560
|
|
503
|
-
|
504
|
-
|
505
|
-
|
561
|
+
it 'raises exception in outer thread' do
|
562
|
+
check_test_exception(enum) do |threaded|
|
563
|
+
threaded.send(method, matcher){ fail TestException }
|
564
|
+
end
|
506
565
|
end
|
507
566
|
end
|
508
567
|
end
|
509
568
|
|
510
569
|
describe_enum_method 'each_entry' do
|
511
|
-
|
512
|
-
|
513
|
-
|
514
|
-
|
515
|
-
|
516
|
-
|
517
|
-
end
|
570
|
+
before do
|
571
|
+
def enum.each
|
572
|
+
10.times{ yield }
|
573
|
+
10.times{ yield 1 }
|
574
|
+
10.times{ yield 2, 3 }
|
575
|
+
10.times{ yield 4, 5, 6 }
|
518
576
|
end
|
519
577
|
end
|
520
578
|
let(:runner){ proc{ |o| ValueItem.new(0, o).value } }
|
521
579
|
|
522
|
-
it '
|
580
|
+
it 'returns same result with threads' do
|
523
581
|
expect(enum.in_threads.each_entry(&runner)).
|
524
582
|
to eq(enum.each_entry(&runner))
|
525
583
|
end
|
526
584
|
|
527
|
-
it '
|
585
|
+
it 'executes block for each element' do
|
528
586
|
@o = double('order')
|
529
|
-
|
530
|
-
|
531
|
-
|
587
|
+
enum.each_entry do |*o|
|
588
|
+
expect(@o).to receive(:notify).with(o)
|
589
|
+
end
|
532
590
|
@mutex = Mutex.new
|
533
|
-
enum.in_threads.each_entry do
|
591
|
+
enum.in_threads.each_entry do |*o|
|
534
592
|
@mutex.synchronize{ @o.notify(o) }
|
535
593
|
runner[]
|
536
594
|
end
|
537
595
|
end
|
538
596
|
|
539
|
-
it '
|
597
|
+
it 'runs faster with threads', :retry => 3 do
|
540
598
|
expect(measure{ enum.in_threads.each_entry(&runner) }).
|
541
599
|
to be < measure{ enum.each_entry(&runner) } * speed_coef
|
542
600
|
end
|
543
601
|
|
544
|
-
it '
|
602
|
+
it 'returns same enum without block' do
|
545
603
|
expect(enum.in_threads.each_entry.to_a).to eq(enum.each_entry.to_a)
|
546
604
|
end
|
547
605
|
|
548
|
-
it '
|
606
|
+
it 'raises exception in outer thread' do
|
549
607
|
check_test_exception(enum) do |threaded|
|
550
608
|
threaded.each_entry{ fail TestException }
|
551
609
|
end
|
@@ -554,15 +612,15 @@ describe 'in_threads' do
|
|
554
612
|
|
555
613
|
%w[flat_map collect_concat].each do |method|
|
556
614
|
describe_enum_method method do
|
557
|
-
let(:
|
615
|
+
let(:items){ Array.new(20){ |i| RandItem.new(i) }.each_slice(3).to_a }
|
558
616
|
let(:runner){ proc{ |a| a.map(&:value) } }
|
559
617
|
|
560
|
-
it '
|
618
|
+
it 'returns same result with threads' do
|
561
619
|
expect(enum.in_threads.send(method, &runner)).
|
562
620
|
to eq(enum.send(method, &runner))
|
563
621
|
end
|
564
622
|
|
565
|
-
it '
|
623
|
+
it 'fires same objects' do
|
566
624
|
enum.send(method) do |a|
|
567
625
|
a.each do |o|
|
568
626
|
expect(o).to receive(:touch).with(a).once
|
@@ -576,17 +634,17 @@ describe 'in_threads' do
|
|
576
634
|
end
|
577
635
|
end
|
578
636
|
|
579
|
-
it '
|
637
|
+
it 'runs faster with threads', :retry => 3 do
|
580
638
|
expect(measure{ enum.in_threads.send(method, &runner) }).
|
581
639
|
to be < measure{ enum.send(method, &runner) } * speed_coef
|
582
640
|
end
|
583
641
|
|
584
|
-
it '
|
642
|
+
it 'returns same enum without block' do
|
585
643
|
expect(enum.in_threads.send(method).to_a).
|
586
644
|
to eq(enum.send(method).to_a)
|
587
645
|
end
|
588
646
|
|
589
|
-
it '
|
647
|
+
it 'raises exception in outer thread' do
|
590
648
|
check_test_exception(enum) do |threaded|
|
591
649
|
threaded.send(method){ fail TestException }
|
592
650
|
end
|
@@ -596,14 +654,14 @@ describe 'in_threads' do
|
|
596
654
|
|
597
655
|
context 'unthreaded' do
|
598
656
|
%w[inject reduce].each do |method|
|
599
|
-
describe method do
|
600
|
-
it '
|
657
|
+
describe "##{method}" do
|
658
|
+
it 'returns same result' do
|
601
659
|
combiner = proc{ |memo, o| memo + o.value }
|
602
660
|
expect(enum.in_threads.send(method, 0, &combiner)).
|
603
661
|
to eq(enum.send(method, 0, &combiner))
|
604
662
|
end
|
605
663
|
|
606
|
-
it '
|
664
|
+
it 'raises exception in outer thread' do
|
607
665
|
check_test_exception(enum) do |threaded|
|
608
666
|
threaded.send(method){ fail TestException }
|
609
667
|
end
|
@@ -612,14 +670,14 @@ describe 'in_threads' do
|
|
612
670
|
end
|
613
671
|
|
614
672
|
%w[max min minmax sort].each do |method|
|
615
|
-
describe method do
|
616
|
-
it '
|
673
|
+
describe "##{method}" do
|
674
|
+
it 'returns same result' do
|
617
675
|
comparer = proc{ |a, b| a.value <=> b.value }
|
618
676
|
expect(enum.in_threads.send(method, &comparer)).
|
619
677
|
to eq(enum.send(method, &comparer))
|
620
678
|
end
|
621
679
|
|
622
|
-
it '
|
680
|
+
it 'raises exception in outer thread' do
|
623
681
|
check_test_exception(enum) do |threaded|
|
624
682
|
threaded.send(method){ fail TestException }
|
625
683
|
end
|
@@ -628,24 +686,24 @@ describe 'in_threads' do
|
|
628
686
|
end
|
629
687
|
|
630
688
|
%w[to_a entries].each do |method|
|
631
|
-
describe method do
|
632
|
-
it '
|
689
|
+
describe "##{method}" do
|
690
|
+
it 'returns same result' do
|
633
691
|
expect(enum.in_threads.send(method)).to eq(enum.send(method))
|
634
692
|
end
|
635
693
|
end
|
636
694
|
end
|
637
695
|
|
638
696
|
%w[drop take].each do |method|
|
639
|
-
describe method do
|
640
|
-
it '
|
697
|
+
describe "##{method}" do
|
698
|
+
it 'returns same result' do
|
641
699
|
expect(enum.in_threads.send(method, 2)).to eq(enum.send(method, 2))
|
642
700
|
end
|
643
701
|
end
|
644
702
|
end
|
645
703
|
|
646
704
|
%w[first].each do |method|
|
647
|
-
describe method do
|
648
|
-
it '
|
705
|
+
describe "##{method}" do
|
706
|
+
it 'returns same result' do
|
649
707
|
expect(enum.in_threads.send(method)).to eq(enum.send(method))
|
650
708
|
expect(enum.in_threads.send(method, 3)).to eq(enum.send(method, 3))
|
651
709
|
end
|
@@ -653,10 +711,10 @@ describe 'in_threads' do
|
|
653
711
|
end
|
654
712
|
|
655
713
|
%w[include? member?].each do |method|
|
656
|
-
describe method do
|
657
|
-
it '
|
658
|
-
expect(enum.in_threads.send(method,
|
659
|
-
to eq(enum.send(method,
|
714
|
+
describe "##{method}" do
|
715
|
+
it 'returns same result' do
|
716
|
+
expect(enum.in_threads.send(method, items[10])).
|
717
|
+
to eq(enum.send(method, items[10]))
|
660
718
|
end
|
661
719
|
end
|
662
720
|
end
|
@@ -664,26 +722,26 @@ describe 'in_threads' do
|
|
664
722
|
describe_enum_method 'each_with_object' do
|
665
723
|
let(:runner){ proc{ |o, h| h[o.value] = true } }
|
666
724
|
|
667
|
-
it '
|
725
|
+
it 'returns same result' do
|
668
726
|
expect(enum.in_threads.each_with_object({}, &runner)).
|
669
727
|
to eq(enum.each_with_object({}, &runner))
|
670
728
|
end
|
671
729
|
|
672
|
-
it '
|
730
|
+
it 'raises exception in outer thread' do
|
673
731
|
check_test_exception(enum) do |threaded|
|
674
732
|
threaded.each_with_object({}){ fail TestException }
|
675
733
|
end
|
676
734
|
end
|
677
735
|
end
|
678
736
|
|
679
|
-
%w[chunk slice_before].each do |method|
|
737
|
+
%w[chunk slice_before slice_after].each do |method|
|
680
738
|
describe_enum_method method do
|
681
|
-
it '
|
739
|
+
it 'returns same result' do
|
682
740
|
expect(enum.in_threads.send(method, &:check?).to_a).
|
683
741
|
to eq(enum.send(method, &:check?).to_a)
|
684
742
|
end
|
685
743
|
|
686
|
-
it '
|
744
|
+
it 'raises exception in outer thread' do
|
687
745
|
check_test_exception(enum) do |threaded|
|
688
746
|
threaded.send(method){ fail TestException }.to_a
|
689
747
|
end
|
metadata
CHANGED
@@ -1,66 +1,66 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: in_threads
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ivan Kuchin
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2017-03-19 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rspec
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- - ~>
|
17
|
+
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
19
|
version: '3.0'
|
20
20
|
type: :development
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
|
-
- - ~>
|
24
|
+
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '3.0'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: rspec-retry
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
|
-
- - ~>
|
31
|
+
- - "~>"
|
32
32
|
- !ruby/object:Gem::Version
|
33
33
|
version: '0.3'
|
34
34
|
type: :development
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
|
-
- - ~>
|
38
|
+
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '0.3'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: rubocop
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
|
-
- - ~>
|
45
|
+
- - "~>"
|
46
46
|
- !ruby/object:Gem::Version
|
47
|
-
version: '0.
|
47
|
+
version: '0.47'
|
48
48
|
type: :development
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
|
-
- - ~>
|
52
|
+
- - "~>"
|
53
53
|
- !ruby/object:Gem::Version
|
54
|
-
version: '0.
|
54
|
+
version: '0.47'
|
55
55
|
description:
|
56
56
|
email:
|
57
57
|
executables: []
|
58
58
|
extensions: []
|
59
59
|
extra_rdoc_files: []
|
60
60
|
files:
|
61
|
-
- .gitignore
|
62
|
-
- .rubocop.yml
|
63
|
-
- .travis.yml
|
61
|
+
- ".gitignore"
|
62
|
+
- ".rubocop.yml"
|
63
|
+
- ".travis.yml"
|
64
64
|
- Gemfile
|
65
65
|
- LICENSE.txt
|
66
66
|
- README.markdown
|
@@ -78,21 +78,20 @@ require_paths:
|
|
78
78
|
- lib
|
79
79
|
required_ruby_version: !ruby/object:Gem::Requirement
|
80
80
|
requirements:
|
81
|
-
- -
|
81
|
+
- - ">="
|
82
82
|
- !ruby/object:Gem::Version
|
83
83
|
version: '0'
|
84
84
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
85
85
|
requirements:
|
86
|
-
- -
|
86
|
+
- - ">="
|
87
87
|
- !ruby/object:Gem::Version
|
88
88
|
version: '0'
|
89
89
|
requirements: []
|
90
90
|
rubyforge_project: in_threads
|
91
|
-
rubygems_version: 2.
|
91
|
+
rubygems_version: 2.6.10
|
92
92
|
signing_key:
|
93
93
|
specification_version: 4
|
94
94
|
summary: Execute ruby code in parallel
|
95
95
|
test_files:
|
96
96
|
- spec/in_threads_spec.rb
|
97
97
|
- spec/spec_helper.rb
|
98
|
-
has_rdoc:
|