rspec-support 3.6.0.beta2 → 3.7.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: a7fcfff9285fcfb448dbb76d0b30871c0d60f59e
4
- data.tar.gz: 56752014cf41733a30d156dd4e6166317deb3e15
3
+ metadata.gz: 97a8c3ef5bd62597387905254a288976a0c64c7a
4
+ data.tar.gz: b43e05200a5722ac6b8df8f6e34b1e7b2a30804a
5
5
  SHA512:
6
- metadata.gz: e855bdc6915f139f0743b1f1dac1251411f389b00c8f61f12676ee5da459fb194e1bfde2546416b13528018d7ff4affd1c9e149fcba45f3ac09f7c30867e5c0e
7
- data.tar.gz: 2e0b5cab4de91471beadad27058fdceb2f8607ee801cd1fe86d7347fe1e3f20028f628e1578da0c8f72049ef249fa36a7445ad1f8a6ba39036da90bf15e466c1
6
+ metadata.gz: fb1cfe9e1c326894f7a44d40df99e09ae579a39c2dac9dbe2af2e4996e76521d37bb7950f764f16c6a0c5864c384725042df706b9e22d3476628a0384bf47616
7
+ data.tar.gz: 8638d927462d2555d0ad2eba87dd5b0abfd3c2379d28430da87d447cccbc0630c75466438b250547994b95da13de042ae688830f109d8d9b6958de8a0ce84faa
Binary file
data.tar.gz.sig CHANGED
Binary file
@@ -1,7 +1,32 @@
1
+ ### Development
2
+ [Full Changelog](http://github.com/rspec/rspec-support/compare/v3.7.0...master)
3
+
4
+ ### 3.7.0 / 2017-05-04
5
+ [Full Changelog](http://github.com/rspec/rspec-support/compare/v3.6.0...v3.7.0)
6
+
7
+ Enhancements:
8
+
9
+ * Improve compatibility with `--enable-frozen-string-literal` option
10
+ on Ruby 2.3+. (Pat Allan, #320)
11
+ * Add `Support.class_of` for extracting class of any object.
12
+ (Yuji Nakayama, #325)
13
+
14
+ Bug Fixes:
15
+
16
+ * Fix recursive const support to not blow up when given buggy classes
17
+ that raise odd errors from `#to_str`. (Myron Marston, #317)
18
+
19
+ ### 3.6.0 / 2017-05-04
20
+ [Full Changelog](http://github.com/rspec/rspec-support/compare/v3.6.0.beta2...3.6.0)
21
+
22
+ Enhancements:
23
+
24
+ * Import `Source` classes from rspec-core. (Yuji Nakayama, #315)
25
+
1
26
  ### 3.6.0.beta2 / 2016-12-12
2
27
  [Full Changelog](http://github.com/rspec/rspec-support/compare/v3.6.0.beta1...v3.6.0.beta2)
3
28
 
4
- No user-facinc changes.
29
+ No user-facing changes.
5
30
 
6
31
  ### 3.6.0.beta1 / 2016-10-09
7
32
  [Full Changelog](http://github.com/rspec/rspec-support/compare/v3.5.0...v3.6.0.beta1)
@@ -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] ||= {}
@@ -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")
@@ -199,8 +199,7 @@ module RSpec
199
199
  end
200
200
 
201
201
  def klass
202
- singleton_class = class << object; self; end
203
- singleton_class.ancestors.find { |ancestor| !ancestor.equal?(singleton_class) }
202
+ Support.class_of(object)
204
203
  end
205
204
 
206
205
  # http://stackoverflow.com/a/2818916
@@ -243,7 +242,12 @@ module RSpec
243
242
  DescribableMatcherInspector,
244
243
  DelegatorInspector,
245
244
  InspectableObjectInspector
246
- ]
245
+ ].tap do |classes|
246
+ # 2.4 has improved BigDecimal formatting so we do not need
247
+ # to provide our own.
248
+ # https://github.com/ruby/bigdecimal/pull/42
249
+ classes.delete(BigDecimalInspector) if RUBY_VERSION >= '2.4'
250
+ end
247
251
 
248
252
  private
249
253
 
@@ -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,10 @@ 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
+
31
35
  def jruby_9000?
32
36
  jruby? && JRUBY_VERSION >= '9.0.0.0'
33
37
  end
@@ -75,9 +79,10 @@ module RSpec
75
79
  ripper_requirements.push(false) if Ruby.rbx?
76
80
 
77
81
  if Ruby.jruby?
78
- ripper_requirements.push(ComparableVersion.new(JRUBY_VERSION) >= '1.7.5')
79
- # Ripper on JRuby 9.0.0.0.rc1 or later reports wrong line number.
80
- ripper_requirements.push(ComparableVersion.new(JRUBY_VERSION) < '9.0.0.0.rc1')
82
+ ripper_requirements.push(Ruby.jruby_version >= '1.7.5')
83
+ # Ripper on JRuby 9.0.0.0.rc1 - 9.1.8.0 reports wrong line number
84
+ # or cannot parse source including `:if`.
85
+ ripper_requirements.push(!Ruby.jruby_version.between?('9.0.0.0.rc1', '9.1.8.0'))
81
86
  end
82
87
 
83
88
  if ripper_requirements.all?
@@ -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,107 @@
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
+ def each(&block)
49
+ return to_enum(__method__) unless block_given?
50
+
51
+ yield self
52
+
53
+ children.each do |child|
54
+ child.each(&block)
55
+ end
56
+ end
57
+
58
+ def each_ancestor
59
+ return to_enum(__method__) unless block_given?
60
+
61
+ current_node = self
62
+
63
+ while (current_node = current_node.parent)
64
+ yield current_node
65
+ end
66
+ end
67
+
68
+ def inspect
69
+ "#<#{self.class} #{type}>"
70
+ end
71
+
72
+ private
73
+
74
+ def raw_args
75
+ sexp[1..-1] || []
76
+ end
77
+ end
78
+
79
+ # @private
80
+ # Basically `Ripper.sexp` generates arrays whose first element is a symbol (type of sexp),
81
+ # but it exceptionally generates typeless arrays for expression sequence:
82
+ #
83
+ # Ripper.sexp('foo; bar')
84
+ # => [
85
+ # :program,
86
+ # [ # Typeless array
87
+ # [:vcall, [:@ident, "foo", [1, 0]]],
88
+ # [:vcall, [:@ident, "bar", [1, 5]]]
89
+ # ]
90
+ # ]
91
+ #
92
+ # We wrap typeless arrays in this pseudo type node
93
+ # so that it can be handled in the same way as other type node.
94
+ class ExpressionSequenceNode < Node
95
+ def type
96
+ :_expression_sequence
97
+ end
98
+
99
+ private
100
+
101
+ def raw_args
102
+ sexp
103
+ end
104
+ end
105
+ end
106
+ end
107
+ 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
- readme, writeme = IO.pipe
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
- rescue Support::AllExceptionsExceptOnesWeMustNotRescue => e
20
- exception = e
21
+ # rubocop:disable Lint/HandleExceptions
22
+ rescue Support::AllExceptionsExceptOnesWeMustNotRescue => exception
23
+ # rubocop:enable Lint/HandleExceptions
21
24
  end
22
25
 
23
- writeme.write Marshal.dump(exception)
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
- writeme.close
37
+ exception_writer.close
38
+ result_writer.close
31
39
  Process.waitpid(pid)
32
40
 
33
- exception = Marshal.load(readme.read)
34
- readme.close
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, " \
@@ -1,7 +1,7 @@
1
1
  module RSpec
2
2
  module Support
3
3
  module Version
4
- STRING = '3.6.0.beta2'
4
+ STRING = '3.7.0'
5
5
  end
6
6
  end
7
7
  end
@@ -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 << " Use #{options[:replacement]} instead." if options[:replacement]
32
- message << " Called from #{call_site}." if call_site
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.6.0.beta2
4
+ version: 3.7.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - David Chelimsky
@@ -48,7 +48,7 @@ cert_chain:
48
48
  ZsVDj6a7lH3cNqtWXZxrb2wO38qV5AkYj8SQK7Hj3/Yui9myUX3crr+PdetazSqQ
49
49
  F3MdtaDehhjC
50
50
  -----END CERTIFICATE-----
51
- date: 2016-12-12 00:00:00.000000000 Z
51
+ date: 2017-10-17 00:00:00.000000000 Z
52
52
  dependencies:
53
53
  - !ruby/object:Gem::Dependency
54
54
  name: bundler
@@ -116,6 +116,10 @@ files:
116
116
  - lib/rspec/support/recursive_const_methods.rb
117
117
  - lib/rspec/support/reentrant_mutex.rb
118
118
  - lib/rspec/support/ruby_features.rb
119
+ - lib/rspec/support/source.rb
120
+ - lib/rspec/support/source/location.rb
121
+ - lib/rspec/support/source/node.rb
122
+ - lib/rspec/support/source/token.rb
119
123
  - lib/rspec/support/spec.rb
120
124
  - lib/rspec/support/spec/deprecation_helpers.rb
121
125
  - lib/rspec/support/spec/formatting_support.rb
@@ -144,13 +148,13 @@ required_ruby_version: !ruby/object:Gem::Requirement
144
148
  version: 1.8.7
145
149
  required_rubygems_version: !ruby/object:Gem::Requirement
146
150
  requirements:
147
- - - ">"
151
+ - - ">="
148
152
  - !ruby/object:Gem::Version
149
- version: 1.3.1
153
+ version: '0'
150
154
  requirements: []
151
155
  rubyforge_project:
152
- rubygems_version: 2.2.2
156
+ rubygems_version: 2.6.14
153
157
  signing_key:
154
158
  specification_version: 4
155
- summary: rspec-support-3.6.0.beta2
159
+ summary: rspec-support-3.7.0
156
160
  test_files: []
metadata.gz.sig CHANGED
Binary file