diff --git a/changelog/fix_return_minimal_known_ruby_version_from.md b/changelog/fix_return_minimal_known_ruby_version_from.md new file mode 100644 index 00000000000..93d49548920 --- /dev/null +++ b/changelog/fix_return_minimal_known_ruby_version_from.md @@ -0,0 +1 @@ +* [#9482](https://github.com/rubocop-hq/rubocop/issues/9482): Return minimal known ruby version from gemspecs `required_ruby_version`. ([@HeroProtagonist][]) diff --git a/lib/rubocop/target_ruby.rb b/lib/rubocop/target_ruby.rb index dc261b40598..19cf3024db4 100644 --- a/lib/rubocop/target_ruby.rb +++ b/lib/rubocop/target_ruby.rb @@ -165,14 +165,10 @@ def find_version file = gemspec_filepath return unless file && File.file?(file) - version = version_from_gemspec_file(file) - return if version.nil? + right_hand_side = version_from_gemspec_file(file) + return if right_hand_side.nil? - requirement = version.children.last - return version_from_array(version) if version.array_type? - return version_from_array(requirement) if gem_requirement? version - - version_from_str(version.str_content) + find_minimal_known_ruby(right_hand_side) end def gemspec_filename @@ -192,15 +188,25 @@ def version_from_gemspec_file(file) required_ruby_version(processed_source.ast).first end + def version_from_right_hand_side(right_hand_side) + if right_hand_side.array_type? + version_from_array(right_hand_side) + elsif gem_requirement?(right_hand_side) + right_hand_side.children.last.value + else + right_hand_side.value + end + end + def version_from_array(array) - versions = array.children.map { |v| version_from_str(v.is_a?(String) ? v : v.str_content) } - versions.compact.min + array.children.map(&:value) end - def version_from_str(str) - str.match(/^(?:>=|<=)?\s*(?\d+(?:\.\d+)*)/) do |md| - md[:version].to_f - end + def find_minimal_known_ruby(right_hand_side) + version = version_from_right_hand_side(right_hand_side) + requirement = Gem::Requirement.new(version) + + KNOWN_RUBIES.detect { |v| requirement.satisfied_by?(Gem::Version.new("#{v}.99")) } end end diff --git a/spec/rubocop/target_ruby_spec.rb b/spec/rubocop/target_ruby_spec.rb index 165122d9054..e8c8109a7de 100644 --- a/spec/rubocop/target_ruby_spec.rb +++ b/spec/rubocop/target_ruby_spec.rb @@ -294,46 +294,46 @@ let(:base_path) { configuration.base_dir_for_path_parameters } let(:gemspec_file_path) { File.join(base_path, 'example.gemspec') } - it 'sets target_ruby from required_ruby_version from exact version' do + it 'sets target_ruby from inclusive range' do content = <<-HEREDOC Gem::Specification.new do |s| s.name = 'test' - s.required_ruby_version = '2.7.4' + s.required_ruby_version = '>= 2.6.1' s.licenses = ['MIT'] end HEREDOC create_file(gemspec_file_path, content) - expect(target_ruby.version).to eq 2.7 + expect(target_ruby.version).to eq 2.6 end - it 'sets target_ruby from required_ruby_version from inclusive range' do + it 'sets target_ruby from exclusive range' do content = <<-HEREDOC Gem::Specification.new do |s| s.name = 'test' - s.required_ruby_version = '>= 3.0.0' + s.required_ruby_version = '> 2.4.1' s.licenses = ['MIT'] end HEREDOC create_file(gemspec_file_path, content) - expect(target_ruby.version).to eq 3.0 + expect(target_ruby.version).to eq 2.4 end - it 'sets default target_ruby from exclusive range' do + it 'sets target_ruby from approximate version' do content = <<-HEREDOC Gem::Specification.new do |s| s.name = 'test' - s.required_ruby_version = '< 3.0.0' + s.required_ruby_version = '~> 2.5.0' s.licenses = ['MIT'] end HEREDOC create_file(gemspec_file_path, content) - expect(target_ruby.version).to eq default_version + expect(target_ruby.version).to eq 2.5 end end @@ -341,35 +341,21 @@ let(:base_path) { configuration.base_dir_for_path_parameters } let(:gemspec_file_path) { File.join(base_path, 'example.gemspec') } - it 'sets target_ruby from required_ruby_version from exact requirement version' do - content = - <<-HEREDOC - Gem::Specification.new do |s| - s.name = 'test' - s.required_ruby_version = Gem::Requirement.new('2.7.4') - s.licenses = ['MIT'] - end - HEREDOC - - create_file(gemspec_file_path, content) - expect(target_ruby.version).to eq 2.7 - end - it 'sets target_ruby from required_ruby_version from inclusive requirement range' do content = <<-HEREDOC Gem::Specification.new do |s| s.name = 'test' - s.required_ruby_version = Gem::Requirement.new('>= 3.0.0') + s.required_ruby_version = Gem::Requirement.new('>= 2.3.1') s.licenses = ['MIT'] end HEREDOC create_file(gemspec_file_path, content) - expect(target_ruby.version).to eq 3.0 + expect(target_ruby.version).to eq default_version end - it 'sets default target_ruby from exclusive requirement range' do + it 'sets first known ruby version that satisfies requirement' do content = <<-HEREDOC Gem::Specification.new do |s| @@ -388,7 +374,7 @@ let(:base_path) { configuration.base_dir_for_path_parameters } let(:gemspec_file_path) { File.join(base_path, 'example.gemspec') } - it 'sets target_ruby from the lowest value' do + it 'sets target_ruby to the minimal version satisfying the requirements' do content = <<-HEREDOC Gem::Specification.new do |s| @@ -402,32 +388,18 @@ expect(target_ruby.version).to eq 2.6 end - it 'sets target_ruby from required_ruby_version with inclusive range' do + it 'sets target_ruby from required_ruby_version with many requirements' do content = <<-HEREDOC Gem::Specification.new do |s| s.name = 'test' - s.required_ruby_version = ['<=2.7.4', '>2.6.5'] + s.required_ruby_version = ['<=2.7.4', '>2.4.5', '~>2.5.1'] s.licenses = ['MIT'] end HEREDOC create_file(gemspec_file_path, content) - expect(target_ruby.version).to eq 2.7 - end - - it 'sets default target_ruby with all exclusive ranges' do - content = - <<-HEREDOC - Gem::Specification.new do |s| - s.name = 'test' - s.required_ruby_version = ['<2.7.4', '>2.6.5'] - s.licenses = ['MIT'] - end - HEREDOC - - create_file(gemspec_file_path, content) - expect(target_ruby.version).to eq default_version + expect(target_ruby.version).to eq 2.5 end end