Add Ruby 3.1 to CI (#558)

* Add Ruby 3.1 to CI

Update Rubocop for recent Rubies
Disable Rubocop run for Rubies before Ruby 2.4
Quote '3.0' in the CI configuration to ensure it loads a 3.0.x Ruby
Set RUBYOPT="--disable_error_highlight" so Ruby 3.1 error matchers pass

* Add CHANGELOG.md entry

* Re-add deleted line from CHANGELOG.md

* Set minimum supported Ruby version to 2.4.

Remove a number of code bits designed to support Rubies below version 2.4

* Bump version.  Remove unneeded require from Gemfile.  Add require to spec/support file
This commit is contained in:
Peter Goldstein 2022-01-27 18:59:24 -08:00 committed by GitHub
parent 4dc015eb52
commit 3e57eb531f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 89 additions and 105 deletions

View File

@ -52,14 +52,12 @@ jobs:
fail-fast: false fail-fast: false
matrix: matrix:
ruby: ruby:
- 3.0 - '3.1'
- 2.7 - '3.0'
- 2.6 - '2.7'
- 2.5 - '2.6'
- 2.4 - '2.5'
- 2.3 - '2.4'
- 2.2
- 2.1
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
- name: Set up Ruby - name: Set up Ruby
@ -70,6 +68,8 @@ jobs:
- name: Install dependencies - name: Install dependencies
run: bundle install --jobs 4 --retry 3 run: bundle install --jobs 4 --retry 3
- name: Run tests - name: Run tests
env:
RUBYOPT: "--disable-error_highlight"
run: bundle exec rake run: bundle exec rake
test-jruby: test-jruby:

View File

@ -9,7 +9,7 @@ AllCops:
inherit_from: .rubocop_todo.yml inherit_from: .rubocop_todo.yml
# Disabled until we can use the squiggly heredoc (after deprecating Ruby <2.3) # Disabled until we can use the squiggly heredoc (after deprecating Ruby <2.3)
Layout/IndentHeredoc: Layout/HeredocIndentation:
Enabled: false Enabled: false
Metrics/ClassLength: Metrics/ClassLength:
@ -43,3 +43,6 @@ Naming/FileName:
# boolean casting that we do. # boolean casting that we do.
Style/DoubleNegation: Style/DoubleNegation:
Enabled: false Enabled: false
Style/HashSyntax:
Enabled: false

View File

@ -17,6 +17,7 @@ Any violations of this scheme are considered to be bugs.
### Changed ### Changed
* Your contribution here. * Your contribution here.
* [#558](https://github.com/hashie/hashie/pull/558): Test with Ruby 3.1 - [@petergoldstein](https://github.com/petergoldstein).
### Deprecated ### Deprecated

14
Gemfile
View File

@ -9,20 +9,12 @@ group :development do
gem 'guard-rspec', '~> 4.3.1', require: false gem 'guard-rspec', '~> 4.3.1', require: false
gem 'guard-yield', '~> 0.1.0', require: false gem 'guard-yield', '~> 0.1.0', require: false
gem 'pry' gem 'pry'
gem 'pry-stack_explorer', platforms: %i[ruby_19 ruby_20 ruby_21]
gem 'rubocop', '0.52.1' gem 'rubocop', '~> 1.0'
group :test do group :test do
# ActiveSupport required to test compatibility with ActiveSupport Core Extensions. # ActiveSupport required to test compatibility with ActiveSupport Core Extensions.
# rubocop:disable Bundler/DuplicatedGem gem 'activesupport', '~> 5.x', require: false
require File.expand_path('../lib/hashie/extensions/ruby_version', __FILE__)
if Hashie::Extensions::RubyVersion.new(RUBY_VERSION) >=
Hashie::Extensions::RubyVersion.new('2.4.0')
gem 'activesupport', '~> 5.x', require: false
else
gem 'activesupport', '~> 4.x', require: false
end
# rubocop:enable Bundler/DuplicatedGem
gem 'rake' gem 'rake'
gem 'rspec', '~> 3' gem 'rspec', '~> 3'
gem 'rspec-pending_for', '~> 0.1' gem 'rspec-pending_for', '~> 0.1'

View File

@ -1,3 +1,5 @@
# frozen_string_literal: true
require_relative 'spec/support/integration_specs' require_relative 'spec/support/integration_specs'
run_all = lambda do |*| run_all = lambda do |*|

View File

@ -1,3 +1,5 @@
# frozen_string_literal: true
require 'rubygems' require 'rubygems'
require 'bundler' require 'bundler'
Bundler.setup Bundler.setup
@ -16,6 +18,7 @@ RuboCop::RakeTask.new(:rubocop)
require_relative 'spec/support/integration_specs' require_relative 'spec/support/integration_specs'
task :integration_specs do task :integration_specs do
next if ENV['CI'] next if ENV['CI']
status_codes = [] status_codes = []
handler = lambda do |status_code| handler = lambda do |status_code|
status_codes << status_code unless status_code.zero? status_codes << status_code unless status_code.zero?

View File

@ -1,4 +1,5 @@
#!/usr/bin/env ruby #!/usr/bin/env ruby
# frozen_string_literal: true
require 'bundler/setup' require 'bundler/setup'
require 'hashie' require 'hashie'

View File

@ -24,5 +24,7 @@ Gem::Specification.new do |gem|
} }
end end
gem.required_ruby_version = '>= 2.4'
gem.add_development_dependency 'bundler' gem.add_development_dependency 'bundler'
end end

View File

@ -17,14 +17,7 @@ module Hashie
}.freeze }.freeze
ABSTRACT_CORE_TYPES = ABSTRACT_CORE_TYPES =
if RubyVersion.new(RUBY_VERSION) >= RubyVersion.new('2.4.0') { Numeric => [Integer, Float, Complex, Rational] }
{ Numeric => [Integer, Float, Complex, Rational] }
else
{
Integer => [Fixnum, Bignum],
Numeric => [Fixnum, Bignum, Float, Complex, Rational]
}
end
def self.included(base) def self.included(base)
base.send :include, InstanceMethods base.send :include, InstanceMethods

View File

@ -322,22 +322,18 @@ module Hashie
self.class.new(other_hash).merge(self) self.class.new(other_hash).merge(self)
end end
with_minimum_ruby('2.3.0') do def dig(*keys)
def dig(*keys) super(*keys.map { |key| convert_key(key) })
super(*keys.map { |key| convert_key(key) })
end
end end
with_minimum_ruby('2.4.0') do def transform_values(&blk)
def transform_values(&blk) self.class.new(super(&blk))
self.class.new(super(&blk)) end
end
# Returns a new instance of the class it was called on, with nil values # Returns a new instance of the class it was called on, with nil values
# removed. # removed.
def compact def compact
self.class.new(super) self.class.new(super)
end
end end
with_minimum_ruby('2.5.0') do with_minimum_ruby('2.5.0') do

View File

@ -1,3 +1,3 @@
module Hashie module Hashie
VERSION = '5.0.1'.freeze VERSION = '5.1.0'.freeze
end end

View File

@ -1,28 +1,26 @@
require 'spec_helper' require 'spec_helper'
describe Array do describe Array do
with_minimum_ruby('2.3.0') do describe '#dig' do
describe '#dig' do let(:array) { Hashie::Array.new(%i[a b c]) }
let(:array) { Hashie::Array.new(%i[a b c]) }
it 'works with a string index' do it 'works with a string index' do
expect(array.dig('0')).to eq(:a) expect(array.dig('0')).to eq(:a)
end
it 'works with a numeric index' do
expect(array.dig(1)).to eq(:b)
end
context 'when array is empty' do
let(:array) { Hashie::Array.new([]) }
it 'works with a first numeric and next string index' do
expect(array.dig(0, 'hello')).to eq(nil)
end end
it 'works with a numeric index' do it 'throws an error with first string and next numeric index' do
expect(array.dig(1)).to eq(:b) expect { array.dig('hello', 0) }.to raise_error(TypeError)
end
context 'when array is empty' do
let(:array) { Hashie::Array.new([]) }
it 'works with a first numeric and next string index' do
expect(array.dig(0, 'hello')).to eq(nil)
end
it 'throws an error with first string and next numeric index' do
expect { array.dig('hello', 0) }.to raise_error(TypeError)
end
end end
end end
end end

View File

@ -563,13 +563,7 @@ describe Hashie::Extensions::Coercion do
end end
it 'raises a CoercionError when coercion is not possible' do it 'raises a CoercionError when coercion is not possible' do
type = type = Integer
if Hashie::Extensions::RubyVersion.new(RUBY_VERSION) >=
Hashie::Extensions::RubyVersion.new('2.4.0')
Integer
else
Fixnum
end
subject.coerce_value type, Symbol subject.coerce_value type, Symbol
expect { instance[:hi] = 1 }.to raise_error( expect { instance[:hi] = 1 }.to raise_error(
@ -578,13 +572,7 @@ describe Hashie::Extensions::Coercion do
end end
it 'coerces Integer to String' do it 'coerces Integer to String' do
type = type = Integer
if Hashie::Extensions::RubyVersion.new(RUBY_VERSION) >=
Hashie::Extensions::RubyVersion.new('2.4.0')
Integer
else
Fixnum
end
subject.coerce_value type, String subject.coerce_value type, String

View File

@ -649,8 +649,7 @@ describe Hashie::Mash do
context 'when key does not exist' do context 'when key does not exist' do
it 'raises KeyError' do it 'raises KeyError' do
error = RUBY_VERSION =~ /1.8/ ? IndexError : KeyError expect { mash.fetch(:two) }.to raise_error(KeyError)
expect { mash.fetch(:two) }.to raise_error(error)
end end
context 'with default value given' do context 'with default value given' do
@ -980,44 +979,40 @@ describe Hashie::Mash do
end end
end end
with_minimum_ruby('2.3.0') do describe '#dig' do
describe '#dig' do subject { described_class.new(a: { b: 1 }) }
subject { described_class.new(a: { b: 1 }) }
it 'accepts both string and symbol as key' do it 'accepts both string and symbol as key' do
expect(subject.dig(:a, :b)).to eq(1) expect(subject.dig(:a, :b)).to eq(1)
expect(subject.dig('a', 'b')).to eq(1) expect(subject.dig('a', 'b')).to eq(1)
end end
context 'when the Mash wraps a Hashie::Array' do context 'when the Mash wraps a Hashie::Array' do
it 'handles digging into an array' do it 'handles digging into an array' do
mash = described_class.new(alphabet: { first_three: Hashie::Array['a', 'b', 'c'] }) mash = described_class.new(alphabet: { first_three: Hashie::Array['a', 'b', 'c'] })
expect(mash.dig(:alphabet, :first_three, 0)).to eq 'a' expect(mash.dig(:alphabet, :first_three, 0)).to eq 'a'
end
end end
end end
end end
with_minimum_ruby('2.4.0') do describe '#transform_values' do
describe '#transform_values' do subject(:mash) { described_class.new(a: 1) }
subject(:mash) { described_class.new(a: 1) }
it 'returns a Hashie::Mash' do it 'returns a Hashie::Mash' do
expect(mash.transform_values(&:to_s)).to be_kind_of(described_class) expect(mash.transform_values(&:to_s)).to be_kind_of(described_class)
end end
it 'transforms the value' do it 'transforms the value' do
expect(mash.transform_values(&:to_s).a).to eql('1') expect(mash.transform_values(&:to_s).a).to eql('1')
end end
context 'when using with subclass' do context 'when using with subclass' do
let(:subclass) { Class.new(Hashie::Mash) } let(:subclass) { Class.new(Hashie::Mash) }
subject(:sub_mash) { subclass.new(a: 1).transform_values { |a| a + 2 } } subject(:sub_mash) { subclass.new(a: 1).transform_values { |a| a + 2 } }
it 'creates an instance of subclass' do it 'creates an instance of subclass' do
expect(sub_mash).to be_kind_of(subclass) expect(sub_mash).to be_kind_of(subclass)
end
end end
end end

View File

@ -1,3 +1,5 @@
# frozen_string_literal: true
namespace :perf do namespace :perf do
task :setup do task :setup do
require 'omniauth' require 'omniauth'
@ -12,6 +14,7 @@ namespace :perf do
def call_app(path = ENV['GET_PATH'] || '/') def call_app(path = ENV['GET_PATH'] || '/')
result = @app.get(path) result = @app.get(path)
raise "Did not succeed #{result.body}" unless result.status == 200 raise "Did not succeed #{result.body}" unless result.status == 200
result result
end end
end end

View File

@ -1,10 +1,17 @@
require File.expand_path('../../../lib/hashie/extensions/ruby_version', __FILE__)
# Generates the bundle command for running an integration test # Generates the bundle command for running an integration test
# #
# @param [String] integration the integration folder to run # @param [String] integration the integration folder to run
# @param [String] command the command to run # @param [String] command the command to run
# @return [String] # @return [String]
def integration_command(integration, command) def integration_command(integration, command)
"#{integration_gemfile(integration)} #{command}" if Hashie::Extensions::RubyVersion.new(RUBY_VERSION) >=
Hashie::Extensions::RubyVersion.new('3.1.0')
ruby_opts = "RUBYOPT=--disable-error_highlight "
end
"#{ruby_opts}#{integration_gemfile(integration)} #{command}"
end end
# Generates the Gemfile for an integration # Generates the Gemfile for an integration