Skip to content

Commit 7048b51

Browse files
fatkodimabbatsov
andauthored
Enhance Gemspec/RequiredRubyVersion cop with check that required_ruby_version is specified (#8370)
Co-authored-by: Bozhidar Batsov <[email protected]>
1 parent 426814e commit 7048b51

File tree

5 files changed

+51
-15
lines changed

5 files changed

+51
-15
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
### New features
66

77
* [#8322](https://github.com/rubocop-hq/rubocop/pull/8322): Support autocorrect for `Style/CaseEquality` cop. ([@fatkodima][])
8+
* [#7876](https://github.com/rubocop-hq/rubocop/issues/7876): Enhance `Gemspec/RequiredRubyVersion` cop with check that `required_ruby_version` is specified. ([@fatkodima][])
89
* [#8291](https://github.com/rubocop-hq/rubocop/pull/8291): Add new `Lint/SelfAssignment` cop. ([@fatkodima][])
910
* [#8389](https://github.com/rubocop-hq/rubocop/pull/8389): Add new `Lint/DuplicateRescueException` cop. ([@fatkodima][])
1011
* [#8433](https://github.com/rubocop-hq/rubocop/pull/8433): Add new `Lint/BinaryOperatorWithIdenticalOperands` cop. ([@fatkodima][])

config/default.yml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -210,9 +210,10 @@ Gemspec/OrderedDependencies:
210210
- '**/*.gemspec'
211211

212212
Gemspec/RequiredRubyVersion:
213-
Description: 'Checks that `required_ruby_version` of gemspec and `TargetRubyVersion` of .rubocop.yml are equal.'
213+
Description: 'Checks that `required_ruby_version` of gemspec is specified and equal to `TargetRubyVersion` of .rubocop.yml.'
214214
Enabled: true
215215
VersionAdded: '0.52'
216+
VersionChanged: '0.89'
216217
Include:
217218
- '**/*.gemspec'
218219

docs/modules/ROOT/pages/cops_gemspec.adoc

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -149,11 +149,11 @@ spec.add_dependency 'rspec'
149149
| Yes
150150
| No
151151
| 0.52
152-
| -
152+
| 0.89
153153
|===
154154

155-
Checks that `required_ruby_version` of gemspec and `TargetRubyVersion`
156-
of .rubocop.yml are equal.
155+
Checks that `required_ruby_version` of gemspec is specified and
156+
equal to `TargetRubyVersion` of .rubocop.yml.
157157
Thereby, RuboCop to perform static analysis working on the version
158158
required by gemspec.
159159

@@ -163,6 +163,11 @@ required by gemspec.
163163
----
164164
# When `TargetRubyVersion` of .rubocop.yml is `2.5`.
165165
166+
# bad
167+
Gem::Specification.new do |spec|
168+
# no `required_ruby_version` specified
169+
end
170+
166171
# bad
167172
Gem::Specification.new do |spec|
168173
spec.required_ruby_version = '>= 2.4.0'

lib/rubocop/cop/gemspec/required_ruby_version.rb

Lines changed: 32 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@
33
module RuboCop
44
module Cop
55
module Gemspec
6-
# Checks that `required_ruby_version` of gemspec and `TargetRubyVersion`
7-
# of .rubocop.yml are equal.
6+
# Checks that `required_ruby_version` of gemspec is specified and
7+
# equal to `TargetRubyVersion` of .rubocop.yml.
88
# Thereby, RuboCop to perform static analysis working on the version
99
# required by gemspec.
1010
#
@@ -13,6 +13,11 @@ module Gemspec
1313
#
1414
# # bad
1515
# Gem::Specification.new do |spec|
16+
# # no `required_ruby_version` specified
17+
# end
18+
#
19+
# # bad
20+
# Gem::Specification.new do |spec|
1621
# spec.required_ruby_version = '>= 2.4.0'
1722
# end
1823
#
@@ -41,28 +46,44 @@ module Gemspec
4146
# spec.required_ruby_version = '~> 2.5'
4247
# end
4348
class RequiredRubyVersion < Cop
44-
MSG = '`required_ruby_version` (%<required_ruby_version>s, ' \
45-
'declared in %<gemspec_filename>s) and `TargetRubyVersion` ' \
46-
'(%<target_ruby_version>s, which may be specified in ' \
47-
'.rubocop.yml) should be equal.'
49+
include RangeHelp
50+
51+
NOT_EQUAL_MSG = '`required_ruby_version` (%<required_ruby_version>s, ' \
52+
'declared in %<gemspec_filename>s) and `TargetRubyVersion` ' \
53+
'(%<target_ruby_version>s, which may be specified in ' \
54+
'.rubocop.yml) should be equal.'
55+
MISSING_MSG = '`required_ruby_version` should be specified.'
4856

4957
def_node_search :required_ruby_version, <<~PATTERN
50-
(send _ :required_ruby_version= ${(str _) (array (str _))})
58+
(send _ :required_ruby_version= $_)
5159
PATTERN
5260

61+
def_node_matcher :string_version?, <<~PATTERN
62+
{(str _) (array (str _))}
63+
PATTERN
64+
65+
# rubocop:disable Metrics/AbcSize
5366
def investigate(processed_source)
54-
required_ruby_version(processed_source.ast) do |version|
67+
version = required_ruby_version(processed_source.ast).first
68+
69+
if version
70+
return unless string_version?(version)
71+
5572
ruby_version = extract_ruby_version(version)
5673

5774
return if ruby_version == target_ruby_version.to_s
5875

5976
add_offense(
6077
processed_source.ast,
6178
location: version.loc.expression,
62-
message: message(ruby_version, target_ruby_version)
79+
message: not_equal_message(ruby_version, target_ruby_version)
6380
)
81+
else
82+
range = source_range(processed_source.buffer, 1, 0)
83+
add_offense(nil, location: range, message: MISSING_MSG)
6484
end
6585
end
86+
# rubocop:enable Metrics/AbcSize
6687

6788
private
6889

@@ -76,9 +97,9 @@ def extract_ruby_version(required_ruby_version)
7697
required_ruby_version.str_content.scan(/\d/).first(2).join('.')
7798
end
7899

79-
def message(required_ruby_version, target_ruby_version)
100+
def not_equal_message(required_ruby_version, target_ruby_version)
80101
format(
81-
MSG,
102+
NOT_EQUAL_MSG,
82103
required_ruby_version: required_ruby_version,
83104
gemspec_filename: File.basename(processed_source.file_path),
84105
target_ruby_version: target_ruby_version

spec/rubocop/cop/gemspec/required_ruby_version_spec.rb

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,4 +128,12 @@
128128
RUBY
129129
end
130130
end
131+
132+
it 'registers an offense when `required_ruby_version` is not specified' do
133+
expect_offense(<<~RUBY, '/path/to/foo.gemspec')
134+
Gem::Specification.new do |spec|
135+
^ `required_ruby_version` should be specified.
136+
end
137+
RUBY
138+
end
131139
end

0 commit comments

Comments
 (0)