rspec-support 3.13.6 → 4.0.0.beta1
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 +4 -4
- checksums.yaml.gz.sig +0 -0
- data/Changelog.md +32 -4
- data/LICENSE.md +9 -6
- data/README.md +6 -38
- data/lib/rspec/support/caller_filter.rb +36 -47
- data/lib/rspec/support/differ.rb +33 -14
- data/lib/rspec/support/directory_maker.rb +0 -2
- data/lib/rspec/support/encoded_string.rb +63 -80
- data/lib/rspec/support/fuzzy_matcher.rb +4 -2
- data/lib/rspec/support/method_signature_verifier.rb +87 -149
- data/lib/rspec/support/object_formatter.rb +3 -28
- data/lib/rspec/support/recursive_const_methods.rb +16 -39
- data/lib/rspec/support/reentrant_mutex.rb +16 -46
- data/lib/rspec/support/ruby_features.rb +18 -138
- data/lib/rspec/support/source.rb +3 -12
- data/lib/rspec/support/spec/coverage.rb +50 -0
- data/lib/rspec/support/spec/in_sub_process.rb +1 -1
- data/lib/rspec/support/spec/library_wide_checks.rb +9 -12
- data/lib/rspec/support/spec/shell_out.rb +3 -25
- data/lib/rspec/support/spec/stderr_splitter.rb +7 -20
- data/lib/rspec/support/spec/string_matcher.rb +18 -28
- data/lib/rspec/support/spec.rb +3 -41
- data/lib/rspec/support/version.rb +1 -1
- data/lib/rspec/support/with_keywords_when_needed.rb +8 -17
- data/lib/rspec/support.rb +21 -51
- data.tar.gz.sig +0 -0
- metadata +22 -51
- metadata.gz.sig +0 -0
- data/lib/rspec/support/mutex.rb +0 -75
- data/lib/rspec/support/spec/diff_helpers.rb +0 -45
|
@@ -10,7 +10,7 @@ module RSpec
|
|
|
10
10
|
# keyword args of a given method.
|
|
11
11
|
#
|
|
12
12
|
# @private
|
|
13
|
-
class MethodSignature
|
|
13
|
+
class MethodSignature
|
|
14
14
|
attr_reader :min_non_kw_args, :max_non_kw_args, :optional_kw_args, :required_kw_args
|
|
15
15
|
|
|
16
16
|
def initialize(method)
|
|
@@ -47,141 +47,98 @@ module RSpec
|
|
|
47
47
|
end
|
|
48
48
|
end
|
|
49
49
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
parts = []
|
|
50
|
+
def description
|
|
51
|
+
@description ||= begin
|
|
52
|
+
parts = []
|
|
54
53
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
end
|
|
58
|
-
|
|
59
|
-
if @optional_kw_args.any?
|
|
60
|
-
parts << "optional keyword args (#{@optional_kw_args.map(&:inspect).join(", ")})"
|
|
61
|
-
end
|
|
62
|
-
|
|
63
|
-
if @required_kw_args.any?
|
|
64
|
-
parts << "required keyword args (#{@required_kw_args.map(&:inspect).join(", ")})"
|
|
65
|
-
end
|
|
66
|
-
|
|
67
|
-
parts << "any additional keyword args" if @allows_any_kw_args
|
|
68
|
-
|
|
69
|
-
parts.join(" and ")
|
|
54
|
+
unless non_kw_args_arity_description == "0"
|
|
55
|
+
parts << "arity of #{non_kw_args_arity_description}"
|
|
70
56
|
end
|
|
71
|
-
end
|
|
72
|
-
|
|
73
|
-
def missing_kw_args_from(given_kw_args)
|
|
74
|
-
@required_kw_args - given_kw_args
|
|
75
|
-
end
|
|
76
|
-
|
|
77
|
-
def invalid_kw_args_from(given_kw_args)
|
|
78
|
-
return [] if @allows_any_kw_args
|
|
79
|
-
given_kw_args - @allowed_kw_args
|
|
80
|
-
end
|
|
81
57
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
def has_kw_args_in?(args)
|
|
85
|
-
# If the last arg is a hash, depending on the signature it could be kw_args or a positional parameter.
|
|
86
|
-
return false unless Hash === args.last && could_contain_kw_args?(args)
|
|
87
|
-
|
|
88
|
-
# If the position of the hash is beyond the count of required and optional positional
|
|
89
|
-
# args then it is the kwargs hash
|
|
90
|
-
return true if args.count > @max_non_kw_args
|
|
91
|
-
|
|
92
|
-
# This is the proper way to disambiguate between positional args and keywords hash
|
|
93
|
-
# but relies on beginning of the call chain annotating the method with
|
|
94
|
-
# ruby2_keywords, so only use it for positive feedback as without the annotation
|
|
95
|
-
# this is always false
|
|
96
|
-
return true if Hash.ruby2_keywords_hash?(args[-1])
|
|
97
|
-
|
|
98
|
-
# Otherwise, the hash could be defined kw_args or an optional positional parameter
|
|
99
|
-
# inspect the keys against known kwargs to determine what it is
|
|
100
|
-
# Note: the problem with this is that if a user passes only invalid keyword args,
|
|
101
|
-
# rspec no longer detects is and will assign this to a positional argument
|
|
102
|
-
return arbitrary_kw_args? || args.last.keys.all? { |x| @allowed_kw_args.include?(x) }
|
|
103
|
-
end
|
|
104
|
-
else
|
|
105
|
-
def has_kw_args_in?(args)
|
|
106
|
-
# Version <= Ruby 2.7
|
|
107
|
-
# If the last argument is Hash, Ruby will treat only symbol keys as keyword arguments
|
|
108
|
-
# the rest will be grouped in another Hash and passed as positional argument.
|
|
109
|
-
Hash === args.last &&
|
|
110
|
-
could_contain_kw_args?(args) &&
|
|
111
|
-
(args.last.empty? || args.last.keys.any? { |x| x.is_a?(Symbol) })
|
|
58
|
+
if @optional_kw_args.any?
|
|
59
|
+
parts << "optional keyword args (#{@optional_kw_args.map(&:inspect).join(", ")})"
|
|
112
60
|
end
|
|
113
|
-
end
|
|
114
|
-
|
|
115
|
-
# Without considering what the last arg is, could it
|
|
116
|
-
# contain keyword arguments?
|
|
117
|
-
def could_contain_kw_args?(args)
|
|
118
|
-
return false if args.count <= min_non_kw_args
|
|
119
61
|
|
|
120
|
-
|
|
121
|
-
|
|
62
|
+
if @required_kw_args.any?
|
|
63
|
+
parts << "required keyword args (#{@required_kw_args.map(&:inspect).join(", ")})"
|
|
64
|
+
end
|
|
122
65
|
|
|
123
|
-
|
|
124
|
-
@allows_any_kw_args
|
|
125
|
-
end
|
|
66
|
+
parts << "any additional keyword args" if @allows_any_kw_args
|
|
126
67
|
|
|
127
|
-
|
|
128
|
-
@max_non_kw_args == INFINITY
|
|
68
|
+
parts.join(" and ")
|
|
129
69
|
end
|
|
70
|
+
end
|
|
130
71
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
@method.parameters.each do |(type, name)|
|
|
136
|
-
case type
|
|
137
|
-
# def foo(a:)
|
|
138
|
-
when :keyreq then @required_kw_args << name
|
|
139
|
-
# def foo(a: 1)
|
|
140
|
-
when :key then @optional_kw_args << name
|
|
141
|
-
# def foo(**kw_args)
|
|
142
|
-
when :keyrest then @allows_any_kw_args = true
|
|
143
|
-
# def foo(a)
|
|
144
|
-
when :req then @min_non_kw_args += 1
|
|
145
|
-
# def foo(a = 1)
|
|
146
|
-
when :opt then optional_non_kw_args += 1
|
|
147
|
-
# def foo(*a)
|
|
148
|
-
when :rest then optional_non_kw_args = INFINITY
|
|
149
|
-
end
|
|
150
|
-
end
|
|
72
|
+
def missing_kw_args_from(given_kw_args)
|
|
73
|
+
@required_kw_args - given_kw_args
|
|
74
|
+
end
|
|
151
75
|
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
def description
|
|
157
|
-
"arity of #{non_kw_args_arity_description}"
|
|
158
|
-
end
|
|
76
|
+
def invalid_kw_args_from(given_kw_args)
|
|
77
|
+
return [] if @allows_any_kw_args
|
|
78
|
+
given_kw_args - @allowed_kw_args
|
|
79
|
+
end
|
|
159
80
|
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
81
|
+
# Considering the arg types, are there kw_args?
|
|
82
|
+
def has_kw_args_in?(args)
|
|
83
|
+
# If the last arg is a hash, depending on the signature it could be kw_args or a positional parameter.
|
|
84
|
+
return false unless Hash === args.last && could_contain_kw_args?(args)
|
|
85
|
+
|
|
86
|
+
# If the position of the hash is beyond the count of required and optional positional
|
|
87
|
+
# args then it is the kwargs hash
|
|
88
|
+
return true if args.count > @max_non_kw_args
|
|
89
|
+
|
|
90
|
+
# This is the proper way to disambiguate between positional args and keywords hash
|
|
91
|
+
# but relies on beginning of the call chain annotating the method with
|
|
92
|
+
# ruby2_keywords, so only use it for positive feedback as without the annotation
|
|
93
|
+
# this is always false
|
|
94
|
+
return true if Hash.ruby2_keywords_hash?(args[-1])
|
|
95
|
+
|
|
96
|
+
# Otherwise, the hash could be defined kw_args or an optional positional parameter
|
|
97
|
+
# inspect the keys against known kwargs to determine what it is
|
|
98
|
+
# Note: the problem with this is that if a user passes only invalid keyword args,
|
|
99
|
+
# rspec no longer detects is and will assign this to a positional argument
|
|
100
|
+
return arbitrary_kw_args? || args.last.keys.all? { |x| @allowed_kw_args.include?(x) }
|
|
101
|
+
end
|
|
163
102
|
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
103
|
+
# Without considering what the last arg is, could it
|
|
104
|
+
# contain keyword arguments?
|
|
105
|
+
def could_contain_kw_args?(args)
|
|
106
|
+
return false if args.count <= min_non_kw_args
|
|
167
107
|
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
end
|
|
108
|
+
@allows_any_kw_args || @allowed_kw_args.any?
|
|
109
|
+
end
|
|
171
110
|
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
111
|
+
def arbitrary_kw_args?
|
|
112
|
+
@allows_any_kw_args
|
|
113
|
+
end
|
|
175
114
|
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
115
|
+
def unlimited_args?
|
|
116
|
+
@max_non_kw_args == INFINITY
|
|
117
|
+
end
|
|
179
118
|
|
|
180
|
-
|
|
181
|
-
|
|
119
|
+
def classify_parameters
|
|
120
|
+
optional_non_kw_args = @min_non_kw_args = 0
|
|
121
|
+
@allows_any_kw_args = false
|
|
122
|
+
|
|
123
|
+
@method.parameters.each do |(type, name)|
|
|
124
|
+
case type
|
|
125
|
+
# def foo(a:)
|
|
126
|
+
when :keyreq then @required_kw_args << name
|
|
127
|
+
# def foo(a: 1)
|
|
128
|
+
when :key then @optional_kw_args << name
|
|
129
|
+
# def foo(**kw_args)
|
|
130
|
+
when :keyrest then @allows_any_kw_args = true
|
|
131
|
+
# def foo(a)
|
|
132
|
+
when :req then @min_non_kw_args += 1
|
|
133
|
+
# def foo(a = 1)
|
|
134
|
+
when :opt then optional_non_kw_args += 1
|
|
135
|
+
# def foo(*a)
|
|
136
|
+
when :rest then optional_non_kw_args = INFINITY
|
|
137
|
+
end
|
|
182
138
|
end
|
|
183
139
|
|
|
184
|
-
|
|
140
|
+
@max_non_kw_args = @min_non_kw_args + optional_non_kw_args
|
|
141
|
+
@allowed_kw_args = @required_kw_args + @optional_kw_args
|
|
185
142
|
end
|
|
186
143
|
|
|
187
144
|
INFINITY = 1 / 0.0
|
|
@@ -190,8 +147,7 @@ module RSpec
|
|
|
190
147
|
if RSpec::Support::Ruby.jruby?
|
|
191
148
|
# JRuby has only partial support for UnboundMethod#parameters, so we fall back on using #arity
|
|
192
149
|
# https://github.com/jruby/jruby/issues/2816 and https://github.com/jruby/jruby/issues/2817
|
|
193
|
-
if
|
|
194
|
-
Java::JavaLang::String.instance_method(:char_at).parameters == []
|
|
150
|
+
if Java::JavaLang::String.instance_method(:char_at).parameters == []
|
|
195
151
|
|
|
196
152
|
class MethodSignature < remove_const(:MethodSignature)
|
|
197
153
|
private
|
|
@@ -277,7 +233,10 @@ module RSpec
|
|
|
277
233
|
end
|
|
278
234
|
|
|
279
235
|
def keywords=(values)
|
|
236
|
+
# until RSpec 4
|
|
237
|
+
# rubocop:disable Lint/UselessOr
|
|
280
238
|
@keywords = values.to_a || []
|
|
239
|
+
# rubocop:enable Lint/UselessOr
|
|
281
240
|
end
|
|
282
241
|
end
|
|
283
242
|
|
|
@@ -291,11 +250,9 @@ module RSpec
|
|
|
291
250
|
#
|
|
292
251
|
# @api private
|
|
293
252
|
class BlockSignature < MethodSignature
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
@min_non_kw_args = @max_non_kw_args unless @max_non_kw_args == INFINITY
|
|
298
|
-
end
|
|
253
|
+
def classify_parameters
|
|
254
|
+
super
|
|
255
|
+
@min_non_kw_args = @max_non_kw_args unless @max_non_kw_args == INFINITY
|
|
299
256
|
end
|
|
300
257
|
end
|
|
301
258
|
|
|
@@ -312,7 +269,7 @@ module RSpec
|
|
|
312
269
|
@arbitrary_kw_args = @unlimited_args = false
|
|
313
270
|
end
|
|
314
271
|
|
|
315
|
-
def with_expectation(expectation)
|
|
272
|
+
def with_expectation(expectation)
|
|
316
273
|
return self unless MethodSignatureExpectation === expectation
|
|
317
274
|
|
|
318
275
|
if expectation.empty?
|
|
@@ -322,19 +279,9 @@ module RSpec
|
|
|
322
279
|
@min_non_kw_args = @non_kw_args = expectation.min_count || 0
|
|
323
280
|
@max_non_kw_args = expectation.max_count || @min_non_kw_args
|
|
324
281
|
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
@unlimited_args = false
|
|
329
|
-
end
|
|
330
|
-
|
|
331
|
-
if RubyFeatures.kw_args_supported?
|
|
332
|
-
@kw_args = expectation.keywords
|
|
333
|
-
@arbitrary_kw_args = expectation.expect_arbitrary_keywords
|
|
334
|
-
else
|
|
335
|
-
@kw_args = []
|
|
336
|
-
@arbitrary_kw_args = false
|
|
337
|
-
end
|
|
282
|
+
@unlimited_args = expectation.expect_unlimited_arguments
|
|
283
|
+
@kw_args = expectation.keywords
|
|
284
|
+
@arbitrary_kw_args = expectation.expect_arbitrary_keywords
|
|
338
285
|
end
|
|
339
286
|
|
|
340
287
|
self
|
|
@@ -388,16 +335,7 @@ module RSpec
|
|
|
388
335
|
end
|
|
389
336
|
|
|
390
337
|
def split_args(args)
|
|
391
|
-
kw_args = if @signature.has_kw_args_in?(args)
|
|
392
|
-
last = args.pop
|
|
393
|
-
non_kw_args = last.reject { |k, _| k.is_a?(Symbol) }
|
|
394
|
-
if non_kw_args.empty?
|
|
395
|
-
last.keys
|
|
396
|
-
else
|
|
397
|
-
args << non_kw_args
|
|
398
|
-
last.select { |k, _| k.is_a?(Symbol) }.keys
|
|
399
|
-
end
|
|
400
|
-
elsif @signature.has_kw_args_in?(args) && RubyFeatures.kw_arg_separation?
|
|
338
|
+
kw_args = if @signature.has_kw_args_in?(args)
|
|
401
339
|
args.pop.keys
|
|
402
340
|
else
|
|
403
341
|
[]
|
|
@@ -147,14 +147,8 @@ module RSpec
|
|
|
147
147
|
Time === object
|
|
148
148
|
end
|
|
149
149
|
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
object.strftime("#{FORMAT}.#{"%09d" % object.nsec} %z")
|
|
153
|
-
end
|
|
154
|
-
else # for 1.8.7
|
|
155
|
-
def inspect
|
|
156
|
-
object.strftime("#{FORMAT}.#{"%06d" % object.usec} %z")
|
|
157
|
-
end
|
|
150
|
+
def inspect
|
|
151
|
+
object.strftime("#{FORMAT}.#{"%09d" % object.nsec} %z")
|
|
158
152
|
end
|
|
159
153
|
end
|
|
160
154
|
|
|
@@ -176,16 +170,6 @@ module RSpec
|
|
|
176
170
|
end
|
|
177
171
|
end
|
|
178
172
|
|
|
179
|
-
class BigDecimalInspector < BaseInspector
|
|
180
|
-
def self.can_inspect?(object)
|
|
181
|
-
defined?(BigDecimal) && BigDecimal === object
|
|
182
|
-
end
|
|
183
|
-
|
|
184
|
-
def inspect
|
|
185
|
-
"#{object.to_s('F')} (#{object.inspect})"
|
|
186
|
-
end
|
|
187
|
-
end
|
|
188
|
-
|
|
189
173
|
class DescribableMatcherInspector < BaseInspector
|
|
190
174
|
def self.can_inspect?(object)
|
|
191
175
|
Support.is_a_matcher?(object) && object.respond_to?(:description)
|
|
@@ -217,9 +201,6 @@ module RSpec
|
|
|
217
201
|
# http://stackoverflow.com/a/2818916
|
|
218
202
|
def native_object_id
|
|
219
203
|
OBJECT_ID_FORMAT % (object.__id__ << 1)
|
|
220
|
-
rescue NoMethodError
|
|
221
|
-
# In Ruby 1.9.2, BasicObject responds to none of #__id__, #object_id, #id...
|
|
222
|
-
'-'
|
|
223
204
|
end
|
|
224
205
|
end
|
|
225
206
|
|
|
@@ -249,17 +230,11 @@ module RSpec
|
|
|
249
230
|
INSPECTOR_CLASSES = [
|
|
250
231
|
TimeInspector,
|
|
251
232
|
DateTimeInspector,
|
|
252
|
-
BigDecimalInspector,
|
|
253
233
|
UninspectableObjectInspector,
|
|
254
234
|
DescribableMatcherInspector,
|
|
255
235
|
DelegatorInspector,
|
|
256
236
|
InspectableObjectInspector
|
|
257
|
-
]
|
|
258
|
-
# 2.4 has improved BigDecimal formatting so we do not need
|
|
259
|
-
# to provide our own.
|
|
260
|
-
# https://github.com/ruby/bigdecimal/pull/42
|
|
261
|
-
classes.delete(BigDecimalInspector) if RUBY_VERSION >= '2.4'
|
|
262
|
-
end
|
|
237
|
+
]
|
|
263
238
|
|
|
264
239
|
private
|
|
265
240
|
|
|
@@ -7,52 +7,29 @@ module RSpec
|
|
|
7
7
|
module RecursiveConstMethods
|
|
8
8
|
# We only want to consider constants that are defined directly on a
|
|
9
9
|
# particular module, and not include top-level/inherited constants.
|
|
10
|
-
# Unfortunately, the constant API changed between 1.8 and 1.9, so
|
|
11
|
-
# we need to conditionally define methods to ignore the top-level/inherited
|
|
12
|
-
# constants.
|
|
13
10
|
#
|
|
14
11
|
# Given:
|
|
15
12
|
# class A; B = 1; end
|
|
16
13
|
# class C < A; end
|
|
17
14
|
#
|
|
18
|
-
#
|
|
19
|
-
#
|
|
20
|
-
#
|
|
21
|
-
#
|
|
22
|
-
#
|
|
23
|
-
#
|
|
24
|
-
#
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
# - C.constants(false) #=> []
|
|
30
|
-
if Module.method(:const_defined?).arity == 1
|
|
31
|
-
def const_defined_on?(mod, const_name)
|
|
32
|
-
mod.const_defined?(const_name)
|
|
33
|
-
end
|
|
34
|
-
|
|
35
|
-
def get_const_defined_on(mod, const_name)
|
|
36
|
-
return mod.const_get(const_name) if const_defined_on?(mod, const_name)
|
|
37
|
-
|
|
38
|
-
raise NameError, "uninitialized constant #{mod.name}::#{const_name}"
|
|
39
|
-
end
|
|
40
|
-
|
|
41
|
-
def constants_defined_on(mod)
|
|
42
|
-
mod.constants.select { |c| const_defined_on?(mod, c) }
|
|
43
|
-
end
|
|
44
|
-
else
|
|
45
|
-
def const_defined_on?(mod, const_name)
|
|
46
|
-
mod.const_defined?(const_name, false)
|
|
47
|
-
end
|
|
15
|
+
# Then:
|
|
16
|
+
# C.const_get("Hash") # => ::Hash
|
|
17
|
+
# C.const_defined?("Hash") # => true
|
|
18
|
+
# C.const_get("Hash", false) # => raises NameError
|
|
19
|
+
# C.const_defined?("Hash", false) # => false
|
|
20
|
+
# C.constants # => [:B]
|
|
21
|
+
# C.constants(false) #=> []
|
|
22
|
+
|
|
23
|
+
def const_defined_on?(mod, const_name)
|
|
24
|
+
mod.const_defined?(const_name, false)
|
|
25
|
+
end
|
|
48
26
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
27
|
+
def get_const_defined_on(mod, const_name)
|
|
28
|
+
mod.const_get(const_name, false)
|
|
29
|
+
end
|
|
52
30
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
end
|
|
31
|
+
def constants_defined_on(mod)
|
|
32
|
+
mod.constants(false)
|
|
56
33
|
end
|
|
57
34
|
|
|
58
35
|
def recursive_const_get(const_name)
|
|
@@ -2,16 +2,20 @@
|
|
|
2
2
|
|
|
3
3
|
module RSpec
|
|
4
4
|
module Support
|
|
5
|
+
# This class protects us against Mutex.new stubbed out within tests.
|
|
6
|
+
# @private
|
|
7
|
+
class Mutex < ::Mutex
|
|
8
|
+
class << self
|
|
9
|
+
define_method(:new, &::Mutex.method(:new))
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
|
|
5
13
|
# Allows a thread to lock out other threads from a critical section of code,
|
|
6
14
|
# while allowing the thread with the lock to reenter that section.
|
|
7
15
|
#
|
|
8
16
|
# Based on Monitor as of 2.2 -
|
|
9
17
|
# https://github.com/ruby/ruby/blob/eb7ddaa3a47bf48045d26c72eb0f263a53524ebc/lib/monitor.rb#L9
|
|
10
18
|
#
|
|
11
|
-
# Depends on Mutex, but Mutex is only available as part of core since 1.9.1:
|
|
12
|
-
# exists - http://ruby-doc.org/core-1.9.1/Mutex.html
|
|
13
|
-
# dne - http://ruby-doc.org/core-1.9.0/Mutex.html
|
|
14
|
-
#
|
|
15
19
|
# @private
|
|
16
20
|
class ReentrantMutex
|
|
17
21
|
def initialize
|
|
@@ -29,52 +33,18 @@ module RSpec
|
|
|
29
33
|
|
|
30
34
|
private
|
|
31
35
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
def enter
|
|
36
|
-
@mutex.lock unless @mutex.owned?
|
|
37
|
-
@count += 1
|
|
38
|
-
end
|
|
39
|
-
|
|
40
|
-
def exit
|
|
41
|
-
unless @mutex.owned?
|
|
42
|
-
raise ThreadError, "Attempt to unlock a mutex which is locked by another thread/fiber"
|
|
43
|
-
end
|
|
44
|
-
@count -= 1
|
|
45
|
-
@mutex.unlock if @count == 0
|
|
46
|
-
end
|
|
47
|
-
else
|
|
48
|
-
def enter
|
|
49
|
-
@mutex.lock if @owner != Thread.current
|
|
50
|
-
@owner = Thread.current
|
|
51
|
-
@count += 1
|
|
52
|
-
end
|
|
53
|
-
|
|
54
|
-
def exit
|
|
55
|
-
@count -= 1
|
|
56
|
-
return unless @count == 0
|
|
57
|
-
@owner = nil
|
|
58
|
-
@mutex.unlock
|
|
59
|
-
end
|
|
36
|
+
def enter
|
|
37
|
+
@mutex.lock unless @mutex.owned?
|
|
38
|
+
@count += 1
|
|
60
39
|
end
|
|
61
|
-
end
|
|
62
|
-
|
|
63
|
-
if defined? ::Mutex
|
|
64
|
-
# On 1.9 and up, this is in core, so we just use the real one
|
|
65
|
-
class Mutex < ::Mutex
|
|
66
|
-
# If you mock Mutex.new you break our usage of Mutex, so
|
|
67
|
-
# instead we capture the original method to return Mutexes.
|
|
68
|
-
NEW_MUTEX_METHOD = Mutex.method(:new)
|
|
69
40
|
|
|
70
|
-
|
|
71
|
-
|
|
41
|
+
def exit
|
|
42
|
+
unless @mutex.owned?
|
|
43
|
+
raise ThreadError, "Attempt to unlock a mutex which is locked by another thread/fiber"
|
|
72
44
|
end
|
|
45
|
+
@count -= 1
|
|
46
|
+
@mutex.unlock if @count == 0
|
|
73
47
|
end
|
|
74
|
-
else # For 1.8.7
|
|
75
|
-
# :nocov:
|
|
76
|
-
RSpec::Support.require_rspec_support "mutex"
|
|
77
|
-
# :nocov:
|
|
78
48
|
end
|
|
79
49
|
end
|
|
80
50
|
end
|