diff --git a/CHANGELOG.md b/CHANGELOG.md index 0b646c7fd58..05b88f3ebc0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,7 @@ * [#8646](https://github.com/rubocop-hq/rubocop/issues/8646): Faster find of all files in `TargetFinder` class which improves initial startup speed. ([@tleish][]) * [#8102](https://github.com/rubocop-hq/rubocop/issues/8102): Consider class length instead of block length for `Struct.new`. ([@tejasbubane][]) +* [#7408](https://github.com/rubocop-hq/rubocop/issues/7408): Make `Gemspec/RequiredRubyVersion` cop aware of `Gem::Requirement`. ([@tejasbubane][]) ## 0.92.0 (2020-09-25) diff --git a/lib/rubocop/cop/gemspec/required_ruby_version.rb b/lib/rubocop/cop/gemspec/required_ruby_version.rb index aeed941b855..7b912b48257 100644 --- a/lib/rubocop/cop/gemspec/required_ruby_version.rb +++ b/lib/rubocop/cop/gemspec/required_ruby_version.rb @@ -58,24 +58,22 @@ class RequiredRubyVersion < Cop (send _ :required_ruby_version= $_) PATTERN - def_node_matcher :string_version?, <<~PATTERN - {(str _) (array (str _))} + def_node_matcher :defined_ruby_version, <<~PATTERN + {$(str _) $(array (str _) (str _)) + (send (const (const nil? :Gem) :Requirement) :new $(str _))} PATTERN # rubocop:disable Metrics/AbcSize def investigate(processed_source) - version = required_ruby_version(processed_source.ast).first + version_def = required_ruby_version(processed_source.ast).first - if version - return unless string_version?(version) - - ruby_version = extract_ruby_version(version) - - return if ruby_version == target_ruby_version.to_s + if version_def + ruby_version = extract_ruby_version(defined_ruby_version(version_def)) + return if !ruby_version || ruby_version == target_ruby_version.to_s add_offense( processed_source.ast, - location: version.loc.expression, + location: version_def.loc.expression, message: not_equal_message(ruby_version, target_ruby_version) ) else @@ -88,6 +86,8 @@ def investigate(processed_source) private def extract_ruby_version(required_ruby_version) + return unless required_ruby_version + if required_ruby_version.array_type? required_ruby_version = required_ruby_version.children.detect do |v| /[>=]/.match?(v.str_content) diff --git a/spec/rubocop/cop/gemspec/required_ruby_version_spec.rb b/spec/rubocop/cop/gemspec/required_ruby_version_spec.rb index 789df4a1f07..4c3f2c49fe6 100644 --- a/spec/rubocop/cop/gemspec/required_ruby_version_spec.rb +++ b/spec/rubocop/cop/gemspec/required_ruby_version_spec.rb @@ -20,6 +20,24 @@ RUBY end + it 'registers an offense when `required_ruby_version` is specified in array and is lower than `TargetRubyVersion`' do + expect_offense(<<~RUBY, '/path/to/foo.gemspec') + Gem::Specification.new do |spec| + spec.required_ruby_version = ['>= 2.6.0', '< 3.0.0'] + ^^^^^^^^^^^^^^^^^^^^^^^ `required_ruby_version` (2.6, declared in foo.gemspec) and `TargetRubyVersion` (2.7, which may be specified in .rubocop.yml) should be equal. + end + RUBY + end + + it 'recognizes Gem::Requirement and registers offense' do + expect_offense(<<~RUBY, '/path/to/foo.gemspec') + Gem::Specification.new do |spec| + spec.required_ruby_version = Gem::Requirement.new(">= 2.6.0") + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `required_ruby_version` (2.6, declared in foo.gemspec) and `TargetRubyVersion` (2.7, which may be specified in .rubocop.yml) should be equal. + end + RUBY + end + describe 'false negatives' do it 'does not register an offense when `required_ruby_version` ' \ 'is assigned as a variable (string literal)' do