Skip to content
This repository was archived by the owner on Nov 30, 2024. It is now read-only.

Commit 1a26b09

Browse files
authored
Merge pull request #436 from rspec/drop-old-rubies
Drop Ruby < 2.3 support
2 parents b9de711 + 0d41dfa commit 1a26b09

40 files changed

+961
-1677
lines changed

Changelog.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
### Development (unreleased)
2+
3+
Breaking Changes:
4+
5+
* Ruby < 2.3 is no longer supported. (Phil Pirozhkov, #436)
6+
17
### 3.10.0 / 2020-10-30
28

39
No changes. Released to support other RSpec releases.

Gemfile

Lines changed: 3 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -13,51 +13,21 @@ branch = File.read(File.expand_path("../maintenance-branch", __FILE__)).chomp
1313
end
1414
end
1515

16-
if RUBY_VERSION < '1.9.3'
17-
gem 'rake', '< 11.0.0' # rake 11 requires Ruby 1.9.3 or later
18-
elsif RUBY_VERSION < '2.0.0'
19-
gem 'rake', '< 12.0.0' # rake 12 requires Ruby 2.0.0 or later
20-
else
21-
gem 'rake', '>= 12.3.3'
22-
end
23-
2416
if ENV['DIFF_LCS_VERSION']
2517
gem 'diff-lcs', ENV['DIFF_LCS_VERSION']
2618
else
2719
gem 'diff-lcs', '~> 1.4', '>= 1.4.3'
2820
end
2921

30-
if RUBY_VERSION < '2.3.0' && !!(RbConfig::CONFIG['host_os'] =~ /cygwin|mswin|mingw|bccwin|wince|emx/)
31-
gem "childprocess", "< 1.0.0"
32-
elsif RUBY_VERSION < '2.3.0'
33-
gem "childprocess", "< 3.0.0"
34-
else
35-
gem "childprocess", ">= 3.0.0"
36-
end
22+
gem "childprocess", ">= 3.0.0"
23+
gem 'ffi', '~> 1.12.0'
3724

3825
### dep for ci/coverage
3926
gem 'simplecov', '~> 0.8'
4027

41-
if RUBY_VERSION < '2.0.0' || RUBY_ENGINE == 'java'
42-
gem 'json', '< 2.0.0' # is a dependency of simplecov
43-
else
44-
gem 'json', '> 2.3.0'
45-
end
46-
47-
if RUBY_VERSION < '2.2.0' && !!(RbConfig::CONFIG['host_os'] =~ /cygwin|mswin|mingw|bccwin|wince|emx/)
48-
gem 'ffi', '< 1.10'
49-
elsif RUBY_VERSION < '2.0'
50-
# ffi dropped Ruby 1.8 support in 1.9.19 and Ruby 1.9 support in 1.11.0
51-
gem 'ffi', '< 1.9.19'
52-
elsif RUBY_VERSION < '2.3.0'
53-
gem 'ffi', '~> 1.12.0'
54-
else
55-
gem 'ffi', '~> 1.13.0'
56-
end
57-
5828
# No need to run rubocop on earlier versions
5929
if RUBY_VERSION >= '2.4' && RUBY_ENGINE == 'ruby'
6030
gem "rubocop", "~> 0.52.1"
6131
end
6232

63-
eval File.read('Gemfile-custom') if File.exist?('Gemfile-custom')
33+
eval_gemfile 'Gemfile-custom' if File.exist?('Gemfile-custom')

lib/rspec/support.rb

Lines changed: 11 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -12,22 +12,13 @@ module Support
1212
# hand, does a linear O(N) search over the dirs in the $LOAD_PATH until
1313
# it can resolve the file relative to one of the dirs.
1414
def self.define_optimized_require_for_rspec(lib, &require_relative)
15-
name = "require_rspec_#{lib}"
16-
17-
if Kernel.respond_to?(:require_relative)
18-
(class << self; self; end).__send__(:define_method, name) do |f|
19-
require_relative.call("#{lib}/#{f}")
20-
end
21-
else
22-
(class << self; self; end).__send__(:define_method, name) do |f|
23-
require "rspec/#{lib}/#{f}"
24-
end
15+
define_singleton_method("require_rspec_#{lib}") do |f|
16+
require_relative.call("#{lib}/#{f}")
2517
end
2618
end
2719

2820
define_optimized_require_for_rspec(:support) { |f| require_relative(f) }
2921
require_rspec_support "version"
30-
require_rspec_support "ruby_features"
3122

3223
# @api private
3324
KERNEL_METHOD_METHOD = ::Kernel.instance_method(:method)
@@ -43,33 +34,15 @@ def self.define_optimized_require_for_rspec(lib, &require_relative)
4334
# - BasicObject subclasses that mixin a Kernel dup (e.g. SimpleDelegator)
4435
# - Objects that undefine method and delegate everything to another
4536
# object (e.g. Mongoid association objects)
46-
if RubyFeatures.supports_rebinding_module_methods?
47-
def self.method_handle_for(object, method_name)
48-
KERNEL_METHOD_METHOD.bind(object).call(method_name)
49-
rescue NameError => original
50-
begin
51-
handle = object.method(method_name)
52-
raise original unless handle.is_a? Method
53-
handle
54-
rescue Support::AllExceptionsExceptOnesWeMustNotRescue
55-
raise original
56-
end
57-
end
58-
else
59-
def self.method_handle_for(object, method_name)
60-
if ::Kernel === object
61-
KERNEL_METHOD_METHOD.bind(object).call(method_name)
62-
else
63-
object.method(method_name)
64-
end
65-
rescue NameError => original
66-
begin
67-
handle = object.method(method_name)
68-
raise original unless handle.is_a? Method
69-
handle
70-
rescue Support::AllExceptionsExceptOnesWeMustNotRescue
71-
raise original
72-
end
37+
def self.method_handle_for(object, method_name)
38+
KERNEL_METHOD_METHOD.bind(object).call(method_name)
39+
rescue NameError => original
40+
begin
41+
handle = object.method(method_name)
42+
raise original unless handle.is_a? Method
43+
handle
44+
rescue Support::AllExceptionsExceptOnesWeMustNotRescue
45+
raise original
7346
end
7447
end
7548

lib/rspec/support/caller_filter.rb

Lines changed: 37 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
RSpec::Support.require_rspec_support "ruby_features"
2-
31
module RSpec
42
# Consistent implementation for "cleaning" the caller method to strip out
53
# non-rspec lines. This enables errors to be reported at the call site in
@@ -27,56 +25,48 @@ class CallerFilter
2725
# with this complexity in our `RSpec.deprecate` calls, so we ignore it here.
2826
IGNORE_REGEX = Regexp.union(LIB_REGEX, "rubygems/core_ext/kernel_require.rb")
2927

30-
if RSpec::Support::RubyFeatures.caller_locations_supported?
31-
# This supports args because it's more efficient when the caller specifies
32-
# these. It allows us to skip frames the caller knows are part of RSpec,
33-
# and to decrease the increment size if the caller is confident the line will
34-
# be found in a small number of stack frames from `skip_frames`.
35-
#
36-
# Note that there is a risk to passing a `skip_frames` value that is too high:
37-
# If it skippped the first non-rspec line, then this method would return the
38-
# 2nd or 3rd (or whatever) non-rspec line. Thus, you generally shouldn't pass
39-
# values for these parameters, particularly since most places that use this are
40-
# not hot spots (generally it gets used for deprecation warnings). However,
41-
# if you do have a hot spot that calls this, passing `skip_frames` can make
42-
# a significant difference. Just make sure that that particular use is tested
43-
# so that if the provided `skip_frames` changes to no longer be accurate in
44-
# such a way that would return the wrong stack frame, a test will fail to tell you.
45-
#
46-
# See benchmarks/skip_frames_for_caller_filter.rb for measurements.
47-
def self.first_non_rspec_line(skip_frames=3, increment=5)
48-
# Why a default `skip_frames` of 3?
49-
# By the time `caller_locations` is called below, the first 3 frames are:
50-
# lib/rspec/support/caller_filter.rb:63:in `block in first_non_rspec_line'
51-
# lib/rspec/support/caller_filter.rb:62:in `loop'
52-
# lib/rspec/support/caller_filter.rb:62:in `first_non_rspec_line'
28+
# This supports args because it's more efficient when the caller specifies
29+
# these. It allows us to skip frames the caller knows are part of RSpec,
30+
# and to decrease the increment size if the caller is confident the line will
31+
# be found in a small number of stack frames from `skip_frames`.
32+
#
33+
# Note that there is a risk to passing a `skip_frames` value that is too high:
34+
# If it skippped the first non-rspec line, then this method would return the
35+
# 2nd or 3rd (or whatever) non-rspec line. Thus, you generally shouldn't pass
36+
# values for these parameters, particularly since most places that use this are
37+
# not hot spots (generally it gets used for deprecation warnings). However,
38+
# if you do have a hot spot that calls this, passing `skip_frames` can make
39+
# a significant difference. Just make sure that that particular use is tested
40+
# so that if the provided `skip_frames` changes to no longer be accurate in
41+
# such a way that would return the wrong stack frame, a test will fail to tell you.
42+
#
43+
# See benchmarks/skip_frames_for_caller_filter.rb for measurements.
44+
def self.first_non_rspec_line(skip_frames=3, increment=5)
45+
# Why a default `skip_frames` of 3?
46+
# By the time `caller_locations` is called below, the first 3 frames are:
47+
# lib/rspec/support/caller_filter.rb:63:in `block in first_non_rspec_line'
48+
# lib/rspec/support/caller_filter.rb:62:in `loop'
49+
# lib/rspec/support/caller_filter.rb:62:in `first_non_rspec_line'
5350

54-
# `caller` is an expensive method that scales linearly with the size of
55-
# the stack. The performance hit for fetching it in chunks is small,
56-
# and since the target line is probably near the top of the stack, the
57-
# overall improvement of a chunked search like this is significant.
58-
#
59-
# See benchmarks/caller.rb for measurements.
51+
# `caller` is an expensive method that scales linearly with the size of
52+
# the stack. The performance hit for fetching it in chunks is small,
53+
# and since the target line is probably near the top of the stack, the
54+
# overall improvement of a chunked search like this is significant.
55+
#
56+
# See benchmarks/caller.rb for measurements.
6057

61-
# The default increment of 5 for this method are mostly arbitrary, but
62-
# is chosen to give good performance on the common case of creating a double.
58+
# The default increment of 5 for this method are mostly arbitrary, but
59+
# is chosen to give good performance on the common case of creating a double.
6360

64-
loop do
65-
stack = caller_locations(skip_frames, increment)
66-
raise "No non-lib lines in stack" unless stack
61+
loop do
62+
stack = caller_locations(skip_frames, increment)
63+
raise "No non-lib lines in stack" unless stack
6764

68-
line = stack.find { |l| l.path !~ IGNORE_REGEX }
69-
return line.to_s if line
65+
line = stack.find { |l| l.path !~ IGNORE_REGEX }
66+
return line.to_s if line
7067

71-
skip_frames += increment
72-
increment *= 2 # The choice of two here is arbitrary.
73-
end
74-
end
75-
else
76-
# Earlier rubies do not support the two argument form of `caller`. This
77-
# fallback is logically the same, but slower.
78-
def self.first_non_rspec_line(*)
79-
caller.find { |line| line !~ IGNORE_REGEX }
68+
skip_frames += increment
69+
increment *= 2 # The choice of two here is arbitrary.
8070
end
8171
end
8272
end

lib/rspec/support/differ.rb

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -102,14 +102,8 @@ def diffably_stringify(array)
102102
end
103103
end
104104

105-
if String.method_defined?(:encoding)
106-
def multiline?(string)
107-
string.include?("\n".encode(string.encoding))
108-
end
109-
else
110-
def multiline?(string)
111-
string.include?("\n")
112-
end
105+
def multiline?(string)
106+
string.include?("\n".encode(string.encoding))
113107
end
114108

115109
def build_hunks(actual, expected)

lib/rspec/support/directory_maker.rb

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
RSpec::Support.require_rspec_support 'ruby_features'
2-
31
module RSpec
42
module Support
53
# @api private

0 commit comments

Comments
 (0)