Skip to content

Commit

Permalink
Merge pull request #12645 from jenshenny/change-source-order
Browse files Browse the repository at this point in the history
Check gemspec `required_ruby_version` before `.ruby-version` and other sources
  • Loading branch information
koic committed Jan 26, 2024
2 parents 3e31e45 + 02b2c3a commit d1746be
Show file tree
Hide file tree
Showing 4 changed files with 278 additions and 259 deletions.
1 change: 1 addition & 0 deletions changelog/change_source_order_for_target_ruby.md
@@ -0,0 +1 @@
* [#12645](https://github.com/rubocop/rubocop/pull/12645): Change source order for target ruby to check gemspec after RuboCop configuration. ([@jenshenny][])
2 changes: 1 addition & 1 deletion docs/modules/ROOT/pages/configuration.adoc
Expand Up @@ -610,7 +610,7 @@ AllCops:

Otherwise, RuboCop will then check your project for a series of files where
the version may be specified already. The files that will be looked for are
`.ruby-version`, `.tool-versions`, `Gemfile.lock`, and `*.gemspec`.
`*.gemspec`, `.ruby-version`, `.tool-versions`, and `Gemfile.lock`.
If Gemspec file has an array for `required_ruby_version`, the lowest version will be used.
If none of the files are found a default version value will be used.

Expand Down
158 changes: 79 additions & 79 deletions lib/rubocop/target_ruby.rb
Expand Up @@ -48,6 +48,84 @@ def find_version
end
end

# The target ruby version may be found in a .gemspec file.
# @api private
class GemspecFile < Source
extend NodePattern::Macros

GEMSPEC_EXTENSION = '.gemspec'

# @!method required_ruby_version(node)
def_node_search :required_ruby_version, <<~PATTERN
(send _ :required_ruby_version= $_)
PATTERN

# @!method gem_requirement_versions(node)
def_node_matcher :gem_requirement_versions, <<~PATTERN
(send (const(const _ :Gem):Requirement) :new
{$str+ | (send $str :freeze)+ | (array $str+) | (array (send $str :freeze)+)}
)
PATTERN

def name
"`required_ruby_version` parameter (in #{gemspec_filename})"
end

private

def find_version
file = gemspec_filepath
return unless file && File.file?(file)

right_hand_side = version_from_gemspec_file(file)
return if right_hand_side.nil?

find_default_minimal_known_ruby(right_hand_side)
end

def gemspec_filename
@gemspec_filename ||= begin
basename = Pathname.new(@config.base_dir_for_path_parameters).basename.to_s
"#{basename}#{GEMSPEC_EXTENSION}"
end
end

def gemspec_filepath
@gemspec_filepath ||=
@config.find_file_upwards(gemspec_filename, @config.base_dir_for_path_parameters)
end

def version_from_gemspec_file(file)
processed_source = ProcessedSource.from_file(file, DEFAULT_VERSION)
required_ruby_version(processed_source.ast).first
end

def version_from_right_hand_side(right_hand_side)
gem_requirement_versions = gem_requirement_versions(right_hand_side)

if right_hand_side.array_type?
version_from_array(right_hand_side)
elsif gem_requirement_versions
gem_requirement_versions.map(&:value)
else
right_hand_side.value
end
end

def version_from_array(array)
array.children.map(&:value)
end

def find_default_minimal_known_ruby(right_hand_side)
version = version_from_right_hand_side(right_hand_side)
requirement = Gem::Requirement.new(version)

KNOWN_RUBIES.detect do |v|
v >= DEFAULT_VERSION && requirement.satisfied_by?(Gem::Version.new("#{v}.99"))
end
end
end

# The target ruby version may be found in a .ruby-version file.
# @api private
class RubyVersionFile < Source
Expand Down Expand Up @@ -143,84 +221,6 @@ def bundler_lock_file_path
end
end

# The target ruby version may be found in a .gemspec file.
# @api private
class GemspecFile < Source
extend NodePattern::Macros

GEMSPEC_EXTENSION = '.gemspec'

# @!method required_ruby_version(node)
def_node_search :required_ruby_version, <<~PATTERN
(send _ :required_ruby_version= $_)
PATTERN

# @!method gem_requirement_versions(node)
def_node_matcher :gem_requirement_versions, <<~PATTERN
(send (const(const _ :Gem):Requirement) :new
{$str+ | (send $str :freeze)+ | (array $str+) | (array (send $str :freeze)+)}
)
PATTERN

def name
"`required_ruby_version` parameter (in #{gemspec_filename})"
end

private

def find_version
file = gemspec_filepath
return unless file && File.file?(file)

right_hand_side = version_from_gemspec_file(file)
return if right_hand_side.nil?

find_default_minimal_known_ruby(right_hand_side)
end

def gemspec_filename
@gemspec_filename ||= begin
basename = Pathname.new(@config.base_dir_for_path_parameters).basename.to_s
"#{basename}#{GEMSPEC_EXTENSION}"
end
end

def gemspec_filepath
@gemspec_filepath ||=
@config.find_file_upwards(gemspec_filename, @config.base_dir_for_path_parameters)
end

def version_from_gemspec_file(file)
processed_source = ProcessedSource.from_file(file, DEFAULT_VERSION)
required_ruby_version(processed_source.ast).first
end

def version_from_right_hand_side(right_hand_side)
gem_requirement_versions = gem_requirement_versions(right_hand_side)

if right_hand_side.array_type?
version_from_array(right_hand_side)
elsif gem_requirement_versions
gem_requirement_versions.map(&:value)
else
right_hand_side.value
end
end

def version_from_array(array)
array.children.map(&:value)
end

def find_default_minimal_known_ruby(right_hand_side)
version = version_from_right_hand_side(right_hand_side)
requirement = Gem::Requirement.new(version)

KNOWN_RUBIES.detect do |v|
v >= DEFAULT_VERSION && requirement.satisfied_by?(Gem::Version.new("#{v}.99"))
end
end
end

# If all else fails, a default version will be picked.
# @api private
class Default < Source
Expand All @@ -241,10 +241,10 @@ def self.supported_versions

SOURCES = [
RuboCopConfig,
GemspecFile,
RubyVersionFile,
ToolVersionsFile,
BundlerLockFile,
GemspecFile,
Default
].freeze

Expand Down

0 comments on commit d1746be

Please sign in to comment.