Skip to content

Commit

Permalink
[Fix rubocop#8761] Add GemspecFile class and specs
Browse files Browse the repository at this point in the history
  • Loading branch information
HeroProtagonist committed Nov 7, 2020
1 parent 37467bc commit e8af386
Show file tree
Hide file tree
Showing 2 changed files with 173 additions and 1 deletion.
58 changes: 57 additions & 1 deletion lib/rubocop/target_ruby.rb
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,62 @@ 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'

def_node_search :required_ruby_version, <<~PATTERN
(send _ :required_ruby_version= $_)
PATTERN

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

private

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

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

if version.array_type?
versions = version.children.map { |v| version_from_str(v.str_content) }
return versions.compact.min
end

version_from_str(version.str_content)
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_str(str)
str.match(/^(?:>=|<=)?\s*(?<version>\d+(?:\.\d+)*)/) do |md|
md[:version].to_f
end
end
end

# If all else fails, a default version will be picked.
# @api private
class Default < Source
Expand All @@ -130,7 +186,7 @@ def self.supported_versions
KNOWN_RUBIES
end

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

def initialize(config)
Expand Down
116 changes: 116 additions & 0 deletions spec/rubocop/target_ruby_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,122 @@
expect(target_ruby.version).to eq default_version
end
end

context 'gemspec file' do
context 'when file contains `required_ruby_version` as a string' do
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
content =
<<-HEREDOC
Gem::Specification.new do |s|
s.name = 'test'
s.required_ruby_version = '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 range' do
content =
<<-HEREDOC
Gem::Specification.new do |s|
s.name = 'test'
s.required_ruby_version = '>= 3.0.0'
s.licenses = ['MIT']
end
HEREDOC

create_file(gemspec_file_path, content)
expect(target_ruby.version).to eq 3.0
end

it 'sets default target_ruby from exclusive range' do
content =
<<-HEREDOC
Gem::Specification.new do |s|
s.name = 'test'
s.required_ruby_version = '< 3.0.0'
s.licenses = ['MIT']
end
HEREDOC

create_file(gemspec_file_path, content)
expect(target_ruby.version).to eq default_version
end
end

context 'when file contains `required_ruby_version` as an array' do
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
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 2.6
end

it 'sets target_ruby from required_ruby_version with inclusive range' 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 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
end
end

context 'when file does not contain `required_ruby_version`' do
let(:base_path) { configuration.base_dir_for_path_parameters }
let(:gemspec_file_path) { File.join(base_path, 'example.gemspec') }

it 'sets default target_ruby' do
content =
<<-HEREDOC
Gem::Specification.new do |s|
s.name = 'test'
s.platform = Gem::Platform::RUBY
s.licenses = ['MIT']
s.summary = 'test tool.'
end
HEREDOC

create_file(gemspec_file_path, content)
expect(target_ruby.version).to eq default_version
end
end
end
end

context 'when .ruby-version is in a parent directory' do
Expand Down

0 comments on commit e8af386

Please sign in to comment.