rspec-multiprocess_runner 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 4c75ed167254b35531b51f11a1dda272f3587055
4
+ data.tar.gz: c5cb965e6c3e0caaecc65f7e4236124c98d407af
5
+ SHA512:
6
+ metadata.gz: 35139e859a97c7b20cbff792b652be8172c1a70dbed65ac2277bf53a18486092cae8199820782d8747ce4830cbf927ec73f4ae6625888f2939b10a6103668c0e
7
+ data.tar.gz: 79868c598e2dfc09f467ccf9badc6382afce4b9930f6711784bdb7f336878a3921608a8fd240dbaf77fdac6818be1c99816b20687fe29755f9f4259e895738ad
data/CHANGELOG.md CHANGED
@@ -1,3 +1,16 @@
1
+ # 0.2.0
2
+
3
+ * Terminate workers when the coordinator process is interrupted with SIGINT (^C)
4
+ or SIGTERM (`kill` with no args) (#3)
5
+ * Add per-example timeout option. When using `multirspec` or the rake tasks, it
6
+ defaults to 15 seconds (#2)
7
+ * **Breaking change**: per-file timeout is now disabled by default (#2)
8
+ * **Breaking change**: changed arguments for `Coordinator`'s constructor
9
+ * Correct signal used when requesting that stalled processes quit (use TERM
10
+ instead of QUIT)
11
+ * Stop idle processes once there's no work, instead of waiting and stopping
12
+ everything when the suite is complete
13
+
1
14
  # 0.1.0
2
15
 
3
16
  * Initial version
data/README.md CHANGED
@@ -95,16 +95,27 @@ Create a coordinator and tell it to run:
95
95
 
96
96
  worker_count = 4
97
97
  per_file_timeout = 5 * 60 # 5 minutes in seconds
98
- rspec_args = %w(--backtrace)
98
+ rspec_options = %w(--backtrace)
99
99
  files = Dir['**/*_spec.rb']
100
100
 
101
- coordinator = RSpec::MultiprocessRunner::Coordinator(worker_count, per_file_timeout, rspec_args, files)
101
+ coordinator = RSpec::MultiprocessRunner::Coordinator.new(
102
+ worker_count, files,
103
+ {
104
+ file_timeout_seconds: per_file_timeout,
105
+ rspec_options: rspec_options
106
+ }
107
+ )
102
108
  coordinator.run
103
109
 
104
110
  ## Contributing
105
111
 
106
112
  Bug reports and pull requests are welcome on GitHub at https://github.com/cdd/rspec-multiprocess_runner.
107
113
 
114
+ ### Project infrastructure
115
+
116
+ * [Source on GitHub](https://github.com/cdd/rspec-multiprocess_runner)
117
+ * [![Build Status](https://travis-ci.org/cdd/rspec-multiprocess_runner.svg?branch=master)](https://travis-ci.org/cdd/rspec-multiprocess_runner)
118
+ [Continuous Integration on Travis-CI](https://travis-ci.org/cdd/rspec-multiprocess_runner)
108
119
 
109
120
  ## License
110
121
 
data/exe/multirspec CHANGED
@@ -6,11 +6,27 @@ require 'rspec/multiprocess_runner/coordinator'
6
6
  options = RSpec::MultiprocessRunner::CommandLineOptions.new.parse(ARGV.dup)
7
7
  exit(2) unless options
8
8
 
9
- success = RSpec::MultiprocessRunner::Coordinator.new(
9
+ coordinator = RSpec::MultiprocessRunner::Coordinator.new(
10
10
  options.worker_count,
11
- options.file_timeout_seconds,
12
- options.rspec_options,
13
- options.files_to_run
14
- ).run
11
+ options.files_to_run,
12
+ {
13
+ file_timeout_seconds: options.file_timeout_seconds,
14
+ example_timeout_seconds: options.example_timeout_seconds,
15
+ rspec_options: options.rspec_options
16
+ }
17
+ )
18
+
19
+ trap("INT") do
20
+ $stderr.puts "INT happened"
21
+ coordinator.shutdown(print_summary: true)
22
+ Kernel.exit(4)
23
+ end
24
+
25
+ trap("TERM") do
26
+ coordinator.shutdown
27
+ Kernel.exit(3)
28
+ end
29
+
30
+ success = coordinator.run
15
31
 
16
32
  exit(success ? 0 : 1)
@@ -5,12 +5,13 @@ require 'pathname'
5
5
  module RSpec::MultiprocessRunner
6
6
  # @private
7
7
  class CommandLineOptions
8
- attr_accessor :worker_count, :file_timeout_seconds, :rspec_options,
9
- :explicit_files_or_directories, :pattern
8
+ attr_accessor :worker_count, :file_timeout_seconds, :example_timeout_seconds,
9
+ :rspec_options, :explicit_files_or_directories, :pattern
10
10
 
11
11
  def initialize
12
12
  self.worker_count = 3
13
- self.file_timeout_seconds = 300
13
+ self.file_timeout_seconds = nil
14
+ self.example_timeout_seconds = 15
14
15
  self.pattern = "**/*_spec.rb"
15
16
  self.rspec_options = []
16
17
  end
@@ -58,19 +59,31 @@ module RSpec::MultiprocessRunner
58
59
  @help_requested
59
60
  end
60
61
 
62
+ def print_default(default_value)
63
+ if default_value
64
+ "default: #{default_value}"
65
+ else
66
+ "none by default"
67
+ end
68
+ end
69
+
61
70
  def build_parser
62
71
  OptionParser.new do |parser|
63
72
  parser.banner = "#{File.basename $0} [options] [files or directories] [-- rspec options]"
64
73
 
65
- parser.on("-w", "--worker-count COUNT", Integer, "Number of workers to run (default: #{worker_count})") do |n|
74
+ parser.on("-w", "--worker-count COUNT", Integer, "Number of workers to run (#{print_default worker_count})") do |n|
66
75
  self.worker_count = n
67
76
  end
68
77
 
69
- parser.on("-t", "--file-timeout SECONDS", Integer, "Maximum time to allow any single file to run (default: #{file_timeout_seconds})") do |s|
78
+ parser.on("-t", "--file-timeout SECONDS", Float, "Maximum time to allow any single file to run (#{print_default file_timeout_seconds})") do |s|
70
79
  self.file_timeout_seconds = s
71
80
  end
72
81
 
73
- parser.on("-P", "--pattern PATTERN", "A glob to use to select files to run (default: #{pattern})") do |pattern|
82
+ parser.on("-T", "--example-timeout SECONDS", Float, "Maximum time to allow any single example to run (#{print_default example_timeout_seconds})") do |s|
83
+ self.example_timeout_seconds = s
84
+ end
85
+
86
+ parser.on("-P", "--pattern PATTERN", "A glob to use to select files to run (#{print_default pattern})") do |pattern|
74
87
  self.pattern = pattern
75
88
  end
76
89
 
@@ -4,13 +4,14 @@ require 'rspec/multiprocess_runner/worker'
4
4
 
5
5
  module RSpec::MultiprocessRunner
6
6
  class Coordinator
7
- def initialize(worker_count, file_timeout, rspec_options, files)
7
+ def initialize(worker_count, files, options={})
8
8
  @worker_count = worker_count
9
- @file_timeout = file_timeout
10
- @rspec_options = rspec_options
9
+ @file_timeout_seconds = options[:file_timeout_seconds]
10
+ @example_timeout_seconds = options[:example_timeout_seconds]
11
+ @rspec_options = options[:rspec_options]
11
12
  @spec_files = files
12
13
  @workers = []
13
- @deactivated_workers = []
14
+ @stopped_workers = []
14
15
  end
15
16
 
16
17
  def run
@@ -26,7 +27,23 @@ module RSpec::MultiprocessRunner
26
27
  end
27
28
 
28
29
  def failed?
29
- !@deactivated_workers.empty? || any_example_failed?
30
+ !failed_workers.empty? || !@spec_files.empty? || any_example_failed?
31
+ end
32
+
33
+ def shutdown(options={})
34
+ if @shutting_down
35
+ # Immediately kill the workers if shutdown is requested again
36
+ end_workers_in_parallel(@workers.dup, :kill_now)
37
+ else
38
+ @shutting_down = true
39
+ print "Shutting down #{pluralize(@workers.size, "worker")} …" if options[:print_summary]
40
+ # end_workers_in_parallel modifies @workers, so dup before sending in
41
+ end_workers_in_parallel(@workers.dup, :shutdown_now)
42
+ if options[:print_summary]
43
+ puts " done"
44
+ print_summary
45
+ end
46
+ end
30
47
  end
31
48
 
32
49
  private
@@ -40,28 +57,46 @@ module RSpec::MultiprocessRunner
40
57
  act_on_available_worker_messages(0.3)
41
58
  reap_stalled_workers
42
59
  start_missing_workers
60
+ quit_idle_unnecessary_workers
43
61
  break unless @workers.detect(&:working?)
44
62
  end
45
63
  end
46
64
 
47
65
  def quit_all_workers
48
- quit_threads = @workers.map do |worker|
66
+ # quit_workers modifies @workers, so dup before sending in
67
+ quit_workers(@workers.dup)
68
+ end
69
+
70
+ def end_workers_in_parallel(some_workers, end_method)
71
+ end_threads = some_workers.map do |worker|
72
+ # This method is not threadsafe because it updates instance variables.
73
+ # But it's fine to run it outside of the thread because it doesn't
74
+ # block.
75
+ mark_worker_as_stopped(worker)
49
76
  Thread.new do
50
- worker.quit
51
- worker.wait_until_quit
77
+ worker.send(end_method)
52
78
  end
53
79
  end
54
- quit_threads.each(&:join)
80
+ end_threads.each(&:join)
81
+ end
82
+
83
+ def quit_workers(some_workers)
84
+ end_workers_in_parallel(some_workers, :quit_when_idle_and_wait_for_quit)
55
85
  end
56
86
 
57
87
  def work_left_to_do?
58
88
  !@spec_files.empty?
59
89
  end
60
90
 
91
+ def failed_workers
92
+ @stopped_workers.select { |w| w.deactivation_reason }
93
+ end
94
+
61
95
  def act_on_available_worker_messages(timeout)
62
96
  while (select_result = IO.select(worker_sockets, nil, nil, timeout))
63
97
  select_result.first.each do |readable_socket|
64
98
  ready_worker = @workers.detect { |worker| worker.socket == readable_socket }
99
+ next unless ready_worker # Worker is already gone
65
100
  worker_status = ready_worker.receive_and_act_on_message_from_worker
66
101
  if worker_status == :dead
67
102
  reap_one_worker(ready_worker, "died")
@@ -74,8 +109,12 @@ module RSpec::MultiprocessRunner
74
109
 
75
110
  def reap_one_worker(worker, reason)
76
111
  worker.reap
77
- @deactivated_workers << worker
78
112
  worker.deactivation_reason = reason
113
+ mark_worker_as_stopped(worker)
114
+ end
115
+
116
+ def mark_worker_as_stopped(worker)
117
+ @stopped_workers << worker
79
118
  @workers.reject! { |w| w == worker }
80
119
  end
81
120
 
@@ -92,7 +131,12 @@ module RSpec::MultiprocessRunner
92
131
  def create_and_start_worker_if_necessary(n)
93
132
  if work_left_to_do?
94
133
  $stderr.puts "(Re)starting worker #{n}"
95
- new_worker = Worker.new(n, @file_timeout, @rspec_options)
134
+ new_worker = Worker.new(
135
+ n,
136
+ file_timeout_seconds: @file_timeout_seconds,
137
+ example_timeout_seconds: @example_timeout_seconds,
138
+ rspec_options: @rspec_options
139
+ )
96
140
  @workers << new_worker
97
141
  new_worker.start
98
142
  new_worker.run_file(@spec_files.shift)
@@ -109,11 +153,19 @@ module RSpec::MultiprocessRunner
109
153
  end
110
154
  end
111
155
 
156
+ def quit_idle_unnecessary_workers
157
+ unless work_left_to_do?
158
+ idle_workers = @workers.reject(&:working?)
159
+ quit_workers(idle_workers)
160
+ end
161
+ end
162
+
112
163
  def print_summary
113
164
  elapsed = Time.now - @start_time
114
165
  by_status_and_time = combine_example_results.each_with_object({}) do |result, idx|
115
166
  (idx[result.status] ||= []) << result
116
167
  end
168
+ print_skipped_files_details
117
169
  print_pending_example_details(by_status_and_time["pending"])
118
170
  print_failed_example_details(by_status_and_time["failed"])
119
171
  print_failed_process_details
@@ -124,11 +176,20 @@ module RSpec::MultiprocessRunner
124
176
  end
125
177
 
126
178
  def combine_example_results
127
- (@workers + @deactivated_workers).flat_map(&:example_results).sort_by { |r| r.time_finished }
179
+ (@workers + @stopped_workers).flat_map(&:example_results).sort_by { |r| r.time_finished }
128
180
  end
129
181
 
130
182
  def any_example_failed?
131
- (@workers + @deactivated_workers).detect { |w| w.example_results.detect { |r| r.status == "failed" } }
183
+ (@workers + @stopped_workers).detect { |w| w.example_results.detect { |r| r.status == "failed" } }
184
+ end
185
+
186
+ def print_skipped_files_details
187
+ return if @spec_files.empty?
188
+ puts
189
+ puts "Skipped files:"
190
+ @spec_files.each do |spec_file|
191
+ puts " - #{spec_file}"
192
+ end
132
193
  end
133
194
 
134
195
  def print_pending_example_details(pending_example_results)
@@ -161,21 +222,23 @@ module RSpec::MultiprocessRunner
161
222
  example_count = by_status_and_time.map { |status, results| results.size }.inject(0) { |sum, ct| sum + ct }
162
223
  failure_count = by_status_and_time["failed"] ? by_status_and_time["failed"].size : 0
163
224
  pending_count = by_status_and_time["pending"] ? by_status_and_time["pending"].size : 0
164
- process_failure_count = @deactivated_workers.size
225
+ process_failure_count = failed_workers.size
226
+ skipped_count = @spec_files.size
165
227
 
166
228
  # Copied from RSpec
167
229
  summary = pluralize(example_count, "example")
168
230
  summary << ", " << pluralize(failure_count, "failure")
169
231
  summary << ", #{pending_count} pending" if pending_count > 0
170
232
  summary << ", " << pluralize(process_failure_count, "failed proc") if process_failure_count > 0
233
+ summary << ", " << pluralize(skipped_count, "skipped file") if skipped_count > 0
171
234
  puts summary
172
235
  end
173
236
 
174
237
  def print_failed_process_details
175
- return if @deactivated_workers.empty?
238
+ return if failed_workers.empty?
176
239
  puts
177
240
  puts "Failed processes:"
178
- @deactivated_workers.each do |worker|
241
+ failed_workers.each do |worker|
179
242
  puts " - #{worker.pid} (env #{worker.environment_number}) #{worker.deactivation_reason} on #{worker.current_file}"
180
243
  end
181
244
  end
@@ -30,9 +30,13 @@ module RSpec::MultiprocessRunner
30
30
  attr_accessor :worker_count
31
31
 
32
32
  # The maximum number of seconds to allow a single spec file to run
33
- # before killing it. Defaults to 300.
33
+ # before killing it. Defaults to disabled.
34
34
  attr_accessor :file_timeout_seconds
35
35
 
36
+ # The maximum number of seconds to allow a single example to run
37
+ # before killing it. Defaults to 15.
38
+ attr_accessor :example_timeout_seconds
39
+
36
40
  # Whether or not to fail Rake when an error occurs (typically when
37
41
  # examples fail). Defaults to `true`.
38
42
  attr_accessor :fail_on_error
@@ -94,6 +98,9 @@ module RSpec::MultiprocessRunner
94
98
  if worker_count
95
99
  cmd_parts << '--worker-count' << worker_count.to_s
96
100
  end
101
+ if example_timeout_seconds
102
+ cmd_parts << '--example-timeout' << example_timeout_seconds.to_s
103
+ end
97
104
  if file_timeout_seconds
98
105
  cmd_parts << '--file-timeout' << file_timeout_seconds.to_s
99
106
  end
@@ -1,5 +1,5 @@
1
1
  module RSpec
2
2
  module MultiprocessRunner
3
- VERSION = "0.1.0"
3
+ VERSION = "0.2.0"
4
4
  end
5
5
  end
@@ -29,11 +29,12 @@ module RSpec::MultiprocessRunner
29
29
  STATUS_EXAMPLE_COMPLETE = "example_complete"
30
30
  STATUS_RUN_COMPLETE = "run_complete"
31
31
 
32
- def initialize(environment_number, file_timeout, rspec_arguments=[])
32
+ def initialize(environment_number, options)
33
33
  @environment_number = environment_number
34
34
  @worker_socket, @coordinator_socket = Socket.pair(:UNIX, :STREAM)
35
- @rspec_arguments = rspec_arguments + ["--format", ReportingFormatter.to_s]
36
- @file_timeout = file_timeout
35
+ @rspec_arguments = (options[:rspec_options] || []) + ["--format", ReportingFormatter.to_s]
36
+ @example_timeout_seconds = options[:example_timeout_seconds]
37
+ @file_timeout_seconds = options[:file_timeout_seconds]
37
38
  @example_results = []
38
39
 
39
40
  # Use a single configuration and world across all individual runs
@@ -65,6 +66,17 @@ module RSpec::MultiprocessRunner
65
66
  @coordinator_socket.close
66
67
  @pid = Process.pid
67
68
  ENV["TEST_ENV_NUMBER"] = environment_number.to_s
69
+
70
+ # reset TERM handler so that
71
+ # - the coordinator's version (if any) is not executed twice
72
+ # - it actually terminates the process, instead of doing the ruby
73
+ # default (throw an exception, which gets caught by RSpec)
74
+ Kernel.trap("TERM", "SYSTEM_DEFAULT")
75
+ # rely on the coordinator to handle INT
76
+ Kernel.trap("INT", "IGNORE")
77
+ # prevent RSpec from trapping INT, also
78
+ ::RSpec::Core::Runner.instance_eval { def self.trap_interrupt; end }
79
+
68
80
  set_process_name
69
81
  run_loop
70
82
  end
@@ -84,18 +96,15 @@ module RSpec::MultiprocessRunner
84
96
 
85
97
  public
86
98
 
87
- def quit
99
+ def quit_when_idle_and_wait_for_quit
88
100
  send_message_to_worker(command: COMMAND_QUIT)
89
- end
90
-
91
- def wait_until_quit
92
101
  Process.wait(self.pid)
93
102
  end
94
103
 
95
104
  def run_file(filename)
96
105
  send_message_to_worker(command: COMMAND_RUN_FILE, filename: filename)
97
106
  @current_file = filename
98
- @current_file_started_at = Time.now
107
+ @current_file_started_at = @current_example_started_at = Time.now
99
108
  end
100
109
 
101
110
  def working?
@@ -103,21 +112,28 @@ module RSpec::MultiprocessRunner
103
112
  end
104
113
 
105
114
  def stalled?
106
- working? && (Time.now - @current_file_started_at > @file_timeout)
115
+ file_stalled =
116
+ if @file_timeout_seconds
117
+ working? && (Time.now - @current_file_started_at > @file_timeout_seconds)
118
+ end
119
+ example_stalled =
120
+ if @example_timeout_seconds
121
+ working? && (Time.now - @current_example_started_at > @example_timeout_seconds)
122
+ end
123
+ file_stalled || example_stalled
124
+ end
125
+
126
+ def shutdown_now
127
+ terminate_then_kill(5)
128
+ end
129
+
130
+ def kill_now
131
+ Process.kill(:KILL, pid)
132
+ Process.detach(pid)
107
133
  end
108
134
 
109
135
  def reap
110
- begin
111
- Timeout.timeout(4) do
112
- $stderr.puts "Reaping troubled process #{environment_number} (#{pid}; #{@current_file}) with QUIT"
113
- Process.kill(:QUIT, pid)
114
- Process.wait(pid)
115
- end
116
- rescue Timeout::Error
117
- $stderr.puts "Reaping troubled process #{environment_number} (#{pid}) with KILL"
118
- Process.kill(:KILL, pid)
119
- Process.wait(pid)
120
- end
136
+ terminate_then_kill(3, "Reaping troubled process #{environment_number} (#{pid}; #{@current_file})")
121
137
  end
122
138
 
123
139
  def receive_and_act_on_message_from_worker
@@ -126,6 +142,19 @@ module RSpec::MultiprocessRunner
126
142
 
127
143
  private
128
144
 
145
+ def terminate_then_kill(timeout, message=nil)
146
+ begin
147
+ Timeout.timeout(timeout) do
148
+ $stderr.puts "#{message} with TERM" if message
149
+ Process.kill(:TERM, pid)
150
+ Process.wait(pid)
151
+ end
152
+ rescue Timeout::Error
153
+ $stderr.puts "#{message} with KILL" if message
154
+ kill_now
155
+ end
156
+ end
157
+
129
158
  def receive_message_from_worker
130
159
  receive_message(@coordinator_socket)
131
160
  end
@@ -136,6 +165,7 @@ module RSpec::MultiprocessRunner
136
165
  when STATUS_RUN_COMPLETE
137
166
  @current_file = nil
138
167
  @current_file_started_at = nil
168
+ @current_example_started_at = nil
139
169
  when STATUS_EXAMPLE_COMPLETE
140
170
  example_results << ExampleResult.new(message_hash)
141
171
  suffix =
@@ -149,6 +179,7 @@ module RSpec::MultiprocessRunner
149
179
  suffix += "\n#{message_hash["details"]}"
150
180
  end
151
181
  $stdout.puts "#{environment_number} (#{pid}): #{message_hash["description"]}#{suffix}"
182
+ @current_example_started_at = Time.now
152
183
  else
153
184
  $stderr.puts "Received unsupported status #{message_hash["status"].inspect} in worker #{pid}"
154
185
  end
@@ -194,16 +225,25 @@ module RSpec::MultiprocessRunner
194
225
  end
195
226
  end
196
227
 
228
+ def handle_closed_coordinator_socket
229
+ # when the coordinator socket is closed, there's nothing more to do
230
+ exit
231
+ end
232
+
197
233
  def receive_message_from_coordinator(socket)
198
234
  receive_message(socket)
199
235
  end
200
236
 
201
237
  def send_message_to_coordinator(message_hash)
202
- send_message(@worker_socket, message_hash)
238
+ begin
239
+ send_message(@worker_socket, message_hash)
240
+ rescue Errno::EPIPE
241
+ handle_closed_coordinator_socket
242
+ end
203
243
  end
204
244
 
205
245
  def act_on_message_from_coordinator(message_hash)
206
- return unless message_hash # ignore EOF
246
+ return handle_closed_coordinator_socket unless message_hash # EOF
207
247
  case message_hash["command"]
208
248
  when "quit"
209
249
  exit
metadata CHANGED
@@ -1,84 +1,75 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rspec-multiprocess_runner
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
5
- prerelease:
4
+ version: 0.2.0
6
5
  platform: ruby
7
6
  authors:
8
7
  - Rhett Sutphin
9
8
  autorequire:
10
9
  bindir: exe
11
10
  cert_chain: []
12
- date: 2015-12-15 00:00:00.000000000 Z
11
+ date: 2015-12-24 00:00:00.000000000 Z
13
12
  dependencies:
14
13
  - !ruby/object:Gem::Dependency
15
14
  name: rspec-core
16
15
  requirement: !ruby/object:Gem::Requirement
17
- none: false
18
16
  requirements:
19
- - - ~>
17
+ - - "~>"
20
18
  - !ruby/object:Gem::Version
21
19
  version: '2.0'
22
- - - <
20
+ - - "<"
23
21
  - !ruby/object:Gem::Version
24
22
  version: 2.99.0
25
23
  type: :runtime
26
24
  prerelease: false
27
25
  version_requirements: !ruby/object:Gem::Requirement
28
- none: false
29
26
  requirements:
30
- - - ~>
27
+ - - "~>"
31
28
  - !ruby/object:Gem::Version
32
29
  version: '2.0'
33
- - - <
30
+ - - "<"
34
31
  - !ruby/object:Gem::Version
35
32
  version: 2.99.0
36
33
  - !ruby/object:Gem::Dependency
37
34
  name: bundler
38
35
  requirement: !ruby/object:Gem::Requirement
39
- none: false
40
36
  requirements:
41
- - - ~>
37
+ - - "~>"
42
38
  - !ruby/object:Gem::Version
43
39
  version: '1.10'
44
40
  type: :development
45
41
  prerelease: false
46
42
  version_requirements: !ruby/object:Gem::Requirement
47
- none: false
48
43
  requirements:
49
- - - ~>
44
+ - - "~>"
50
45
  - !ruby/object:Gem::Version
51
46
  version: '1.10'
52
47
  - !ruby/object:Gem::Dependency
53
48
  name: rake
54
49
  requirement: !ruby/object:Gem::Requirement
55
- none: false
56
50
  requirements:
57
- - - ~>
51
+ - - "~>"
58
52
  - !ruby/object:Gem::Version
59
53
  version: '10.0'
60
54
  type: :development
61
55
  prerelease: false
62
56
  version_requirements: !ruby/object:Gem::Requirement
63
- none: false
64
57
  requirements:
65
- - - ~>
58
+ - - "~>"
66
59
  - !ruby/object:Gem::Version
67
60
  version: '10.0'
68
61
  - !ruby/object:Gem::Dependency
69
62
  name: rspec
70
63
  requirement: !ruby/object:Gem::Requirement
71
- none: false
72
64
  requirements:
73
- - - ! '>='
65
+ - - ">="
74
66
  - !ruby/object:Gem::Version
75
67
  version: '0'
76
68
  type: :development
77
69
  prerelease: false
78
70
  version_requirements: !ruby/object:Gem::Requirement
79
- none: false
80
71
  requirements:
81
- - - ! '>='
72
+ - - ">="
82
73
  - !ruby/object:Gem::Version
83
74
  version: '0'
84
75
  description:
@@ -89,9 +80,9 @@ executables:
89
80
  extensions: []
90
81
  extra_rdoc_files: []
91
82
  files:
92
- - .gitignore
93
- - .rspec
94
- - .travis.yml
83
+ - ".gitignore"
84
+ - ".rspec"
85
+ - ".travis.yml"
95
86
  - CHANGELOG.md
96
87
  - Gemfile
97
88
  - LICENSE.txt
@@ -112,32 +103,25 @@ files:
112
103
  homepage: https://github.com/cdd/rspec-multiprocess_runner
113
104
  licenses:
114
105
  - MIT
106
+ metadata: {}
115
107
  post_install_message:
116
108
  rdoc_options: []
117
109
  require_paths:
118
110
  - lib
119
111
  required_ruby_version: !ruby/object:Gem::Requirement
120
- none: false
121
112
  requirements:
122
- - - ! '>='
113
+ - - ">="
123
114
  - !ruby/object:Gem::Version
124
115
  version: '0'
125
- segments:
126
- - 0
127
- hash: -1609184745420465239
128
116
  required_rubygems_version: !ruby/object:Gem::Requirement
129
- none: false
130
117
  requirements:
131
- - - ! '>='
118
+ - - ">="
132
119
  - !ruby/object:Gem::Version
133
120
  version: '0'
134
- segments:
135
- - 0
136
- hash: -1609184745420465239
137
121
  requirements: []
138
122
  rubyforge_project:
139
- rubygems_version: 1.8.25
123
+ rubygems_version: 2.4.5.1
140
124
  signing_key:
141
- specification_version: 3
125
+ specification_version: 4
142
126
  summary: A runner for RSpec 2 that uses multiple processes to execute specs in parallel
143
127
  test_files: []