rspec-support 3.5.0 → 3.9.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 -5
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +0 -0
- data/Changelog.md +84 -1
- data/README.md +1 -1
- data/lib/rspec/support.rb +11 -1
- data/lib/rspec/support/differ.rb +6 -6
- data/lib/rspec/support/method_signature_verifier.rb +71 -25
- data/lib/rspec/support/object_formatter.rb +37 -11
- data/lib/rspec/support/recursive_const_methods.rb +1 -1
- data/lib/rspec/support/ruby_features.rb +32 -5
- data/lib/rspec/support/source.rb +75 -0
- data/lib/rspec/support/source/location.rb +21 -0
- data/lib/rspec/support/source/node.rb +110 -0
- data/lib/rspec/support/source/token.rb +87 -0
- data/lib/rspec/support/spec/in_sub_process.rb +29 -12
- data/lib/rspec/support/spec/shell_out.rb +8 -1
- data/lib/rspec/support/version.rb +1 -1
- data/lib/rspec/support/warnings.rb +2 -2
- metadata +14 -20
- metadata.gz.sig +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 27ddd84c490aacfced87a3d772c93cf8391484030d28f78789ff5e9263811d42
|
4
|
+
data.tar.gz: 515eecb4064c04ac636b6171ad1308532596a13d9b132ac4689893ab76f43bfe
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3755a83a18dcd1326ac122e8250b0abbe0c50af2e630748478c8dfbf0c0f64f65d59725db3ae5370e382f49409b8f7d1639aa09a75c143d4186a8bfeda36a9e3
|
7
|
+
data.tar.gz: 6a41a8e6f905e1c2a37a776a2438d461859aab8434b1cd20c0aa4ca50fb17d898465535710018c8c01c199fde6e179ffef35feb1cd118dc4b71894a0a12d960b
|
checksums.yaml.gz.sig
CHANGED
Binary file
|
data.tar.gz.sig
CHANGED
Binary file
|
data/Changelog.md
CHANGED
@@ -1,7 +1,90 @@
|
|
1
|
+
### 3.9.0 / 2019-10-07
|
2
|
+
|
3
|
+
*NO CHANGES*
|
4
|
+
|
5
|
+
Version 3.9.0 was released to allow other RSpec gems to release 3.9.0.
|
6
|
+
|
7
|
+
### 3.8.3 / 2019-10-02
|
8
|
+
|
9
|
+
Bug Fixes:
|
10
|
+
|
11
|
+
* Escape \r when outputting strings inside arrays.
|
12
|
+
(Tomita Masahiro, Jon Rowe, #378)
|
13
|
+
* Ensure that optional hash arguments are recognised correctly vs keyword
|
14
|
+
arguments. (Evgeni Dzhelyov, #366)
|
15
|
+
|
16
|
+
### 3.8.2 / 2019-06-10
|
17
|
+
[Full Changelog](http://github.com/rspec/rspec-support/compare/v3.8.1...v3.8.2)
|
18
|
+
|
19
|
+
Bug Fixes:
|
20
|
+
|
21
|
+
* Ensure that an empty hash is recognised as empty keyword arguments when
|
22
|
+
applicable. (Thomas Walpole, #375)
|
23
|
+
* Ensure that diffing truthy values produce diffs consistently.
|
24
|
+
(Lucas Nestor, #377)
|
25
|
+
|
26
|
+
### 3.8.1 / 2019-03-03
|
27
|
+
[Full Changelog](http://github.com/rspec/rspec-support/compare/v3.8.0...v3.8.1)
|
28
|
+
|
29
|
+
Bug Fixes:
|
30
|
+
|
31
|
+
* Ensure that inspecting a `SimpleDelegator` based object works regardless of
|
32
|
+
visibilty of the `__getobj__` method. (Jon Rowe, #369)
|
33
|
+
|
34
|
+
### 3.8.0 / 2018-08-04
|
35
|
+
[Full Changelog](http://github.com/rspec/rspec-support/compare/v3.7.1...v3.8.0)
|
36
|
+
|
37
|
+
Bug Fixes:
|
38
|
+
|
39
|
+
* Order hash keys before diffing to improve diff accuracy when using mocked calls.
|
40
|
+
(James Crisp, #334)
|
41
|
+
|
42
|
+
### 3.7.1 / 2018-01-29
|
43
|
+
[Full Changelog](http://github.com/rspec/rspec-support/compare/v3.7.0...v3.7.1)
|
44
|
+
|
45
|
+
Bug Fixes:
|
46
|
+
|
47
|
+
* Fix source extraction logic so that it does not trigger a `SystemStackError`
|
48
|
+
when processing deeply nested example groups. (Craig Bass, #343)
|
49
|
+
|
50
|
+
### 3.7.0 / 2017-10-17
|
51
|
+
[Full Changelog](http://github.com/rspec/rspec-support/compare/v3.6.0...v3.7.0)
|
52
|
+
|
53
|
+
Enhancements:
|
54
|
+
|
55
|
+
* Improve compatibility with `--enable-frozen-string-literal` option
|
56
|
+
on Ruby 2.3+. (Pat Allan, #320)
|
57
|
+
* Add `Support.class_of` for extracting class of any object.
|
58
|
+
(Yuji Nakayama, #325)
|
59
|
+
|
60
|
+
Bug Fixes:
|
61
|
+
|
62
|
+
* Fix recursive const support to not blow up when given buggy classes
|
63
|
+
that raise odd errors from `#to_str`. (Myron Marston, #317)
|
64
|
+
|
65
|
+
### 3.6.0 / 2017-05-04
|
66
|
+
[Full Changelog](http://github.com/rspec/rspec-support/compare/v3.6.0.beta2...3.6.0)
|
67
|
+
|
68
|
+
Enhancements:
|
69
|
+
|
70
|
+
* Import `Source` classes from rspec-core. (Yuji Nakayama, #315)
|
71
|
+
|
72
|
+
### 3.6.0.beta2 / 2016-12-12
|
73
|
+
[Full Changelog](http://github.com/rspec/rspec-support/compare/v3.6.0.beta1...v3.6.0.beta2)
|
74
|
+
|
75
|
+
No user-facing changes.
|
76
|
+
|
77
|
+
### 3.6.0.beta1 / 2016-10-09
|
78
|
+
[Full Changelog](http://github.com/rspec/rspec-support/compare/v3.5.0...v3.6.0.beta1)
|
79
|
+
|
80
|
+
Bug Fixes:
|
81
|
+
|
82
|
+
* Prevent truncated formatted object output from mangling console codes. (#294, Anson Kelly)
|
83
|
+
|
1
84
|
### 3.5.0 / 2016-07-01
|
2
85
|
[Full Changelog](http://github.com/rspec/rspec-support/compare/v3.5.0.beta4...v3.5.0)
|
3
86
|
|
4
|
-
**No user facing changes since
|
87
|
+
**No user facing changes since beta4**
|
5
88
|
|
6
89
|
### 3.5.0.beta4 / 2016-06-05
|
7
90
|
[Full Changelog](http://github.com/rspec/rspec-support/compare/v3.5.0.beta3...v3.5.0.beta4)
|
data/README.md
CHANGED
@@ -13,7 +13,7 @@ RSpec repos as well. Add the following to your `Gemfile`:
|
|
13
13
|
|
14
14
|
```ruby
|
15
15
|
%w[rspec-core rspec-expectations rspec-mocks rspec-support].each do |lib|
|
16
|
-
gem lib, :git => "
|
16
|
+
gem lib, :git => "https://github.com/rspec/#{lib}.git", :branch => 'master'
|
17
17
|
end
|
18
18
|
```
|
19
19
|
|
data/lib/rspec/support.rb
CHANGED
@@ -73,6 +73,16 @@ module RSpec
|
|
73
73
|
end
|
74
74
|
end
|
75
75
|
|
76
|
+
# @api private
|
77
|
+
#
|
78
|
+
# Used internally to get a class of a given object, even if it does not respond to #class.
|
79
|
+
def self.class_of(object)
|
80
|
+
object.class
|
81
|
+
rescue NoMethodError
|
82
|
+
singleton_class = class << object; self; end
|
83
|
+
singleton_class.ancestors.find { |ancestor| !ancestor.equal?(singleton_class) }
|
84
|
+
end
|
85
|
+
|
76
86
|
# A single thread local variable so we don't excessively pollute that namespace.
|
77
87
|
def self.thread_local_data
|
78
88
|
Thread.current[:__rspec] ||= {}
|
@@ -129,7 +139,7 @@ module RSpec
|
|
129
139
|
end
|
130
140
|
end
|
131
141
|
|
132
|
-
# The Differ is only needed when a
|
142
|
+
# The Differ is only needed when a spec fails with a diffable failure.
|
133
143
|
# In the more common case of all specs passing or the only failures being
|
134
144
|
# non-diffable, we can avoid the extra cost of loading the differ, diff-lcs,
|
135
145
|
# pp, etc by avoiding an unnecessary require. Instead, autoload will take
|
data/lib/rspec/support/differ.rb
CHANGED
@@ -11,7 +11,7 @@ module RSpec
|
|
11
11
|
def diff(actual, expected)
|
12
12
|
diff = ""
|
13
13
|
|
14
|
-
|
14
|
+
unless actual.nil? || expected.nil?
|
15
15
|
if all_strings?(actual, expected)
|
16
16
|
if any_multiline_strings?(actual, expected)
|
17
17
|
diff = diff_as_string(coerce_to_string(actual), coerce_to_string(expected))
|
@@ -97,7 +97,7 @@ module RSpec
|
|
97
97
|
if Array === entry
|
98
98
|
entry.inspect
|
99
99
|
else
|
100
|
-
entry.to_s.gsub("\n", "\\n")
|
100
|
+
entry.to_s.gsub("\n", "\\n").gsub("\r", "\\r")
|
101
101
|
end
|
102
102
|
end
|
103
103
|
end
|
@@ -181,19 +181,19 @@ module RSpec
|
|
181
181
|
when Hash
|
182
182
|
hash_to_string(object)
|
183
183
|
when Array
|
184
|
-
PP.pp(ObjectFormatter.prepare_for_inspection(object), "")
|
184
|
+
PP.pp(ObjectFormatter.prepare_for_inspection(object), "".dup)
|
185
185
|
when String
|
186
186
|
object =~ /\n/ ? object : object.inspect
|
187
187
|
else
|
188
|
-
PP.pp(object, "")
|
188
|
+
PP.pp(object, "".dup)
|
189
189
|
end
|
190
190
|
end
|
191
191
|
|
192
192
|
def hash_to_string(hash)
|
193
193
|
formatted_hash = ObjectFormatter.prepare_for_inspection(hash)
|
194
194
|
formatted_hash.keys.sort_by { |k| k.to_s }.map do |key|
|
195
|
-
pp_key = PP.singleline_pp(key, "")
|
196
|
-
pp_value = PP.singleline_pp(formatted_hash[key], "")
|
195
|
+
pp_key = PP.singleline_pp(key, "".dup)
|
196
|
+
pp_value = PP.singleline_pp(formatted_hash[key], "".dup)
|
197
197
|
|
198
198
|
"#{pp_key} => #{pp_value},"
|
199
199
|
end.join("\n")
|
@@ -33,6 +33,18 @@ module RSpec
|
|
33
33
|
optional_max_arg_count <= max_non_kw_args
|
34
34
|
end
|
35
35
|
|
36
|
+
def classify_arity(arity=@method.arity)
|
37
|
+
if arity < 0
|
38
|
+
# `~` inverts the one's complement and gives us the
|
39
|
+
# number of required args
|
40
|
+
@min_non_kw_args = ~arity
|
41
|
+
@max_non_kw_args = INFINITY
|
42
|
+
else
|
43
|
+
@min_non_kw_args = arity
|
44
|
+
@max_non_kw_args = arity
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
36
48
|
if RubyFeatures.optional_and_splat_args_supported?
|
37
49
|
def description
|
38
50
|
@description ||= begin
|
@@ -65,14 +77,19 @@ module RSpec
|
|
65
77
|
given_kw_args - @allowed_kw_args
|
66
78
|
end
|
67
79
|
|
80
|
+
# If the last argument is Hash, Ruby will treat only symbol keys as keyword arguments
|
81
|
+
# the rest will be grouped in another Hash and passed as positional argument.
|
68
82
|
def has_kw_args_in?(args)
|
69
|
-
Hash === args.last &&
|
83
|
+
Hash === args.last &&
|
84
|
+
could_contain_kw_args?(args) &&
|
85
|
+
(args.last.empty? || args.last.keys.any? { |x| x.is_a?(Symbol) })
|
70
86
|
end
|
71
87
|
|
72
88
|
# Without considering what the last arg is, could it
|
73
89
|
# contain keyword arguments?
|
74
90
|
def could_contain_kw_args?(args)
|
75
91
|
return false if args.count <= min_non_kw_args
|
92
|
+
|
76
93
|
@allows_any_kw_args || @allowed_kw_args.any?
|
77
94
|
end
|
78
95
|
|
@@ -137,36 +154,58 @@ module RSpec
|
|
137
154
|
false
|
138
155
|
end
|
139
156
|
|
140
|
-
|
141
|
-
arity = @method.arity
|
142
|
-
if arity < 0
|
143
|
-
# `~` inverts the one's complement and gives us the
|
144
|
-
# number of required args
|
145
|
-
@min_non_kw_args = ~arity
|
146
|
-
@max_non_kw_args = INFINITY
|
147
|
-
else
|
148
|
-
@min_non_kw_args = arity
|
149
|
-
@max_non_kw_args = arity
|
150
|
-
end
|
151
|
-
end
|
157
|
+
alias_method :classify_parameters, :classify_arity
|
152
158
|
end
|
153
159
|
|
154
160
|
INFINITY = 1 / 0.0
|
155
161
|
end
|
156
162
|
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
163
|
+
if RSpec::Support::Ruby.jruby?
|
164
|
+
# JRuby has only partial support for UnboundMethod#parameters, so we fall back on using #arity
|
165
|
+
# https://github.com/jruby/jruby/issues/2816 and https://github.com/jruby/jruby/issues/2817
|
166
|
+
if RubyFeatures.optional_and_splat_args_supported? &&
|
167
|
+
Java::JavaLang::String.instance_method(:char_at).parameters == []
|
162
168
|
|
163
|
-
|
164
|
-
|
169
|
+
class MethodSignature < remove_const(:MethodSignature)
|
170
|
+
private
|
165
171
|
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
172
|
+
def classify_parameters
|
173
|
+
super
|
174
|
+
if (arity = @method.arity) != 0 && @method.parameters.empty?
|
175
|
+
classify_arity(arity)
|
176
|
+
end
|
177
|
+
end
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
181
|
+
# JRuby used to always report -1 arity for Java proxy methods.
|
182
|
+
# The workaround essentially makes use of Java's introspection to figure
|
183
|
+
# out matching methods (which could be more than one partly because Java
|
184
|
+
# supports multiple overloads, and partly because JRuby introduces
|
185
|
+
# aliases to make method names look more Rubyesque). If there is only a
|
186
|
+
# single match, we can use that methods arity directly instead of the
|
187
|
+
# default -1 arity.
|
188
|
+
#
|
189
|
+
# This workaround only works for Java proxy methods, and in order to
|
190
|
+
# support regular methods and blocks, we need to be careful about calling
|
191
|
+
# owner and java_class as they might not be available
|
192
|
+
if Java::JavaLang::String.instance_method(:char_at).arity == -1
|
193
|
+
class MethodSignature < remove_const(:MethodSignature)
|
194
|
+
private
|
195
|
+
|
196
|
+
def classify_parameters
|
197
|
+
super
|
198
|
+
return unless @method.arity == -1
|
199
|
+
return unless @method.respond_to?(:owner)
|
200
|
+
return unless @method.owner.respond_to?(:java_class)
|
201
|
+
java_instance_methods = @method.owner.java_class.java_instance_methods
|
202
|
+
compatible_overloads = java_instance_methods.select do |java_method|
|
203
|
+
@method == @method.owner.instance_method(java_method.name)
|
204
|
+
end
|
205
|
+
if compatible_overloads.size == 1
|
206
|
+
classify_arity(compatible_overloads.first.arity)
|
207
|
+
end
|
208
|
+
end
|
170
209
|
end
|
171
210
|
end
|
172
211
|
end
|
@@ -323,7 +362,14 @@ module RSpec
|
|
323
362
|
|
324
363
|
def split_args(*args)
|
325
364
|
kw_args = if @signature.has_kw_args_in?(args)
|
326
|
-
args.pop
|
365
|
+
last = args.pop
|
366
|
+
non_kw_args = last.reject { |k, _| k.is_a?(Symbol) }
|
367
|
+
if non_kw_args.empty?
|
368
|
+
last.keys
|
369
|
+
else
|
370
|
+
args << non_kw_args
|
371
|
+
last.select { |k, _| k.is_a?(Symbol) }.keys
|
372
|
+
end
|
327
373
|
else
|
328
374
|
[]
|
329
375
|
end
|
@@ -5,7 +5,7 @@ module RSpec
|
|
5
5
|
# Provide additional output details beyond what `inspect` provides when
|
6
6
|
# printing Time, DateTime, or BigDecimal
|
7
7
|
# @api private
|
8
|
-
class ObjectFormatter # rubocop:disable
|
8
|
+
class ObjectFormatter # rubocop:disable Metrics/ClassLength
|
9
9
|
ELLIPSIS = "..."
|
10
10
|
|
11
11
|
attr_accessor :max_formatted_output_length
|
@@ -31,15 +31,15 @@ module RSpec
|
|
31
31
|
|
32
32
|
def format(object)
|
33
33
|
if max_formatted_output_length.nil?
|
34
|
-
|
34
|
+
prepare_for_inspection(object).inspect
|
35
35
|
else
|
36
36
|
formatted_object = prepare_for_inspection(object).inspect
|
37
37
|
if formatted_object.length < max_formatted_output_length
|
38
|
-
|
38
|
+
formatted_object
|
39
39
|
else
|
40
|
-
beginning = formatted_object
|
41
|
-
ending = formatted_object
|
42
|
-
|
40
|
+
beginning = truncate_string formatted_object, 0, max_formatted_output_length / 2
|
41
|
+
ending = truncate_string formatted_object, -max_formatted_output_length / 2, -1
|
42
|
+
beginning + ELLIPSIS + ending
|
43
43
|
end
|
44
44
|
end
|
45
45
|
end
|
@@ -73,7 +73,7 @@ module RSpec
|
|
73
73
|
|
74
74
|
def prepare_hash(input_hash)
|
75
75
|
with_entering_structure(input_hash) do
|
76
|
-
input_hash.inject({}) do |output_hash, key_and_value|
|
76
|
+
sort_hash_keys(input_hash).inject({}) do |output_hash, key_and_value|
|
77
77
|
key, value = key_and_value.map { |element| prepare_element(element) }
|
78
78
|
output_hash[key] = value
|
79
79
|
output_hash
|
@@ -81,6 +81,14 @@ module RSpec
|
|
81
81
|
end
|
82
82
|
end
|
83
83
|
|
84
|
+
def sort_hash_keys(input_hash)
|
85
|
+
if input_hash.keys.all? { |k| k.is_a?(String) || k.is_a?(Symbol) }
|
86
|
+
Hash[input_hash.sort_by { |k, _v| k.to_s }]
|
87
|
+
else
|
88
|
+
input_hash
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
84
92
|
def prepare_element(element)
|
85
93
|
if recursive_structure?(element)
|
86
94
|
case element
|
@@ -199,8 +207,7 @@ module RSpec
|
|
199
207
|
end
|
200
208
|
|
201
209
|
def klass
|
202
|
-
|
203
|
-
singleton_class.ancestors.find { |ancestor| !ancestor.equal?(singleton_class) }
|
210
|
+
Support.class_of(object)
|
204
211
|
end
|
205
212
|
|
206
213
|
# http://stackoverflow.com/a/2818916
|
@@ -218,7 +225,7 @@ module RSpec
|
|
218
225
|
end
|
219
226
|
|
220
227
|
def inspect
|
221
|
-
"#<#{object.class}(#{formatter.format(object.__getobj__)})>"
|
228
|
+
"#<#{object.class}(#{formatter.format(object.send(:__getobj__))})>"
|
222
229
|
end
|
223
230
|
end
|
224
231
|
|
@@ -243,7 +250,26 @@ module RSpec
|
|
243
250
|
DescribableMatcherInspector,
|
244
251
|
DelegatorInspector,
|
245
252
|
InspectableObjectInspector
|
246
|
-
]
|
253
|
+
].tap do |classes|
|
254
|
+
# 2.4 has improved BigDecimal formatting so we do not need
|
255
|
+
# to provide our own.
|
256
|
+
# https://github.com/ruby/bigdecimal/pull/42
|
257
|
+
classes.delete(BigDecimalInspector) if RUBY_VERSION >= '2.4'
|
258
|
+
end
|
259
|
+
|
260
|
+
private
|
261
|
+
|
262
|
+
# Returns the substring defined by the start_index and end_index
|
263
|
+
# If the string ends with a partial ANSI code code then that
|
264
|
+
# will be removed as printing partial ANSI
|
265
|
+
# codes to the terminal can lead to corruption
|
266
|
+
def truncate_string(str, start_index, end_index)
|
267
|
+
cut_str = str[start_index..end_index]
|
268
|
+
|
269
|
+
# ANSI color codes are like: \e[33m so anything with \e[ and a
|
270
|
+
# number without a 'm' is an incomplete color code
|
271
|
+
cut_str.sub(/\e\[\d+$/, '')
|
272
|
+
end
|
247
273
|
end
|
248
274
|
end
|
249
275
|
end
|
@@ -64,7 +64,7 @@ module RSpec
|
|
64
64
|
parts.inject([Object, '']) do |(mod, full_name), name|
|
65
65
|
yield(full_name, name) if block_given? && !(Module === mod)
|
66
66
|
return false unless const_defined_on?(mod, name)
|
67
|
-
[get_const_defined_on(mod, name), [mod, name].join('::')]
|
67
|
+
[get_const_defined_on(mod, name), [mod.name, name].join('::')]
|
68
68
|
end
|
69
69
|
end
|
70
70
|
|
@@ -28,6 +28,14 @@ module RSpec
|
|
28
28
|
RUBY_PLATFORM == 'java'
|
29
29
|
end
|
30
30
|
|
31
|
+
def jruby_version
|
32
|
+
@jruby_version ||= ComparableVersion.new(JRUBY_VERSION)
|
33
|
+
end
|
34
|
+
|
35
|
+
def jruby_9000?
|
36
|
+
jruby? && JRUBY_VERSION >= '9.0.0.0'
|
37
|
+
end
|
38
|
+
|
31
39
|
def rbx?
|
32
40
|
defined?(RUBY_ENGINE) && RUBY_ENGINE == 'rbx'
|
33
41
|
end
|
@@ -48,6 +56,22 @@ module RSpec
|
|
48
56
|
module RubyFeatures
|
49
57
|
module_function
|
50
58
|
|
59
|
+
if Ruby.jruby?
|
60
|
+
# On JRuby 1.7 `--1.8` mode, `Process.respond_to?(:fork)` returns true,
|
61
|
+
# but when you try to fork, it raises an error:
|
62
|
+
# NotImplementedError: fork is not available on this platform
|
63
|
+
#
|
64
|
+
# When we drop support for JRuby 1.7 and/or Ruby 1.8, we can drop
|
65
|
+
# this special case.
|
66
|
+
def fork_supported?
|
67
|
+
false
|
68
|
+
end
|
69
|
+
else
|
70
|
+
def fork_supported?
|
71
|
+
Process.respond_to?(:fork)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
51
75
|
def optional_and_splat_args_supported?
|
52
76
|
Method.method_defined?(:parameters)
|
53
77
|
end
|
@@ -71,9 +95,10 @@ module RSpec
|
|
71
95
|
ripper_requirements.push(false) if Ruby.rbx?
|
72
96
|
|
73
97
|
if Ruby.jruby?
|
74
|
-
ripper_requirements.push(
|
75
|
-
# Ripper on JRuby 9.0.0.0.rc1
|
76
|
-
|
98
|
+
ripper_requirements.push(Ruby.jruby_version >= '1.7.5')
|
99
|
+
# Ripper on JRuby 9.0.0.0.rc1 - 9.1.8.0 reports wrong line number
|
100
|
+
# or cannot parse source including `:if`.
|
101
|
+
ripper_requirements.push(!Ruby.jruby_version.between?('9.0.0.0.rc1', '9.1.8.0'))
|
77
102
|
end
|
78
103
|
|
79
104
|
if ripper_requirements.all?
|
@@ -100,7 +125,6 @@ module RSpec
|
|
100
125
|
end
|
101
126
|
else
|
102
127
|
# RBX / JRuby et al support is unknown for keyword arguments
|
103
|
-
# rubocop:disable Lint/Eval
|
104
128
|
begin
|
105
129
|
eval("o = Object.new; def o.m(a: 1); end;"\
|
106
130
|
" raise SyntaxError unless o.method(:m).parameters.include?([:key, :a])")
|
@@ -138,7 +162,10 @@ module RSpec
|
|
138
162
|
false
|
139
163
|
end
|
140
164
|
end
|
141
|
-
|
165
|
+
end
|
166
|
+
|
167
|
+
def module_refinement_supported?
|
168
|
+
Module.method_defined?(:refine) || Module.private_method_defined?(:refine)
|
142
169
|
end
|
143
170
|
|
144
171
|
def module_prepends_supported?
|
@@ -0,0 +1,75 @@
|
|
1
|
+
RSpec::Support.require_rspec_support 'encoded_string'
|
2
|
+
RSpec::Support.require_rspec_support 'ruby_features'
|
3
|
+
|
4
|
+
module RSpec
|
5
|
+
module Support
|
6
|
+
# @private
|
7
|
+
# Represents a Ruby source file and provides access to AST and tokens.
|
8
|
+
class Source
|
9
|
+
attr_reader :source, :path
|
10
|
+
|
11
|
+
def self.from_file(path)
|
12
|
+
source = File.read(path)
|
13
|
+
new(source, path)
|
14
|
+
end
|
15
|
+
|
16
|
+
if String.method_defined?(:encoding)
|
17
|
+
def initialize(source_string, path=nil)
|
18
|
+
@source = RSpec::Support::EncodedString.new(source_string, Encoding.default_external)
|
19
|
+
@path = path ? File.expand_path(path) : '(string)'
|
20
|
+
end
|
21
|
+
else # for 1.8.7
|
22
|
+
# :nocov:
|
23
|
+
def initialize(source_string, path=nil)
|
24
|
+
@source = RSpec::Support::EncodedString.new(source_string)
|
25
|
+
@path = path ? File.expand_path(path) : '(string)'
|
26
|
+
end
|
27
|
+
# :nocov:
|
28
|
+
end
|
29
|
+
|
30
|
+
def lines
|
31
|
+
@lines ||= source.split("\n")
|
32
|
+
end
|
33
|
+
|
34
|
+
def inspect
|
35
|
+
"#<#{self.class} #{path}>"
|
36
|
+
end
|
37
|
+
|
38
|
+
if RSpec::Support::RubyFeatures.ripper_supported?
|
39
|
+
RSpec::Support.require_rspec_support 'source/node'
|
40
|
+
RSpec::Support.require_rspec_support 'source/token'
|
41
|
+
|
42
|
+
def ast
|
43
|
+
@ast ||= begin
|
44
|
+
require 'ripper'
|
45
|
+
sexp = Ripper.sexp(source)
|
46
|
+
raise SyntaxError unless sexp
|
47
|
+
Node.new(sexp)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def tokens
|
52
|
+
@tokens ||= begin
|
53
|
+
require 'ripper'
|
54
|
+
tokens = Ripper.lex(source)
|
55
|
+
Token.tokens_from_ripper_tokens(tokens)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def nodes_by_line_number
|
60
|
+
@nodes_by_line_number ||= begin
|
61
|
+
nodes_by_line_number = ast.select(&:location).group_by { |node| node.location.line }
|
62
|
+
Hash.new { |hash, key| hash[key] = [] }.merge(nodes_by_line_number)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def tokens_by_line_number
|
67
|
+
@tokens_by_line_number ||= begin
|
68
|
+
nodes_by_line_number = tokens.group_by { |token| token.location.line }
|
69
|
+
Hash.new { |hash, key| hash[key] = [] }.merge(nodes_by_line_number)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module RSpec
|
2
|
+
module Support
|
3
|
+
class Source
|
4
|
+
# @private
|
5
|
+
# Represents a source location of node or token.
|
6
|
+
Location = Struct.new(:line, :column) do
|
7
|
+
include Comparable
|
8
|
+
|
9
|
+
def self.location?(array)
|
10
|
+
array.is_a?(Array) && array.size == 2 && array.all? { |e| e.is_a?(Integer) }
|
11
|
+
end
|
12
|
+
|
13
|
+
def <=>(other)
|
14
|
+
line_comparison = (line <=> other.line)
|
15
|
+
return line_comparison unless line_comparison == 0
|
16
|
+
column <=> other.column
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,110 @@
|
|
1
|
+
RSpec::Support.require_rspec_support 'source/location'
|
2
|
+
|
3
|
+
module RSpec
|
4
|
+
module Support
|
5
|
+
class Source
|
6
|
+
# @private
|
7
|
+
# A wrapper for Ripper AST node which is generated with `Ripper.sexp`.
|
8
|
+
class Node
|
9
|
+
include Enumerable
|
10
|
+
|
11
|
+
attr_reader :sexp, :parent
|
12
|
+
|
13
|
+
def self.sexp?(array)
|
14
|
+
array.is_a?(Array) && array.first.is_a?(Symbol)
|
15
|
+
end
|
16
|
+
|
17
|
+
def initialize(ripper_sexp, parent=nil)
|
18
|
+
@sexp = ripper_sexp.freeze
|
19
|
+
@parent = parent
|
20
|
+
end
|
21
|
+
|
22
|
+
def type
|
23
|
+
sexp[0]
|
24
|
+
end
|
25
|
+
|
26
|
+
def args
|
27
|
+
@args ||= raw_args.map do |raw_arg|
|
28
|
+
if Node.sexp?(raw_arg)
|
29
|
+
Node.new(raw_arg, self)
|
30
|
+
elsif Location.location?(raw_arg)
|
31
|
+
Location.new(*raw_arg)
|
32
|
+
elsif raw_arg.is_a?(Array)
|
33
|
+
ExpressionSequenceNode.new(raw_arg, self)
|
34
|
+
else
|
35
|
+
raw_arg
|
36
|
+
end
|
37
|
+
end.freeze
|
38
|
+
end
|
39
|
+
|
40
|
+
def children
|
41
|
+
@children ||= args.select { |arg| arg.is_a?(Node) }.freeze
|
42
|
+
end
|
43
|
+
|
44
|
+
def location
|
45
|
+
@location ||= args.find { |arg| arg.is_a?(Location) }
|
46
|
+
end
|
47
|
+
|
48
|
+
# We use a loop here (instead of recursion) to prevent SystemStackError
|
49
|
+
def each
|
50
|
+
return to_enum(__method__) unless block_given?
|
51
|
+
|
52
|
+
node_queue = []
|
53
|
+
node_queue << self
|
54
|
+
|
55
|
+
while (current_node = node_queue.shift)
|
56
|
+
yield current_node
|
57
|
+
node_queue.concat(current_node.children)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def each_ancestor
|
62
|
+
return to_enum(__method__) unless block_given?
|
63
|
+
|
64
|
+
current_node = self
|
65
|
+
|
66
|
+
while (current_node = current_node.parent)
|
67
|
+
yield current_node
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def inspect
|
72
|
+
"#<#{self.class} #{type}>"
|
73
|
+
end
|
74
|
+
|
75
|
+
private
|
76
|
+
|
77
|
+
def raw_args
|
78
|
+
sexp[1..-1] || []
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
# @private
|
83
|
+
# Basically `Ripper.sexp` generates arrays whose first element is a symbol (type of sexp),
|
84
|
+
# but it exceptionally generates typeless arrays for expression sequence:
|
85
|
+
#
|
86
|
+
# Ripper.sexp('foo; bar')
|
87
|
+
# => [
|
88
|
+
# :program,
|
89
|
+
# [ # Typeless array
|
90
|
+
# [:vcall, [:@ident, "foo", [1, 0]]],
|
91
|
+
# [:vcall, [:@ident, "bar", [1, 5]]]
|
92
|
+
# ]
|
93
|
+
# ]
|
94
|
+
#
|
95
|
+
# We wrap typeless arrays in this pseudo type node
|
96
|
+
# so that it can be handled in the same way as other type node.
|
97
|
+
class ExpressionSequenceNode < Node
|
98
|
+
def type
|
99
|
+
:_expression_sequence
|
100
|
+
end
|
101
|
+
|
102
|
+
private
|
103
|
+
|
104
|
+
def raw_args
|
105
|
+
sexp
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
RSpec::Support.require_rspec_support 'source/location'
|
2
|
+
|
3
|
+
module RSpec
|
4
|
+
module Support
|
5
|
+
class Source
|
6
|
+
# @private
|
7
|
+
# A wrapper for Ripper token which is generated with `Ripper.lex`.
|
8
|
+
class Token
|
9
|
+
CLOSING_TYPES_BY_OPENING_TYPE = {
|
10
|
+
:on_lbracket => :on_rbracket,
|
11
|
+
:on_lparen => :on_rparen,
|
12
|
+
:on_lbrace => :on_rbrace,
|
13
|
+
:on_heredoc_beg => :on_heredoc_end
|
14
|
+
}.freeze
|
15
|
+
|
16
|
+
CLOSING_KEYWORDS_BY_OPENING_KEYWORD = {
|
17
|
+
'def' => 'end',
|
18
|
+
'do' => 'end',
|
19
|
+
}.freeze
|
20
|
+
|
21
|
+
attr_reader :token
|
22
|
+
|
23
|
+
def self.tokens_from_ripper_tokens(ripper_tokens)
|
24
|
+
ripper_tokens.map { |ripper_token| new(ripper_token) }.freeze
|
25
|
+
end
|
26
|
+
|
27
|
+
def initialize(ripper_token)
|
28
|
+
@token = ripper_token.freeze
|
29
|
+
end
|
30
|
+
|
31
|
+
def location
|
32
|
+
@location ||= Location.new(*token[0])
|
33
|
+
end
|
34
|
+
|
35
|
+
def type
|
36
|
+
token[1]
|
37
|
+
end
|
38
|
+
|
39
|
+
def string
|
40
|
+
token[2]
|
41
|
+
end
|
42
|
+
|
43
|
+
def ==(other)
|
44
|
+
token == other.token
|
45
|
+
end
|
46
|
+
|
47
|
+
alias_method :eql?, :==
|
48
|
+
|
49
|
+
def inspect
|
50
|
+
"#<#{self.class} #{type} #{string.inspect}>"
|
51
|
+
end
|
52
|
+
|
53
|
+
def keyword?
|
54
|
+
type == :on_kw
|
55
|
+
end
|
56
|
+
|
57
|
+
def opening?
|
58
|
+
opening_delimiter? || opening_keyword?
|
59
|
+
end
|
60
|
+
|
61
|
+
def closed_by?(other)
|
62
|
+
closed_by_delimiter?(other) || closed_by_keyword?(other)
|
63
|
+
end
|
64
|
+
|
65
|
+
private
|
66
|
+
|
67
|
+
def opening_delimiter?
|
68
|
+
CLOSING_TYPES_BY_OPENING_TYPE.key?(type)
|
69
|
+
end
|
70
|
+
|
71
|
+
def opening_keyword?
|
72
|
+
return false unless keyword?
|
73
|
+
CLOSING_KEYWORDS_BY_OPENING_KEYWORD.key?(string)
|
74
|
+
end
|
75
|
+
|
76
|
+
def closed_by_delimiter?(other)
|
77
|
+
other.type == CLOSING_TYPES_BY_OPENING_TYPE[type]
|
78
|
+
end
|
79
|
+
|
80
|
+
def closed_by_keyword?(other)
|
81
|
+
return false unless other.keyword?
|
82
|
+
other.string == CLOSING_KEYWORDS_BY_OPENING_KEYWORD[string]
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
@@ -3,40 +3,57 @@ module RSpec
|
|
3
3
|
module InSubProcess
|
4
4
|
if Process.respond_to?(:fork) && !(Ruby.jruby? && RUBY_VERSION == '1.8.7')
|
5
5
|
|
6
|
+
UnmarshableObject = Struct.new(:error)
|
7
|
+
|
6
8
|
# Useful as a way to isolate a global change to a subprocess.
|
7
9
|
|
8
10
|
# rubocop:disable MethodLength
|
9
11
|
def in_sub_process(prevent_warnings=true)
|
10
|
-
|
12
|
+
exception_reader, exception_writer = IO.pipe
|
13
|
+
result_reader, result_writer = IO.pipe
|
11
14
|
|
12
15
|
pid = Process.fork do
|
13
|
-
exception = nil
|
14
16
|
warning_preventer = $stderr = RSpec::Support::StdErrSplitter.new($stderr)
|
15
17
|
|
16
18
|
begin
|
17
|
-
yield
|
19
|
+
result = yield
|
18
20
|
warning_preventer.verify_no_warnings! if prevent_warnings
|
19
|
-
|
20
|
-
|
21
|
+
# rubocop:disable Lint/HandleExceptions
|
22
|
+
rescue Support::AllExceptionsExceptOnesWeMustNotRescue => exception
|
23
|
+
# rubocop:enable Lint/HandleExceptions
|
21
24
|
end
|
22
25
|
|
23
|
-
|
26
|
+
exception_writer.write marshal_dump_with_unmarshable_object_handling(exception)
|
27
|
+
exception_reader.close
|
28
|
+
exception_writer.close
|
29
|
+
|
30
|
+
result_writer.write marshal_dump_with_unmarshable_object_handling(result)
|
31
|
+
result_reader.close
|
32
|
+
result_writer.close
|
24
33
|
|
25
|
-
readme.close
|
26
|
-
writeme.close
|
27
34
|
exit! # prevent at_exit hooks from running (e.g. minitest)
|
28
35
|
end
|
29
36
|
|
30
|
-
|
37
|
+
exception_writer.close
|
38
|
+
result_writer.close
|
31
39
|
Process.waitpid(pid)
|
32
40
|
|
33
|
-
exception = Marshal.load(
|
34
|
-
|
35
|
-
|
41
|
+
exception = Marshal.load(exception_reader.read)
|
42
|
+
exception_reader.close
|
36
43
|
raise exception if exception
|
44
|
+
|
45
|
+
result = Marshal.load(result_reader.read)
|
46
|
+
result_reader.close
|
47
|
+
result
|
37
48
|
end
|
38
49
|
# rubocop:enable MethodLength
|
39
50
|
alias :in_sub_process_if_possible :in_sub_process
|
51
|
+
|
52
|
+
def marshal_dump_with_unmarshable_object_handling(object)
|
53
|
+
Marshal.dump(object)
|
54
|
+
rescue TypeError => error
|
55
|
+
Marshal.dump(UnmarshableObject.new(error))
|
56
|
+
end
|
40
57
|
else
|
41
58
|
def in_sub_process(*)
|
42
59
|
skip "This spec requires forking to work properly, " \
|
@@ -59,8 +59,15 @@ module RSpec
|
|
59
59
|
l =~ %r{bundler/source/rubygems} ||
|
60
60
|
# Ignore bundler + rubygems warning.
|
61
61
|
l =~ %r{site_ruby/\d\.\d\.\d/rubygems} ||
|
62
|
+
l =~ %r{jruby-\d\.\d\.\d\.\d/lib/ruby/stdlib/rubygems} ||
|
62
63
|
# This is required for windows for some reason
|
63
|
-
l =~ %r{lib/bundler/rubygems}
|
64
|
+
l =~ %r{lib/bundler/rubygems} ||
|
65
|
+
# This is a JRuby file that generates warnings on 9.0.3.0
|
66
|
+
l =~ %r{lib/ruby/stdlib/jar} ||
|
67
|
+
# This is a JRuby file that generates warnings on 9.1.7.0
|
68
|
+
l =~ %r{org/jruby/RubyKernel\.java} ||
|
69
|
+
# Remove blank lines
|
70
|
+
l == "" || l.nil?
|
64
71
|
end.join("\n")
|
65
72
|
end
|
66
73
|
|
@@ -28,8 +28,8 @@ module RSpec
|
|
28
28
|
# Used internally to print longer warnings
|
29
29
|
def warn_with(message, options={})
|
30
30
|
call_site = options.fetch(:call_site) { CallerFilter.first_non_rspec_line }
|
31
|
-
message
|
32
|
-
message
|
31
|
+
message += " Use #{options[:replacement]} instead." if options[:replacement]
|
32
|
+
message += " Called from #{call_site}." if call_site
|
33
33
|
Support.warning_notifier.call message
|
34
34
|
end
|
35
35
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rspec-support
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.
|
4
|
+
version: 3.9.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- David Chelimsky
|
@@ -48,22 +48,8 @@ cert_chain:
|
|
48
48
|
ZsVDj6a7lH3cNqtWXZxrb2wO38qV5AkYj8SQK7Hj3/Yui9myUX3crr+PdetazSqQ
|
49
49
|
F3MdtaDehhjC
|
50
50
|
-----END CERTIFICATE-----
|
51
|
-
date:
|
51
|
+
date: 2019-10-07 00:00:00.000000000 Z
|
52
52
|
dependencies:
|
53
|
-
- !ruby/object:Gem::Dependency
|
54
|
-
name: bundler
|
55
|
-
requirement: !ruby/object:Gem::Requirement
|
56
|
-
requirements:
|
57
|
-
- - "~>"
|
58
|
-
- !ruby/object:Gem::Version
|
59
|
-
version: '1.3'
|
60
|
-
type: :development
|
61
|
-
prerelease: false
|
62
|
-
version_requirements: !ruby/object:Gem::Requirement
|
63
|
-
requirements:
|
64
|
-
- - "~>"
|
65
|
-
- !ruby/object:Gem::Version
|
66
|
-
version: '1.3'
|
67
53
|
- !ruby/object:Gem::Dependency
|
68
54
|
name: rake
|
69
55
|
requirement: !ruby/object:Gem::Requirement
|
@@ -116,6 +102,10 @@ files:
|
|
116
102
|
- lib/rspec/support/recursive_const_methods.rb
|
117
103
|
- lib/rspec/support/reentrant_mutex.rb
|
118
104
|
- lib/rspec/support/ruby_features.rb
|
105
|
+
- lib/rspec/support/source.rb
|
106
|
+
- lib/rspec/support/source/location.rb
|
107
|
+
- lib/rspec/support/source/node.rb
|
108
|
+
- lib/rspec/support/source/token.rb
|
119
109
|
- lib/rspec/support/spec.rb
|
120
110
|
- lib/rspec/support/spec/deprecation_helpers.rb
|
121
111
|
- lib/rspec/support/spec/formatting_support.rb
|
@@ -131,7 +121,12 @@ files:
|
|
131
121
|
homepage: https://github.com/rspec/rspec-support
|
132
122
|
licenses:
|
133
123
|
- MIT
|
134
|
-
metadata:
|
124
|
+
metadata:
|
125
|
+
bug_tracker_uri: https://github.com/rspec/rspec-support/issues
|
126
|
+
changelog_uri: https://github.com/rspec/rspec-support/blob/v3.9.0/Changelog.md
|
127
|
+
documentation_uri: https://rspec.info/documentation/
|
128
|
+
mailing_list_uri: https://groups.google.com/forum/#!forum/rspec
|
129
|
+
source_code_uri: https://github.com/rspec/rspec-support
|
135
130
|
post_install_message:
|
136
131
|
rdoc_options:
|
137
132
|
- "--charset=UTF-8"
|
@@ -148,9 +143,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
148
143
|
- !ruby/object:Gem::Version
|
149
144
|
version: '0'
|
150
145
|
requirements: []
|
151
|
-
|
152
|
-
rubygems_version: 2.5.1
|
146
|
+
rubygems_version: 3.0.6
|
153
147
|
signing_key:
|
154
148
|
specification_version: 4
|
155
|
-
summary: rspec-support-3.
|
149
|
+
summary: rspec-support-3.9.0
|
156
150
|
test_files: []
|
metadata.gz.sig
CHANGED
Binary file
|