rubocop 1.22.1 → 1.23.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +1 -1
- data/config/default.yml +43 -7
- data/lib/rubocop/cop/bundler/gem_comment.rb +3 -3
- data/lib/rubocop/cop/gemspec/date_assignment.rb +2 -10
- data/lib/rubocop/cop/gemspec/duplicated_assignment.rb +1 -10
- data/lib/rubocop/cop/gemspec/require_mfa.rb +146 -0
- data/lib/rubocop/cop/gemspec/required_ruby_version.rb +30 -23
- data/lib/rubocop/cop/gemspec/ruby_version_globals_usage.rb +3 -10
- data/lib/rubocop/cop/generator.rb +1 -1
- data/lib/rubocop/cop/internal_affairs/location_line_equality_comparison.rb +60 -0
- data/lib/rubocop/cop/internal_affairs.rb +1 -0
- data/lib/rubocop/cop/layout/assignment_indentation.rb +1 -1
- data/lib/rubocop/cop/layout/block_alignment.rb +3 -3
- data/lib/rubocop/cop/layout/dot_position.rb +9 -7
- data/lib/rubocop/cop/layout/empty_comment.rb +1 -1
- data/lib/rubocop/cop/layout/empty_line_between_defs.rb +22 -1
- data/lib/rubocop/cop/layout/empty_lines_around_exception_handling_keywords.rb +7 -4
- data/lib/rubocop/cop/layout/end_alignment.rb +1 -2
- data/lib/rubocop/cop/layout/first_array_element_indentation.rb +1 -1
- data/lib/rubocop/cop/layout/first_hash_element_indentation.rb +1 -1
- data/lib/rubocop/cop/layout/first_parameter_indentation.rb +1 -1
- data/lib/rubocop/cop/layout/hash_alignment.rb +1 -1
- data/lib/rubocop/cop/layout/heredoc_argument_closing_parenthesis.rb +1 -1
- data/lib/rubocop/cop/layout/indentation_width.rb +1 -1
- data/lib/rubocop/cop/layout/line_length.rb +1 -1
- data/lib/rubocop/cop/layout/multiline_assignment_layout.rb +1 -1
- data/lib/rubocop/cop/layout/multiline_block_layout.rb +2 -2
- data/lib/rubocop/cop/layout/multiline_method_call_indentation.rb +1 -1
- data/lib/rubocop/cop/layout/rescue_ensure_alignment.rb +1 -1
- data/lib/rubocop/cop/layout/space_before_comment.rb +1 -1
- data/lib/rubocop/cop/layout/space_in_lambda_literal.rb +11 -5
- data/lib/rubocop/cop/layout/space_inside_parens.rb +0 -4
- data/lib/rubocop/cop/lint/ambiguous_range.rb +3 -3
- data/lib/rubocop/cop/lint/deprecated_constants.rb +3 -2
- data/lib/rubocop/cop/lint/else_layout.rb +1 -1
- data/lib/rubocop/cop/lint/number_conversion.rb +5 -2
- data/lib/rubocop/cop/lint/useless_ruby2_keywords.rb +117 -0
- data/lib/rubocop/cop/metrics/parameter_lists.rb +5 -2
- data/lib/rubocop/cop/mixin/end_keyword_alignment.rb +1 -2
- data/lib/rubocop/cop/mixin/gemspec_help.rb +30 -0
- data/lib/rubocop/cop/mixin/hash_transform_method.rb +3 -3
- data/lib/rubocop/cop/mixin/multiline_element_indentation.rb +1 -1
- data/lib/rubocop/cop/mixin/multiline_literal_brace_layout.rb +1 -1
- data/lib/rubocop/cop/mixin/space_after_punctuation.rb +1 -1
- data/lib/rubocop/cop/mixin/space_before_punctuation.rb +1 -1
- data/lib/rubocop/cop/mixin/statement_modifier.rb +1 -1
- data/lib/rubocop/cop/mixin/string_literals_help.rb +1 -5
- data/lib/rubocop/cop/mixin/trailing_body.rb +1 -1
- data/lib/rubocop/cop/naming/file_name.rb +37 -4
- data/lib/rubocop/cop/security/json_load.rb +1 -1
- data/lib/rubocop/cop/style/commented_keyword.rb +5 -3
- data/lib/rubocop/cop/style/documentation.rb +1 -1
- data/lib/rubocop/cop/style/empty_method.rb +1 -1
- data/lib/rubocop/cop/style/format_string_token.rb +2 -1
- data/lib/rubocop/cop/style/line_end_concatenation.rb +1 -1
- data/lib/rubocop/cop/style/multiline_in_pattern_then.rb +1 -1
- data/lib/rubocop/cop/style/multiline_when_then.rb +1 -1
- data/lib/rubocop/cop/style/open_struct_use.rb +69 -0
- data/lib/rubocop/cop/style/parentheses_around_condition.rb +12 -2
- data/lib/rubocop/cop/style/quoted_symbols.rb +11 -1
- data/lib/rubocop/cop/style/select_by_regexp.rb +9 -3
- data/lib/rubocop/cop/util.rb +11 -1
- data/lib/rubocop/formatter/html_formatter.rb +5 -2
- data/lib/rubocop/formatter/json_formatter.rb +4 -1
- data/lib/rubocop/remote_config.rb +1 -1
- data/lib/rubocop/rspec/parallel_formatter.rb +90 -0
- data/lib/rubocop/rspec/support.rb +1 -0
- data/lib/rubocop/target_finder.rb +1 -1
- data/lib/rubocop/version.rb +1 -1
- data/lib/rubocop/yaml_duplication_checker.rb +1 -1
- data/lib/rubocop.rb +4 -0
- metadata +14 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: cf11fe2d8f8be8879d6afc63d6f3be50b970c7910c83f1d22847d1fc9654d4aa
|
4
|
+
data.tar.gz: fd4c7ef3838a286efe3d1729672cc7a0e72f47cfb4c8d815699d53d2a974a372
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4014183525b58378a0e628ae5136d17c148a41c6c25dd51eddc810ca08fbd89d652f6c715b58eef149005af1145469936416864869b6e63a4c9e521627ab1cb4
|
7
|
+
data.tar.gz: 6e0e2a9a9d6fae829b73bd49814965a28d447207aaf7d1dda073f34130343557df965c77cc998d6ddb0d59eca09f1307d6ca56cbd3fcade575ca52950d1a56d3
|
data/README.md
CHANGED
@@ -54,7 +54,7 @@ To prevent an unwanted RuboCop update you might want to use a conservative versi
|
|
54
54
|
in your `Gemfile`:
|
55
55
|
|
56
56
|
```rb
|
57
|
-
gem 'rubocop', '~> 1.
|
57
|
+
gem 'rubocop', '~> 1.23', require: false
|
58
58
|
```
|
59
59
|
|
60
60
|
See [our versioning policy](https://docs.rubocop.org/rubocop/versioning.html) for further details.
|
data/config/default.yml
CHANGED
@@ -150,6 +150,7 @@ AllCops:
|
|
150
150
|
rubocop-minitest: [minitest]
|
151
151
|
rubocop-sequel: [sequel]
|
152
152
|
rubocop-rake: [rake]
|
153
|
+
rubocop-graphql: [graphql]
|
153
154
|
|
154
155
|
#################### Bundler ###############################
|
155
156
|
|
@@ -258,11 +259,20 @@ Gemspec/OrderedDependencies:
|
|
258
259
|
Include:
|
259
260
|
- '**/*.gemspec'
|
260
261
|
|
262
|
+
Gemspec/RequireMFA:
|
263
|
+
Description: 'Checks that the gemspec has metadata to require MFA from RubyGems.'
|
264
|
+
Enabled: pending
|
265
|
+
VersionAdded: '1.23'
|
266
|
+
Reference:
|
267
|
+
- https://guides.rubygems.org/mfa-requirement-opt-in/
|
268
|
+
Include:
|
269
|
+
- '**/*.gemspec'
|
270
|
+
|
261
271
|
Gemspec/RequiredRubyVersion:
|
262
272
|
Description: 'Checks that `required_ruby_version` of gemspec is specified and equal to `TargetRubyVersion` of .rubocop.yml.'
|
263
273
|
Enabled: true
|
264
274
|
VersionAdded: '0.52'
|
265
|
-
VersionChanged: '
|
275
|
+
VersionChanged: '1.22'
|
266
276
|
Include:
|
267
277
|
- '**/*.gemspec'
|
268
278
|
|
@@ -511,13 +521,13 @@ Layout/EmptyLineBetweenDefs:
|
|
511
521
|
StyleGuide: '#empty-lines-between-methods'
|
512
522
|
Enabled: true
|
513
523
|
VersionAdded: '0.49'
|
514
|
-
VersionChanged: '1.
|
524
|
+
VersionChanged: '1.23'
|
515
525
|
EmptyLineBetweenMethodDefs: true
|
516
526
|
EmptyLineBetweenClassDefs: true
|
517
527
|
EmptyLineBetweenModuleDefs: true
|
518
|
-
#
|
519
|
-
# need an empty line between them.
|
520
|
-
AllowAdjacentOneLineDefs:
|
528
|
+
# `AllowAdjacentOneLineDefs` means that single line method definitions don't
|
529
|
+
# need an empty line between them. `true` by default.
|
530
|
+
AllowAdjacentOneLineDefs: true
|
521
531
|
# Can be array to specify minimum and maximum number of empty lines, e.g. [1, 2]
|
522
532
|
NumberOfEmptyLines: 1
|
523
533
|
|
@@ -1568,6 +1578,7 @@ Lint/DeprecatedConstants:
|
|
1568
1578
|
Description: 'Checks for deprecated constants.'
|
1569
1579
|
Enabled: pending
|
1570
1580
|
VersionAdded: '1.8'
|
1581
|
+
VersionChanged: '1.22'
|
1571
1582
|
# You can configure deprecated constants.
|
1572
1583
|
# If there is an alternative method, you can set alternative value as `Alternative`.
|
1573
1584
|
# And you can set the deprecated version as `DeprecatedVersion`.
|
@@ -1588,6 +1599,9 @@ Lint/DeprecatedConstants:
|
|
1588
1599
|
'FALSE':
|
1589
1600
|
Alternative: 'false'
|
1590
1601
|
DeprecatedVersion: '2.4'
|
1602
|
+
'Net::HTTPServerException':
|
1603
|
+
Alternative: 'Net::HTTPClientException'
|
1604
|
+
DeprecatedVersion: '2.6'
|
1591
1605
|
'Random::DEFAULT':
|
1592
1606
|
Alternative: 'Random.new'
|
1593
1607
|
DeprecatedVersion: '3.0'
|
@@ -2304,6 +2318,11 @@ Lint/UselessMethodDefinition:
|
|
2304
2318
|
Safe: false
|
2305
2319
|
AllowComments: true
|
2306
2320
|
|
2321
|
+
Lint/UselessRuby2Keywords:
|
2322
|
+
Description: 'Finds unnecessary uses of `ruby2_keywords`.'
|
2323
|
+
Enabled: pending
|
2324
|
+
VersionAdded: '1.23'
|
2325
|
+
|
2307
2326
|
Lint/UselessSetterCall:
|
2308
2327
|
Description: 'Checks for useless setter call to a local variable.'
|
2309
2328
|
Enabled: true
|
@@ -2497,6 +2516,7 @@ Naming/FileName:
|
|
2497
2516
|
StyleGuide: '#snake-case-files'
|
2498
2517
|
Enabled: true
|
2499
2518
|
VersionAdded: '0.50'
|
2519
|
+
VersionChanged: '1.23'
|
2500
2520
|
# Camel case file names listed in `AllCops:Include` and all file names listed
|
2501
2521
|
# in `AllCops:Exclude` are excluded by default. Add extra excludes here.
|
2502
2522
|
Exclude: []
|
@@ -2509,6 +2529,13 @@ Naming/FileName:
|
|
2509
2529
|
# whether each source file's class or module name matches the file name --
|
2510
2530
|
# not whether the nested module hierarchy matches the subdirectory path.
|
2511
2531
|
CheckDefinitionPathHierarchy: true
|
2532
|
+
# paths that are considered root directories, for example "lib" in most ruby projects
|
2533
|
+
# or "app/models" in rails projects
|
2534
|
+
CheckDefinitionPathHierarchyRoots:
|
2535
|
+
- lib
|
2536
|
+
- spec
|
2537
|
+
- test
|
2538
|
+
- src
|
2512
2539
|
# If non-`nil`, expect all source file names to match the following regex.
|
2513
2540
|
# Only the file name itself is matched, not the entire file path.
|
2514
2541
|
# Use anchors as necessary if you want to match the entire name rather than
|
@@ -2754,10 +2781,9 @@ Security/JSONLoad:
|
|
2754
2781
|
Reference: 'https://ruby-doc.org/stdlib-2.7.0/libdoc/json/rdoc/JSON.html#method-i-load'
|
2755
2782
|
Enabled: true
|
2756
2783
|
VersionAdded: '0.43'
|
2757
|
-
VersionChanged: '
|
2784
|
+
VersionChanged: '1.22'
|
2758
2785
|
# Autocorrect here will change to a method that may cause crashes depending
|
2759
2786
|
# on the value of the argument.
|
2760
|
-
AutoCorrect: false
|
2761
2787
|
SafeAutoCorrect: false
|
2762
2788
|
|
2763
2789
|
Security/MarshalLoad:
|
@@ -4213,6 +4239,16 @@ Style/OneLineConditional:
|
|
4213
4239
|
VersionAdded: '0.9'
|
4214
4240
|
VersionChanged: '0.90'
|
4215
4241
|
|
4242
|
+
Style/OpenStructUse:
|
4243
|
+
Description: >-
|
4244
|
+
Avoid using OpenStruct. As of Ruby 3.0, use is officially discouraged due to performance,
|
4245
|
+
version compatibility, and potential security issues.
|
4246
|
+
Reference:
|
4247
|
+
- https://docs.ruby-lang.org/en/3.0.0/OpenStruct.html#class-OpenStruct-label-Caveats
|
4248
|
+
|
4249
|
+
Enabled: pending
|
4250
|
+
VersionAdded: '1.23'
|
4251
|
+
|
4216
4252
|
Style/OptionHash:
|
4217
4253
|
Description: "Don't use option hashes when you can use keyword arguments."
|
4218
4254
|
Enabled: false
|
@@ -88,7 +88,7 @@ module RuboCop
|
|
88
88
|
CHECKED_OPTIONS_CONFIG = 'OnlyFor'
|
89
89
|
VERSION_SPECIFIERS_OPTION = 'version_specifiers'
|
90
90
|
RESTRICTIVE_VERSION_SPECIFIERS_OPTION = 'restrictive_version_specifiers'
|
91
|
-
RESTRICTIVE_VERSION_PATTERN =
|
91
|
+
RESTRICTIVE_VERSION_PATTERN = /\A\s*(?:<|~>|\d|=)/.freeze
|
92
92
|
RESTRICT_ON_SEND = %i[gem].freeze
|
93
93
|
|
94
94
|
def on_send(node)
|
@@ -152,8 +152,8 @@ module RuboCop
|
|
152
152
|
def restrictive_version_specified_gem?(node)
|
153
153
|
return unless version_specified_gem?(node)
|
154
154
|
|
155
|
-
node.arguments
|
156
|
-
.any? { |arg| arg&.str_type? && RESTRICTIVE_VERSION_PATTERN.match?(arg.
|
155
|
+
node.arguments[1..-1]
|
156
|
+
.any? { |arg| arg&.str_type? && RESTRICTIVE_VERSION_PATTERN.match?(arg.value) }
|
157
157
|
end
|
158
158
|
|
159
159
|
def contains_checked_options?(node)
|
@@ -21,21 +21,13 @@ module RuboCop
|
|
21
21
|
#
|
22
22
|
class DateAssignment < Base
|
23
23
|
include RangeHelp
|
24
|
+
include GemspecHelp
|
24
25
|
extend AutoCorrector
|
25
26
|
|
26
27
|
MSG = 'Do not use `date =` in gemspec, it is set automatically when the gem is packaged.'
|
27
28
|
|
28
|
-
# @!method gem_specification(node)
|
29
|
-
def_node_matcher :gem_specification, <<~PATTERN
|
30
|
-
(block
|
31
|
-
(send
|
32
|
-
(const
|
33
|
-
(const {cbase nil?} :Gem) :Specification) :new)
|
34
|
-
...)
|
35
|
-
PATTERN
|
36
|
-
|
37
29
|
def on_block(block_node)
|
38
|
-
return unless gem_specification(block_node)
|
30
|
+
return unless gem_specification?(block_node)
|
39
31
|
|
40
32
|
block_parameter = block_node.arguments.first.source
|
41
33
|
|
@@ -36,20 +36,11 @@ module RuboCop
|
|
36
36
|
# end
|
37
37
|
class DuplicatedAssignment < Base
|
38
38
|
include RangeHelp
|
39
|
+
include GemspecHelp
|
39
40
|
|
40
41
|
MSG = '`%<assignment>s` method calls already given on line '\
|
41
42
|
'%<line_of_first_occurrence>d of the gemspec.'
|
42
43
|
|
43
|
-
# @!method gem_specification(node)
|
44
|
-
def_node_search :gem_specification, <<~PATTERN
|
45
|
-
(block
|
46
|
-
(send
|
47
|
-
(const
|
48
|
-
(const {cbase nil?} :Gem) :Specification) :new)
|
49
|
-
(args
|
50
|
-
(arg $_)) ...)
|
51
|
-
PATTERN
|
52
|
-
|
53
44
|
# @!method assignment_method_declarations(node)
|
54
45
|
def_node_search :assignment_method_declarations, <<~PATTERN
|
55
46
|
(send
|
@@ -0,0 +1,146 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Gemspec
|
6
|
+
# Requires a gemspec to have `rubygems_mfa_required` metadata set.
|
7
|
+
#
|
8
|
+
# This setting tells RubyGems that MFA is required for accounts to
|
9
|
+
# be able perform any of these privileged operations:
|
10
|
+
#
|
11
|
+
# * gem push
|
12
|
+
# * gem yank
|
13
|
+
# * gem owner --add/remove
|
14
|
+
# * adding or removing owners using gem ownership page
|
15
|
+
#
|
16
|
+
# This helps make your gem more secure, as users can be more
|
17
|
+
# confident that gem updates were pushed by maintainers.
|
18
|
+
#
|
19
|
+
# @example
|
20
|
+
#
|
21
|
+
# # bad
|
22
|
+
# Gem::Specification.new do |spec|
|
23
|
+
# # no `rubygems_mfa_required` metadata specified
|
24
|
+
# end
|
25
|
+
#
|
26
|
+
# # good
|
27
|
+
# Gem::Specification.new do |spec|
|
28
|
+
# spec.metadata = {
|
29
|
+
# 'rubygems_mfa_required' => 'true'
|
30
|
+
# }
|
31
|
+
# end
|
32
|
+
#
|
33
|
+
# # good
|
34
|
+
# Gem::Specification.new do |spec|
|
35
|
+
# spec.metadata['rubygems_mfa_required'] = 'true'
|
36
|
+
# end
|
37
|
+
#
|
38
|
+
# # bad
|
39
|
+
# Gem::Specification.new do |spec|
|
40
|
+
# spec.metadata = {
|
41
|
+
# 'rubygems_mfa_required' => 'false'
|
42
|
+
# }
|
43
|
+
# end
|
44
|
+
#
|
45
|
+
# # good
|
46
|
+
# Gem::Specification.new do |spec|
|
47
|
+
# spec.metadata = {
|
48
|
+
# 'rubygems_mfa_required' => 'true'
|
49
|
+
# }
|
50
|
+
# end
|
51
|
+
#
|
52
|
+
# # bad
|
53
|
+
# Gem::Specification.new do |spec|
|
54
|
+
# spec.metadata['rubygems_mfa_required'] = 'false'
|
55
|
+
# end
|
56
|
+
#
|
57
|
+
# # good
|
58
|
+
# Gem::Specification.new do |spec|
|
59
|
+
# spec.metadata['rubygems_mfa_required'] = 'true'
|
60
|
+
# end
|
61
|
+
#
|
62
|
+
class RequireMFA < Base
|
63
|
+
include GemspecHelp
|
64
|
+
extend AutoCorrector
|
65
|
+
|
66
|
+
MSG = "`metadata['rubygems_mfa_required']` must be set to `'true'`."
|
67
|
+
|
68
|
+
# @!method metadata(node)
|
69
|
+
def_node_matcher :metadata, <<~PATTERN
|
70
|
+
`{
|
71
|
+
(send _ :metadata= $_)
|
72
|
+
(send (send _ :metadata) :[]= (str "rubygems_mfa_required") $_)
|
73
|
+
}
|
74
|
+
PATTERN
|
75
|
+
|
76
|
+
# @!method rubygems_mfa_required(node)
|
77
|
+
def_node_search :rubygems_mfa_required, <<~PATTERN
|
78
|
+
(pair (str "rubygems_mfa_required") $_)
|
79
|
+
PATTERN
|
80
|
+
|
81
|
+
# @!method true_string?(node)
|
82
|
+
def_node_matcher :true_string?, <<~PATTERN
|
83
|
+
(str "true")
|
84
|
+
PATTERN
|
85
|
+
|
86
|
+
def on_block(node) # rubocop:disable Metrics/MethodLength
|
87
|
+
gem_specification(node) do |block_var|
|
88
|
+
metadata_value = metadata(node)
|
89
|
+
mfa_value = mfa_value(metadata_value)
|
90
|
+
|
91
|
+
if mfa_value
|
92
|
+
unless true_string?(mfa_value)
|
93
|
+
add_offense(mfa_value) do |corrector|
|
94
|
+
change_value(corrector, mfa_value)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
else
|
98
|
+
add_offense(node) do |corrector|
|
99
|
+
autocorrect(corrector, node, block_var, metadata_value)
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
private
|
106
|
+
|
107
|
+
def mfa_value(metadata_value)
|
108
|
+
return unless metadata_value
|
109
|
+
return metadata_value if metadata_value.str_type?
|
110
|
+
|
111
|
+
rubygems_mfa_required(metadata_value).first
|
112
|
+
end
|
113
|
+
|
114
|
+
def autocorrect(corrector, node, block_var, metadata)
|
115
|
+
if metadata
|
116
|
+
return unless metadata.hash_type?
|
117
|
+
|
118
|
+
correct_metadata(corrector, metadata)
|
119
|
+
else
|
120
|
+
correct_missing_metadata(corrector, node, block_var)
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
def correct_metadata(corrector, metadata)
|
125
|
+
if metadata.pairs.any?
|
126
|
+
corrector.insert_after(metadata.pairs.last, ",\n'rubygems_mfa_required' => 'true'")
|
127
|
+
else
|
128
|
+
corrector.insert_before(metadata.loc.end, "'rubygems_mfa_required' => 'true'")
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
def correct_missing_metadata(corrector, node, block_var)
|
133
|
+
corrector.insert_before(node.loc.end, <<~RUBY)
|
134
|
+
#{block_var}.metadata = {
|
135
|
+
'rubygems_mfa_required' => 'true'
|
136
|
+
}
|
137
|
+
RUBY
|
138
|
+
end
|
139
|
+
|
140
|
+
def change_value(corrector, value)
|
141
|
+
corrector.replace(value, "'true'")
|
142
|
+
end
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
@@ -3,10 +3,11 @@
|
|
3
3
|
module RuboCop
|
4
4
|
module Cop
|
5
5
|
module Gemspec
|
6
|
-
# Checks that `required_ruby_version`
|
7
|
-
#
|
8
|
-
#
|
9
|
-
#
|
6
|
+
# Checks that `required_ruby_version` in a gemspec file is set to a valid
|
7
|
+
# value (non-blank) and matches `TargetRubyVersion` as set in RuboCop's
|
8
|
+
# configuration for the gem.
|
9
|
+
#
|
10
|
+
# This ensures that RuboCop is using the same Ruby version as the gem.
|
10
11
|
#
|
11
12
|
# @example
|
12
13
|
# # When `TargetRubyVersion` of .rubocop.yml is `2.5`.
|
@@ -26,6 +27,11 @@ module RuboCop
|
|
26
27
|
# spec.required_ruby_version = '>= 2.6.0'
|
27
28
|
# end
|
28
29
|
#
|
30
|
+
# # bad
|
31
|
+
# Gem::Specification.new do |spec|
|
32
|
+
# spec.required_ruby_version = ''
|
33
|
+
# end
|
34
|
+
#
|
29
35
|
# # good
|
30
36
|
# Gem::Specification.new do |spec|
|
31
37
|
# spec.required_ruby_version = '>= 2.5.0'
|
@@ -49,15 +55,15 @@ module RuboCop
|
|
49
55
|
class RequiredRubyVersion < Base
|
50
56
|
include RangeHelp
|
51
57
|
|
52
|
-
|
53
|
-
|
58
|
+
RESTRICT_ON_SEND = %i[required_ruby_version=].freeze
|
59
|
+
NOT_EQUAL_MSG = '`required_ruby_version` and `TargetRubyVersion` ' \
|
54
60
|
'(%<target_ruby_version>s, which may be specified in ' \
|
55
61
|
'.rubocop.yml) should be equal.'
|
56
62
|
MISSING_MSG = '`required_ruby_version` should be specified.'
|
57
63
|
|
58
|
-
# @!method required_ruby_version(node)
|
59
|
-
def_node_search :required_ruby_version
|
60
|
-
(send _ :required_ruby_version=
|
64
|
+
# @!method required_ruby_version?(node)
|
65
|
+
def_node_search :required_ruby_version?, <<~PATTERN
|
66
|
+
(send _ :required_ruby_version= _)
|
61
67
|
PATTERN
|
62
68
|
|
63
69
|
# @!method defined_ruby_version(node)
|
@@ -66,27 +72,28 @@ module RuboCop
|
|
66
72
|
(send (const (const nil? :Gem) :Requirement) :new $(str _))}
|
67
73
|
PATTERN
|
68
74
|
|
69
|
-
# rubocop:disable Metrics/AbcSize
|
70
75
|
def on_new_investigation
|
71
|
-
|
76
|
+
add_global_offense(MISSING_MSG) unless required_ruby_version?(processed_source.ast)
|
77
|
+
end
|
72
78
|
|
73
|
-
|
74
|
-
|
75
|
-
|
79
|
+
def on_send(node)
|
80
|
+
version_def = node.first_argument
|
81
|
+
return if dynamic_version?(version_def)
|
76
82
|
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
else
|
82
|
-
range = source_range(processed_source.buffer, 1, 0)
|
83
|
-
add_offense(range, message: MISSING_MSG)
|
84
|
-
end
|
83
|
+
ruby_version = extract_ruby_version(defined_ruby_version(version_def))
|
84
|
+
return if ruby_version == target_ruby_version.to_s
|
85
|
+
|
86
|
+
add_offense(version_def, message: not_equal_message(ruby_version, target_ruby_version))
|
85
87
|
end
|
86
|
-
# rubocop:enable Metrics/AbcSize
|
87
88
|
|
88
89
|
private
|
89
90
|
|
91
|
+
def dynamic_version?(node)
|
92
|
+
(node.send_type? && !node.receiver) ||
|
93
|
+
node.variable? ||
|
94
|
+
node.each_descendant(:send, *RuboCop::AST::Node::VARIABLES).any?
|
95
|
+
end
|
96
|
+
|
90
97
|
def extract_ruby_version(required_ruby_version)
|
91
98
|
return unless required_ruby_version
|
92
99
|
|
@@ -26,20 +26,13 @@ module RuboCop
|
|
26
26
|
# end
|
27
27
|
#
|
28
28
|
class RubyVersionGlobalsUsage < Base
|
29
|
+
include GemspecHelp
|
30
|
+
|
29
31
|
MSG = 'Do not use `RUBY_VERSION` in gemspec file.'
|
30
32
|
|
31
33
|
# @!method ruby_version?(node)
|
32
34
|
def_node_matcher :ruby_version?, '(const {cbase nil?} :RUBY_VERSION)'
|
33
35
|
|
34
|
-
# @!method gem_specification?(node)
|
35
|
-
def_node_search :gem_specification?, <<~PATTERN
|
36
|
-
(block
|
37
|
-
(send
|
38
|
-
(const
|
39
|
-
(const {cbase nil?} :Gem) :Specification) :new)
|
40
|
-
...)
|
41
|
-
PATTERN
|
42
|
-
|
43
36
|
def on_const(node)
|
44
37
|
return unless gem_spec_with_ruby_version?(node)
|
45
38
|
|
@@ -49,7 +42,7 @@ module RuboCop
|
|
49
42
|
private
|
50
43
|
|
51
44
|
def gem_spec_with_ruby_version?(node)
|
52
|
-
gem_specification
|
45
|
+
gem_specification(processed_source.ast) && ruby_version?(node)
|
53
46
|
end
|
54
47
|
end
|
55
48
|
end
|
@@ -150,7 +150,7 @@ module RuboCop
|
|
150
150
|
1. Modify the description of #{badge} in config/default.yml
|
151
151
|
2. Implement your new cop in the generated file!
|
152
152
|
3. Commit your new cop with a message such as
|
153
|
-
e.g. "Add new `#{badge}` cop
|
153
|
+
e.g. "Add new `#{badge}` cop"
|
154
154
|
4. Run `bundle exec rake changelog:new` to generate a changelog entry
|
155
155
|
for your new cop.
|
156
156
|
TODO
|
@@ -0,0 +1,60 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module InternalAffairs
|
6
|
+
# This cop enforces the use of `same_line?` instead of location line comparison for equality.
|
7
|
+
#
|
8
|
+
# @example
|
9
|
+
# # bad
|
10
|
+
# node.loc.line == node.parent.loc.line
|
11
|
+
#
|
12
|
+
# # bad
|
13
|
+
# node.loc.first_line == node.parent.loc.first_line
|
14
|
+
#
|
15
|
+
# # good
|
16
|
+
# same_line?(node, node.parent)
|
17
|
+
#
|
18
|
+
class LocationLineEqualityComparison < Base
|
19
|
+
extend AutoCorrector
|
20
|
+
|
21
|
+
MSG = 'Use `%<preferred>s`.'
|
22
|
+
|
23
|
+
# @!method line_send(node)
|
24
|
+
def_node_matcher :line_send, <<~PATTERN
|
25
|
+
{
|
26
|
+
(send (send _ {:loc :source_range}) {:line :first_line})
|
27
|
+
(send _ :first_line)
|
28
|
+
}
|
29
|
+
PATTERN
|
30
|
+
|
31
|
+
# @!method location_line_equality_comparison?(node)
|
32
|
+
def_node_matcher :location_line_equality_comparison?, <<~PATTERN
|
33
|
+
(send #line_send :== #line_send)
|
34
|
+
PATTERN
|
35
|
+
|
36
|
+
def on_send(node)
|
37
|
+
return unless location_line_equality_comparison?(node)
|
38
|
+
|
39
|
+
lhs, _op, rhs = *node
|
40
|
+
|
41
|
+
lhs_receiver = extract_receiver(lhs)
|
42
|
+
rhs_receiver = extract_receiver(rhs)
|
43
|
+
preferred = "same_line?(#{lhs_receiver}, #{rhs_receiver})"
|
44
|
+
|
45
|
+
add_offense(node, message: format(MSG, preferred: preferred)) do |corrector|
|
46
|
+
corrector.replace(node, preferred)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
private
|
51
|
+
|
52
|
+
def extract_receiver(node)
|
53
|
+
receiver = node.receiver
|
54
|
+
receiver = receiver.receiver if receiver.method?(:loc) || receiver.method?(:source_range)
|
55
|
+
receiver.source
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -3,6 +3,7 @@
|
|
3
3
|
require_relative 'internal_affairs/empty_line_between_expect_offense_and_correction'
|
4
4
|
require_relative 'internal_affairs/example_description'
|
5
5
|
require_relative 'internal_affairs/inherit_deprecated_cop_class'
|
6
|
+
require_relative 'internal_affairs/location_line_equality_comparison'
|
6
7
|
require_relative 'internal_affairs/method_name_equal'
|
7
8
|
require_relative 'internal_affairs/node_destructuring'
|
8
9
|
require_relative 'internal_affairs/node_matcher_directive'
|
@@ -33,7 +33,7 @@ module RuboCop
|
|
33
33
|
def check_assignment(node, rhs)
|
34
34
|
return unless rhs
|
35
35
|
return unless node.loc.operator
|
36
|
-
return if node.loc.operator
|
36
|
+
return if same_line?(node.loc.operator, rhs)
|
37
37
|
|
38
38
|
base = display_column(leftmost_multiple_assignment(node).source_range)
|
39
39
|
check_alignment([rhs], base + configured_indentation_width)
|
@@ -101,11 +101,11 @@ module RuboCop
|
|
101
101
|
def block_end_align_target(node)
|
102
102
|
lineage = [node, *node.ancestors]
|
103
103
|
|
104
|
-
|
105
|
-
|
104
|
+
lineage.each_cons(2) do |current, parent|
|
105
|
+
return current if end_align_target?(current, parent)
|
106
106
|
end
|
107
107
|
|
108
|
-
|
108
|
+
lineage.last
|
109
109
|
end
|
110
110
|
|
111
111
|
def end_align_target?(node, parent)
|
@@ -68,18 +68,14 @@ module RuboCop
|
|
68
68
|
end
|
69
69
|
|
70
70
|
def proper_dot_position?(node)
|
71
|
-
|
71
|
+
selector_range = selector_range(node)
|
72
72
|
|
73
|
-
|
74
|
-
# then there is nothing to do
|
75
|
-
return true if heredoc?(node.receiver) && node.receiver.loc.first_line == selector_line
|
73
|
+
return true if same_line?(selector_range, end_range(node.receiver))
|
76
74
|
|
75
|
+
selector_line = selector_range.line
|
77
76
|
receiver_line = receiver_end_line(node.receiver)
|
78
77
|
dot_line = node.loc.dot.line
|
79
78
|
|
80
|
-
# receiver and selector are on the same line
|
81
|
-
return true if selector_line == receiver_line
|
82
|
-
|
83
79
|
# don't register an offense if there is a line comment between the
|
84
80
|
# dot and the selector otherwise, we might break the code while
|
85
81
|
# "correcting" it (even if there is just an extra blank line, treat
|
@@ -123,7 +119,13 @@ module RuboCop
|
|
123
119
|
(node.str_type? || node.dstr_type?) && node.heredoc?
|
124
120
|
end
|
125
121
|
|
122
|
+
def end_range(node)
|
123
|
+
node.source_range.end
|
124
|
+
end
|
125
|
+
|
126
126
|
def selector_range(node)
|
127
|
+
return node unless node.call_type?
|
128
|
+
|
127
129
|
# l.(1) has no selector, so we use the opening parenthesis instead
|
128
130
|
node.loc.selector || node.loc.begin
|
129
131
|
end
|
@@ -96,7 +96,7 @@ module RuboCop
|
|
96
96
|
|
97
97
|
def autocorrect(corrector, node)
|
98
98
|
previous_token = previous_token(node)
|
99
|
-
range = if previous_token && node
|
99
|
+
range = if previous_token && same_line?(node, previous_token)
|
100
100
|
range_with_surrounding_space(range: node.loc.expression, newlines: false)
|
101
101
|
else
|
102
102
|
range_by_whole_lines(node.loc.expression, include_final_newline: true)
|
@@ -77,13 +77,34 @@ module RuboCop
|
|
77
77
|
# def b
|
78
78
|
# end
|
79
79
|
#
|
80
|
-
# @example AllowAdjacentOneLineDefs: true
|
80
|
+
# @example AllowAdjacentOneLineDefs: true (default)
|
81
81
|
#
|
82
82
|
# # good
|
83
83
|
# class ErrorA < BaseError; end
|
84
84
|
# class ErrorB < BaseError; end
|
85
85
|
# class ErrorC < BaseError; end
|
86
86
|
#
|
87
|
+
# # good
|
88
|
+
# class ErrorA < BaseError; end
|
89
|
+
#
|
90
|
+
# class ErrorB < BaseError; end
|
91
|
+
#
|
92
|
+
# class ErrorC < BaseError; end
|
93
|
+
#
|
94
|
+
# @example AllowAdjacentOneLineDefs: false
|
95
|
+
#
|
96
|
+
# # bad
|
97
|
+
# class ErrorA < BaseError; end
|
98
|
+
# class ErrorB < BaseError; end
|
99
|
+
# class ErrorC < BaseError; end
|
100
|
+
#
|
101
|
+
# # good
|
102
|
+
# class ErrorA < BaseError; end
|
103
|
+
#
|
104
|
+
# class ErrorB < BaseError; end
|
105
|
+
#
|
106
|
+
# class ErrorC < BaseError; end
|
107
|
+
#
|
87
108
|
class EmptyLineBetweenDefs < Base
|
88
109
|
include RangeHelp
|
89
110
|
extend AutoCorrector
|