rubocop 1.63.0 → 1.64.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 +18 -3
- data/lib/rubocop/cached_data.rb +11 -3
- data/lib/rubocop/cli/command/show_docs_url.rb +2 -2
- data/lib/rubocop/cli.rb +4 -0
- data/lib/rubocop/config.rb +2 -3
- data/lib/rubocop/cop/base.rb +9 -14
- data/lib/rubocop/cop/bundler/gem_version.rb +3 -5
- data/lib/rubocop/cop/documentation.rb +16 -6
- data/lib/rubocop/cop/gemspec/dependency_version.rb +3 -5
- data/lib/rubocop/cop/internal_affairs/example_description.rb +1 -1
- data/lib/rubocop/cop/layout/comment_indentation.rb +1 -1
- data/lib/rubocop/cop/layout/empty_comment.rb +3 -1
- data/lib/rubocop/cop/layout/first_array_element_indentation.rb +2 -0
- data/lib/rubocop/cop/lint/assignment_in_condition.rb +3 -1
- data/lib/rubocop/cop/lint/deprecated_class_methods.rb +1 -1
- data/lib/rubocop/cop/lint/empty_conditional_body.rb +1 -1
- data/lib/rubocop/cop/lint/mixed_case_range.rb +9 -4
- data/lib/rubocop/cop/lint/non_deterministic_require_order.rb +1 -1
- data/lib/rubocop/cop/lint/unreachable_code.rb +4 -2
- data/lib/rubocop/cop/lint/unreachable_loop.rb +8 -2
- data/lib/rubocop/cop/metrics/utils/code_length_calculator.rb +5 -5
- data/lib/rubocop/cop/mixin/hash_shorthand_syntax.rb +9 -2
- data/lib/rubocop/cop/security/compound_hash.rb +2 -2
- data/lib/rubocop/cop/style/access_modifier_declarations.rb +50 -0
- data/lib/rubocop/cop/style/arguments_forwarding.rb +5 -2
- data/lib/rubocop/cop/style/conditional_assignment.rb +1 -1
- data/lib/rubocop/cop/style/copyright.rb +10 -8
- data/lib/rubocop/cop/style/documentation_method.rb +20 -0
- data/lib/rubocop/cop/style/eval_with_location.rb +1 -1
- data/lib/rubocop/cop/style/hash_syntax.rb +18 -0
- data/lib/rubocop/cop/style/if_with_boolean_literal_branches.rb +5 -3
- data/lib/rubocop/cop/style/map_into_array.rb +3 -3
- data/lib/rubocop/cop/style/numeric_predicate.rb +10 -2
- data/lib/rubocop/cop/style/one_line_conditional.rb +1 -1
- data/lib/rubocop/cop/style/redundant_line_continuation.rb +3 -1
- data/lib/rubocop/cop/style/require_order.rb +1 -1
- data/lib/rubocop/cop/style/send.rb +4 -4
- data/lib/rubocop/cop/style/send_with_literal_method_name.rb +83 -0
- data/lib/rubocop/cop/style/special_global_vars.rb +1 -2
- data/lib/rubocop/cop/style/super_arguments.rb +137 -0
- data/lib/rubocop/cop/style/symbol_proc.rb +32 -5
- data/lib/rubocop/cop/style/top_level_method_definition.rb +1 -1
- data/lib/rubocop/formatter/disabled_config_formatter.rb +13 -9
- data/lib/rubocop/formatter/formatter_set.rb +7 -1
- data/lib/rubocop/lockfile.rb +25 -6
- data/lib/rubocop/lsp/routes.rb +9 -12
- data/lib/rubocop/lsp/server.rb +2 -0
- data/lib/rubocop/lsp.rb +9 -2
- data/lib/rubocop/options.rb +3 -3
- data/lib/rubocop/rake_task.rb +1 -1
- data/lib/rubocop/runner.rb +5 -4
- data/lib/rubocop/version.rb +4 -4
- data/lib/rubocop.rb +2 -0
- metadata +6 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b6dfe4310319b850aafab50e198152b52585d4e9da81d18b5a83dba9ecf73b62
|
4
|
+
data.tar.gz: a25d711605d517c0b1a4ed89eea3f5e65be8803a74f4c92d0b94d43ba9f7a4dd
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 10d92f3f642368e7126f5066662c4e725c5743847efc8fa17c123390534c47ab528ce6ec986ff93800f569046c86988b4ffaa84c1ae89f2c44365f7867fda6f4
|
7
|
+
data.tar.gz: e27fdf438f351200f01a33fba1059d678c37d4759eba3600b9c0f7d1f9329a344ff82e23518d38a4959c06069a1a2693447d2a5df8b202f1b11dad2ff012bae5
|
data/README.md
CHANGED
@@ -53,7 +53,7 @@ To prevent an unwanted RuboCop update you might want to use a conservative versi
|
|
53
53
|
in your `Gemfile`:
|
54
54
|
|
55
55
|
```rb
|
56
|
-
gem 'rubocop', '~> 1.
|
56
|
+
gem 'rubocop', '~> 1.64', require: false
|
57
57
|
```
|
58
58
|
|
59
59
|
See [our versioning policy](https://docs.rubocop.org/rubocop/versioning.html) for further details.
|
data/config/default.yml
CHANGED
@@ -156,7 +156,7 @@ AllCops:
|
|
156
156
|
# included.
|
157
157
|
SuggestExtensions:
|
158
158
|
rubocop-rails: [rails]
|
159
|
-
rubocop-rspec: [rspec]
|
159
|
+
rubocop-rspec: [rspec, rspec-rails]
|
160
160
|
rubocop-minitest: [minitest]
|
161
161
|
rubocop-sequel: [sequel]
|
162
162
|
rubocop-rake: [rake]
|
@@ -1703,7 +1703,6 @@ Lint/Debugger:
|
|
1703
1703
|
DebuggerRequires:
|
1704
1704
|
debug.rb:
|
1705
1705
|
- debug/open
|
1706
|
-
- debug/open_nonstop
|
1707
1706
|
- debug/start
|
1708
1707
|
|
1709
1708
|
Lint/DeprecatedClassMethods:
|
@@ -3091,6 +3090,7 @@ Style/AccessModifierDeclarations:
|
|
3091
3090
|
- inline
|
3092
3091
|
- group
|
3093
3092
|
AllowModifiersOnSymbols: true
|
3093
|
+
AllowModifiersOnAttrs: true
|
3094
3094
|
SafeAutoCorrect: false
|
3095
3095
|
|
3096
3096
|
Style/AccessorGrouping:
|
@@ -3688,6 +3688,7 @@ Style/DocumentationMethod:
|
|
3688
3688
|
Description: 'Checks for missing documentation comment for public methods.'
|
3689
3689
|
Enabled: false
|
3690
3690
|
VersionAdded: '0.43'
|
3691
|
+
AllowedMethods: []
|
3691
3692
|
Exclude:
|
3692
3693
|
- 'spec/**/*'
|
3693
3694
|
- 'test/**/*'
|
@@ -4069,6 +4070,8 @@ Style/HashSyntax:
|
|
4069
4070
|
- either
|
4070
4071
|
# forces use of the 3.1 syntax only if all values can be omitted in the hash.
|
4071
4072
|
- consistent
|
4073
|
+
# allow either (implicit or explicit) syntax but enforce consistency within a single hash
|
4074
|
+
- either_consistent
|
4072
4075
|
# Force hashes that have a symbol value to use hash rockets
|
4073
4076
|
UseHashRocketsWithSymbolValues: false
|
4074
4077
|
# Do not suggest { a?: 1 } over { :a? => 1 } in ruby19 style
|
@@ -5241,6 +5244,13 @@ Style/Send:
|
|
5241
5244
|
Enabled: false
|
5242
5245
|
VersionAdded: '0.33'
|
5243
5246
|
|
5247
|
+
Style/SendWithLiteralMethodName:
|
5248
|
+
Description: 'Detects the use of the `public_send` method with a static method name argument.'
|
5249
|
+
Enabled: pending
|
5250
|
+
Safe: false
|
5251
|
+
AllowSend: true
|
5252
|
+
VersionAdded: '1.64'
|
5253
|
+
|
5244
5254
|
Style/SignalException:
|
5245
5255
|
Description: 'Checks for proper usage of fail and raise.'
|
5246
5256
|
StyleGuide: '#prefer-raise-over-fail'
|
@@ -5415,6 +5425,11 @@ Style/StructInheritance:
|
|
5415
5425
|
VersionAdded: '0.29'
|
5416
5426
|
VersionChanged: '1.20'
|
5417
5427
|
|
5428
|
+
Style/SuperArguments:
|
5429
|
+
Description: 'Call `super` without arguments and parentheses when the signature is identical.'
|
5430
|
+
Enabled: pending
|
5431
|
+
VersionAdded: '1.64'
|
5432
|
+
|
5418
5433
|
Style/SuperWithArgsParentheses:
|
5419
5434
|
Description: 'Use parentheses for `super` with arguments.'
|
5420
5435
|
StyleGuide: '#super-with-args'
|
@@ -5450,7 +5465,7 @@ Style/SymbolProc:
|
|
5450
5465
|
Enabled: true
|
5451
5466
|
Safe: false
|
5452
5467
|
VersionAdded: '0.26'
|
5453
|
-
VersionChanged: '1.
|
5468
|
+
VersionChanged: '1.64'
|
5454
5469
|
AllowMethodsWithArguments: false
|
5455
5470
|
# A list of method names to be always allowed by the check.
|
5456
5471
|
# The names should be fairly unique, otherwise you'll end up ignoring lots of code.
|
data/lib/rubocop/cached_data.rb
CHANGED
@@ -48,11 +48,19 @@ module RuboCop
|
|
48
48
|
source_buffer = Parser::Source::Buffer.new(@filename)
|
49
49
|
source_buffer.source = File.read(@filename, encoding: Encoding::UTF_8)
|
50
50
|
offenses.map! do |o|
|
51
|
-
location =
|
52
|
-
o['location']['begin_pos'],
|
53
|
-
o['location']['end_pos'])
|
51
|
+
location = location_from_source_buffer(o, source_buffer)
|
54
52
|
Cop::Offense.new(o['severity'], location, o['message'], o['cop_name'], o['status'].to_sym)
|
55
53
|
end
|
56
54
|
end
|
55
|
+
|
56
|
+
def location_from_source_buffer(offense, source_buffer)
|
57
|
+
begin_pos = offense['location']['begin_pos']
|
58
|
+
end_pos = offense['location']['end_pos']
|
59
|
+
if begin_pos.zero? && end_pos.zero?
|
60
|
+
Cop::Offense::NO_LOCATION
|
61
|
+
else
|
62
|
+
Parser::Source::Range.new(source_buffer, begin_pos, end_pos)
|
63
|
+
end
|
64
|
+
end
|
57
65
|
end
|
58
66
|
end
|
@@ -26,10 +26,10 @@ module RuboCop
|
|
26
26
|
|
27
27
|
cops_array.each do |cop_name|
|
28
28
|
cop = registry_hash[cop_name]
|
29
|
-
|
30
29
|
next if cop.empty?
|
31
30
|
|
32
|
-
|
31
|
+
url = Cop::Documentation.url_for(cop.first, @config)
|
32
|
+
puts url if url
|
33
33
|
end
|
34
34
|
|
35
35
|
puts
|
data/lib/rubocop/cli.rb
CHANGED
@@ -57,6 +57,10 @@ module RuboCop
|
|
57
57
|
rescue RuboCop::Error => e
|
58
58
|
warn Rainbow("Error: #{e.message}").red
|
59
59
|
STATUS_ERROR
|
60
|
+
rescue Interrupt
|
61
|
+
warn ''
|
62
|
+
warn 'Exiting...'
|
63
|
+
STATUS_INTERRUPTED
|
60
64
|
rescue Finished
|
61
65
|
STATUS_SUCCESS
|
62
66
|
rescue OptionParser::InvalidOption => e
|
data/lib/rubocop/config.rb
CHANGED
@@ -319,9 +319,8 @@ module RuboCop
|
|
319
319
|
# @param [Gem::Version] gem_version an object like `Gem::Version.new("7.1.2.3")`
|
320
320
|
# @return [Float] The major and minor version, like `7.1`
|
321
321
|
def gem_version_to_major_minor_float(gem_version)
|
322
|
-
segments = gem_version.
|
323
|
-
#
|
324
|
-
Float("#{segments.fetch(0)}.#{segments.fetch(1, 0)}")
|
322
|
+
segments = gem_version.segments
|
323
|
+
Float("#{segments[0]}.#{segments[1]}")
|
325
324
|
end
|
326
325
|
|
327
326
|
# @returns [Hash{String => Gem::Version}] The locked gem versions, keyed by the gems' names.
|
data/lib/rubocop/cop/base.rb
CHANGED
@@ -60,12 +60,15 @@ module RuboCop
|
|
60
60
|
[]
|
61
61
|
end
|
62
62
|
|
63
|
-
#
|
63
|
+
# Returns an url to view this cops documentation online.
|
64
|
+
# Requires 'DocumentationBaseURL' to be set for your department.
|
65
|
+
# Will follow the convention of RuboCops own documentation structure,
|
66
|
+
# overwrite this method to accommodate your custom layout.
|
64
67
|
# @return [String, nil]
|
65
68
|
#
|
66
69
|
# @api public
|
67
|
-
def self.documentation_url
|
68
|
-
Documentation.url_for(self)
|
70
|
+
def self.documentation_url(config = nil)
|
71
|
+
Documentation.url_for(self, config)
|
69
72
|
end
|
70
73
|
|
71
74
|
def self.inherited(subclass)
|
@@ -186,7 +189,9 @@ module RuboCop
|
|
186
189
|
def add_global_offense(message = nil, severity: nil)
|
187
190
|
severity = find_severity(nil, severity)
|
188
191
|
message = find_message(nil, message)
|
189
|
-
|
192
|
+
range = Offense::NO_LOCATION
|
193
|
+
status = enabled_line?(range.line) ? :unsupported : :disabled
|
194
|
+
current_offenses << Offense.new(severity, range, message, name, status)
|
190
195
|
end
|
191
196
|
|
192
197
|
# Adds an offense on the specified range (or node with an expression)
|
@@ -396,16 +401,6 @@ module RuboCop
|
|
396
401
|
|
397
402
|
### Actually private methods
|
398
403
|
|
399
|
-
# rubocop:disable Layout/ClassStructure
|
400
|
-
def self.builtin?
|
401
|
-
return false unless (m = instance_methods(false).first) # any custom method will do
|
402
|
-
|
403
|
-
path, _line = instance_method(m).source_location
|
404
|
-
path.start_with?(__dir__)
|
405
|
-
end
|
406
|
-
private_class_method :builtin?
|
407
|
-
# rubocop:enable Layout/ClassStructure
|
408
|
-
|
409
404
|
def reset_investigation
|
410
405
|
@currently_disabled_lines = @current_offenses = @processed_source = @current_corrector = nil
|
411
406
|
end
|
@@ -90,13 +90,11 @@ module RuboCop
|
|
90
90
|
Array(cop_config['AllowedGems'])
|
91
91
|
end
|
92
92
|
|
93
|
-
def message(
|
94
|
-
gem_specification = range.source
|
95
|
-
|
93
|
+
def message(_range)
|
96
94
|
if required_style?
|
97
|
-
|
95
|
+
REQUIRED_MSG
|
98
96
|
elsif forbidden_style?
|
99
|
-
|
97
|
+
FORBIDDEN_MSG
|
100
98
|
end
|
101
99
|
end
|
102
100
|
|
@@ -17,23 +17,33 @@ module RuboCop
|
|
17
17
|
fragment = cop_class.cop_name.downcase.gsub(/[^a-z]/, '')
|
18
18
|
base_url = base_url_for(cop_class, config)
|
19
19
|
|
20
|
-
"#{base_url}/#{base}.html##{fragment}"
|
20
|
+
"#{base_url}/#{base}.html##{fragment}" if base_url
|
21
21
|
end
|
22
22
|
|
23
23
|
# @api private
|
24
24
|
def base_url_for(cop_class, config)
|
25
|
-
|
25
|
+
if config
|
26
|
+
department_name = cop_class.department.to_s
|
27
|
+
url = config.for_department(department_name)['DocumentationBaseURL']
|
28
|
+
return url if url
|
29
|
+
end
|
26
30
|
|
27
|
-
|
28
|
-
|
29
|
-
config.for_department(department_name)['DocumentationBaseURL'] ||
|
30
|
-
config.for_all_cops['DocumentationBaseURL']
|
31
|
+
default_base_url if builtin?(cop_class)
|
31
32
|
end
|
32
33
|
|
33
34
|
# @api private
|
34
35
|
def default_base_url
|
35
36
|
'https://docs.rubocop.org/rubocop'
|
36
37
|
end
|
38
|
+
|
39
|
+
# @api private
|
40
|
+
def builtin?(cop_class)
|
41
|
+
# any custom method will do
|
42
|
+
return false unless (m = cop_class.instance_methods(false).first)
|
43
|
+
|
44
|
+
path, _line = cop_class.instance_method(m).source_location
|
45
|
+
path.start_with?(__dir__)
|
46
|
+
end
|
37
47
|
end
|
38
48
|
end
|
39
49
|
end
|
@@ -101,13 +101,11 @@ module RuboCop
|
|
101
101
|
Array(cop_config['AllowedGems'])
|
102
102
|
end
|
103
103
|
|
104
|
-
def message(
|
105
|
-
gem_specification = range.source
|
106
|
-
|
104
|
+
def message(_range)
|
107
105
|
if required_style?
|
108
|
-
|
106
|
+
REQUIRED_MSG
|
109
107
|
elsif forbidden_style?
|
110
|
-
|
108
|
+
FORBIDDEN_MSG
|
111
109
|
end
|
112
110
|
end
|
113
111
|
|
@@ -46,7 +46,7 @@ module RuboCop
|
|
46
46
|
/\A(does not|doesn't) (register|find|flag|report)/ => 'registers',
|
47
47
|
/\A(does not|doesn't) add (a|an|any )?offense/ => 'registers an offense',
|
48
48
|
/\Aregisters no offense/ => 'registers an offense',
|
49
|
-
/\
|
49
|
+
/\A(accepts|register)\b/ => 'registers'
|
50
50
|
}.freeze
|
51
51
|
|
52
52
|
EXPECT_NO_CORRECTIONS_DESCRIPTION_MAPPING = {
|
@@ -106,7 +106,9 @@ module RuboCop
|
|
106
106
|
end
|
107
107
|
|
108
108
|
def concat_consecutive_comments(comments)
|
109
|
-
consecutive_comments = comments.chunk_while
|
109
|
+
consecutive_comments = comments.chunk_while do |i, j|
|
110
|
+
i.loc.line.succ == j.loc.line && i.loc.column == j.loc.column
|
111
|
+
end
|
110
112
|
|
111
113
|
consecutive_comments.map do |chunk|
|
112
114
|
joined_text = chunk.map { |c| comment_text(c) }.join
|
@@ -88,7 +88,9 @@ module RuboCop
|
|
88
88
|
end
|
89
89
|
|
90
90
|
def skip_children?(asgn_node)
|
91
|
-
|
91
|
+
(asgn_node.call_type? && !asgn_node.assignment_method?) ||
|
92
|
+
empty_condition?(asgn_node) ||
|
93
|
+
(safe_assignment_allowed? && safe_assignment?(asgn_node))
|
92
94
|
end
|
93
95
|
|
94
96
|
def traverse_node(node, &block)
|
@@ -52,7 +52,7 @@ module RuboCop
|
|
52
52
|
# @!method deprecated_class_method?(node)
|
53
53
|
def_node_matcher :deprecated_class_method?, <<~PATTERN
|
54
54
|
{
|
55
|
-
(send (const {cbase nil?}
|
55
|
+
(send (const {cbase nil?} :ENV) {:clone :dup :freeze})
|
56
56
|
(send (const {cbase nil?} {:File :Dir}) :exists? _)
|
57
57
|
(send (const {cbase nil?} :Socket) {:gethostbyaddr :gethostbyname} ...)
|
58
58
|
(send nil? :attr _ boolean)
|
@@ -146,7 +146,7 @@ module RuboCop
|
|
146
146
|
node.source_range.with(end_pos: node.condition.source_range.end_pos)
|
147
147
|
elsif all_branches_body_missing?(node)
|
148
148
|
if_node = node.ancestors.detect(&:if?)
|
149
|
-
node.source_range.
|
149
|
+
node.source_range.join(if_node.loc.end.end)
|
150
150
|
else
|
151
151
|
node.source_range
|
152
152
|
end
|
@@ -47,8 +47,10 @@ module RuboCop
|
|
47
47
|
|
48
48
|
def on_regexp(node)
|
49
49
|
each_unsafe_regexp_range(node) do |loc|
|
50
|
+
next unless (replacement = regexp_range(loc.source))
|
51
|
+
|
50
52
|
add_offense(loc) do |corrector|
|
51
|
-
corrector.replace(loc,
|
53
|
+
corrector.replace(loc, replacement)
|
52
54
|
end
|
53
55
|
end
|
54
56
|
end
|
@@ -99,10 +101,13 @@ module RuboCop
|
|
99
101
|
end
|
100
102
|
end
|
101
103
|
|
102
|
-
def
|
104
|
+
def regexp_range(source)
|
103
105
|
open, close = source.split('-')
|
104
|
-
|
105
|
-
|
106
|
+
return unless (open_range = range_for(open))
|
107
|
+
return unless (close_range = range_for(close))
|
108
|
+
|
109
|
+
first = [open, open_range.end]
|
110
|
+
second = [close_range.begin, close]
|
106
111
|
"#{first.uniq.join('-')}#{second.uniq.join('-')}"
|
107
112
|
end
|
108
113
|
end
|
@@ -130,7 +130,7 @@ module RuboCop
|
|
130
130
|
# @return [Parser::Source::Range]
|
131
131
|
#
|
132
132
|
def last_arg_range(node)
|
133
|
-
node.last_argument.source_range.
|
133
|
+
node.last_argument.source_range.join(node.arguments[-2].source_range.end)
|
134
134
|
end
|
135
135
|
|
136
136
|
def unsorted_dir_loop?(node)
|
@@ -71,7 +71,7 @@ module RuboCop
|
|
71
71
|
expressions.any? { |expr| flow_expression?(expr) }
|
72
72
|
when :if
|
73
73
|
check_if(node)
|
74
|
-
when :case
|
74
|
+
when :case, :case_match
|
75
75
|
check_case(node)
|
76
76
|
else
|
77
77
|
false
|
@@ -89,7 +89,9 @@ module RuboCop
|
|
89
89
|
return false unless else_branch
|
90
90
|
return false unless flow_expression?(else_branch)
|
91
91
|
|
92
|
-
node.
|
92
|
+
branches = node.case_type? ? node.when_branches : node.in_pattern_branches
|
93
|
+
|
94
|
+
branches.all? { |branch| branch.body && flow_expression?(branch.body) }
|
93
95
|
end
|
94
96
|
end
|
95
97
|
end
|
@@ -160,7 +160,7 @@ module RuboCop
|
|
160
160
|
break_statement && !preceded_by_continue_statement?(break_statement)
|
161
161
|
when :if
|
162
162
|
check_if(node)
|
163
|
-
when :case
|
163
|
+
when :case, :case_match
|
164
164
|
check_case(node)
|
165
165
|
else
|
166
166
|
false
|
@@ -178,7 +178,13 @@ module RuboCop
|
|
178
178
|
return false unless else_branch
|
179
179
|
return false unless break_statement?(else_branch)
|
180
180
|
|
181
|
-
|
181
|
+
branches = if node.case_type?
|
182
|
+
node.when_branches
|
183
|
+
else
|
184
|
+
node.in_pattern_branches
|
185
|
+
end
|
186
|
+
|
187
|
+
branches.all? { |branch| branch.body && break_statement?(branch.body) }
|
182
188
|
end
|
183
189
|
|
184
190
|
def preceded_by_continue_statement?(break_statement)
|
@@ -43,16 +43,16 @@ module RuboCop
|
|
43
43
|
types.map do |type|
|
44
44
|
case type
|
45
45
|
when :array
|
46
|
-
|
46
|
+
lambda(&:array_type?)
|
47
47
|
when :hash
|
48
|
-
|
48
|
+
lambda(&:hash_type?)
|
49
49
|
when :heredoc
|
50
50
|
->(node) { heredoc_node?(node) }
|
51
51
|
when :method_call
|
52
|
-
|
52
|
+
lambda(&:call_type?)
|
53
53
|
else
|
54
|
-
raise
|
55
|
-
|
54
|
+
raise Warning, "Unknown foldable type: #{type.inspect}. " \
|
55
|
+
"Valid foldable types are: #{FOLDABLE_TYPES.join(', ')}."
|
56
56
|
end
|
57
57
|
end
|
58
58
|
end
|
@@ -67,13 +67,14 @@ module RuboCop
|
|
67
67
|
end
|
68
68
|
|
69
69
|
def ignore_mixed_hash_shorthand_syntax?(hash_node)
|
70
|
-
target_ruby_version <= 3.0 ||
|
70
|
+
target_ruby_version <= 3.0 ||
|
71
|
+
!%w[consistent either_consistent].include?(enforced_shorthand_syntax) ||
|
71
72
|
!hash_node.hash_type?
|
72
73
|
end
|
73
74
|
|
74
75
|
def ignore_hash_shorthand_syntax?(pair_node)
|
75
76
|
target_ruby_version <= 3.0 || enforced_shorthand_syntax == 'either' ||
|
76
|
-
enforced_shorthand_syntax
|
77
|
+
%w[consistent either_consistent].include?(enforced_shorthand_syntax) ||
|
77
78
|
!pair_node.parent.hash_type?
|
78
79
|
end
|
79
80
|
|
@@ -172,6 +173,11 @@ module RuboCop
|
|
172
173
|
hash_value_type_breakdown[:value_needed]&.any?
|
173
174
|
end
|
174
175
|
|
176
|
+
def ignore_explicit_omissible_hash_shorthand_syntax?(hash_value_type_breakdown)
|
177
|
+
hash_value_type_breakdown.keys == [:value_omittable] &&
|
178
|
+
enforced_shorthand_syntax == 'either_consistent'
|
179
|
+
end
|
180
|
+
|
175
181
|
def each_omitted_value_pair(hash_value_type_breakdown, &block)
|
176
182
|
hash_value_type_breakdown[:value_omitted]&.each(&block)
|
177
183
|
end
|
@@ -198,6 +204,7 @@ module RuboCop
|
|
198
204
|
|
199
205
|
def no_mixed_shorthand_syntax_check(hash_value_type_breakdown)
|
200
206
|
return if hash_with_values_that_cant_be_omitted?(hash_value_type_breakdown)
|
207
|
+
return if ignore_explicit_omissible_hash_shorthand_syntax?(hash_value_type_breakdown)
|
201
208
|
|
202
209
|
each_omittable_value_pair(hash_value_type_breakdown) do |pair_node|
|
203
210
|
hash_key_source = pair_node.key.source
|
@@ -30,8 +30,8 @@ module RuboCop
|
|
30
30
|
class CompoundHash < Base
|
31
31
|
COMBINATOR_IN_HASH_MSG = 'Use `[...].hash` instead of combining hash values manually.'
|
32
32
|
MONUPLE_HASH_MSG =
|
33
|
-
'Delegate hash directly without wrapping in an array when only using a single value'
|
34
|
-
REDUNDANT_HASH_MSG = 'Calling .hash on elements of a hashed array is redundant'
|
33
|
+
'Delegate hash directly without wrapping in an array when only using a single value.'
|
34
|
+
REDUNDANT_HASH_MSG = 'Calling .hash on elements of a hashed array is redundant.'
|
35
35
|
|
36
36
|
# @!method hash_method_definition?(node)
|
37
37
|
def_node_matcher :hash_method_definition?, <<~PATTERN
|
@@ -8,6 +8,17 @@ module RuboCop
|
|
8
8
|
# EnforcedStyle config covers only method definitions.
|
9
9
|
# Applications of visibility methods to symbols can be controlled
|
10
10
|
# using AllowModifiersOnSymbols config.
|
11
|
+
# Also, the visibility of `attr*` methods can be controlled using
|
12
|
+
# AllowModifiersOnAttrs config.
|
13
|
+
#
|
14
|
+
# In Ruby 3.0, `attr*` methods now return an array of defined method names
|
15
|
+
# as symbols. So we can write the modifier and `attr*` in inline style.
|
16
|
+
# AllowModifiersOnAttrs config allows `attr*` methods to be written in
|
17
|
+
# inline style without modifying applications that have been maintained
|
18
|
+
# for a long time in group style. Furthermore, developers who are not very
|
19
|
+
# familiar with Ruby may know that the modifier applies to `def`, but they
|
20
|
+
# may not know that it also applies to `attr*` methods. It would be easier
|
21
|
+
# to understand if we could write `attr*` methods in inline style.
|
11
22
|
#
|
12
23
|
# @safety
|
13
24
|
# Autocorrection is not safe, because the visibility of dynamically
|
@@ -67,6 +78,34 @@ module RuboCop
|
|
67
78
|
# private :bar, :baz
|
68
79
|
#
|
69
80
|
# end
|
81
|
+
#
|
82
|
+
# @example AllowModifiersOnAttrs: true (default)
|
83
|
+
# # good
|
84
|
+
# class Foo
|
85
|
+
#
|
86
|
+
# public attr_reader :bar
|
87
|
+
# protected attr_writer :baz
|
88
|
+
# private attr_accessor :qux
|
89
|
+
# private attr :quux
|
90
|
+
#
|
91
|
+
# def public_method; end
|
92
|
+
#
|
93
|
+
# private
|
94
|
+
#
|
95
|
+
# def private_method; end
|
96
|
+
#
|
97
|
+
# end
|
98
|
+
#
|
99
|
+
# @example AllowModifiersOnAttrs: false
|
100
|
+
# # bad
|
101
|
+
# class Foo
|
102
|
+
#
|
103
|
+
# public attr_reader :bar
|
104
|
+
# protected attr_writer :baz
|
105
|
+
# private attr_accessor :qux
|
106
|
+
# private attr :quux
|
107
|
+
#
|
108
|
+
# end
|
70
109
|
class AccessModifierDeclarations < Base
|
71
110
|
extend AutoCorrector
|
72
111
|
|
@@ -92,10 +131,17 @@ module RuboCop
|
|
92
131
|
(send nil? {:private :protected :public :module_function} (sym _))
|
93
132
|
PATTERN
|
94
133
|
|
134
|
+
# @!method access_modifier_with_attr?(node)
|
135
|
+
def_node_matcher :access_modifier_with_attr?, <<~PATTERN
|
136
|
+
(send nil? {:private :protected :public :module_function}
|
137
|
+
(send nil? {:attr :attr_reader :attr_writer :attr_accessor} _))
|
138
|
+
PATTERN
|
139
|
+
|
95
140
|
def on_send(node)
|
96
141
|
return unless node.access_modifier?
|
97
142
|
return if ALLOWED_NODE_TYPES.include?(node.parent&.type)
|
98
143
|
return if allow_modifiers_on_symbols?(node)
|
144
|
+
return if allow_modifiers_on_attrs?(node)
|
99
145
|
|
100
146
|
if offense?(node)
|
101
147
|
add_offense(node.loc.selector) do |corrector|
|
@@ -128,6 +174,10 @@ module RuboCop
|
|
128
174
|
cop_config['AllowModifiersOnSymbols'] && access_modifier_with_symbol?(node)
|
129
175
|
end
|
130
176
|
|
177
|
+
def allow_modifiers_on_attrs?(node)
|
178
|
+
cop_config['AllowModifiersOnAttrs'] && access_modifier_with_attr?(node)
|
179
|
+
end
|
180
|
+
|
131
181
|
def offense?(node)
|
132
182
|
(group_style? && access_modifier_is_inlined?(node) &&
|
133
183
|
!right_siblings_same_inline_method?(node)) ||
|
@@ -29,6 +29,8 @@ module RuboCop
|
|
29
29
|
#
|
30
30
|
# Names not on this list are likely to be meaningful and are allowed by default.
|
31
31
|
#
|
32
|
+
# This cop handles not only method forwarding but also forwarding to `super`.
|
33
|
+
#
|
32
34
|
# @example
|
33
35
|
# # bad
|
34
36
|
# def foo(*args, &block)
|
@@ -146,7 +148,7 @@ module RuboCop
|
|
146
148
|
|
147
149
|
restarg, kwrestarg, blockarg = extract_forwardable_args(node.arguments)
|
148
150
|
forwardable_args = redundant_forwardable_named_args(restarg, kwrestarg, blockarg)
|
149
|
-
send_nodes = node.each_descendant(:send).to_a
|
151
|
+
send_nodes = node.each_descendant(:send, :csend, :super).to_a
|
150
152
|
|
151
153
|
send_classifications = classify_send_nodes(
|
152
154
|
node, send_nodes, non_splat_or_block_pass_lvar_references(node.body), forwardable_args
|
@@ -312,7 +314,8 @@ module RuboCop
|
|
312
314
|
end
|
313
315
|
|
314
316
|
def register_forward_block_arg_offense(add_parens, def_arguments_or_send, block_arg)
|
315
|
-
return if target_ruby_version <= 3.0 ||
|
317
|
+
return if target_ruby_version <= 3.0 ||
|
318
|
+
block_arg.nil? || block_arg.source == '&' || explicit_block_name?
|
316
319
|
|
317
320
|
add_offense(block_arg, message: BLOCK_MSG) do |corrector|
|
318
321
|
add_parens_if_missing(def_arguments_or_send, corrector) if add_parens
|
@@ -214,7 +214,7 @@ module RuboCop
|
|
214
214
|
extend AutoCorrector
|
215
215
|
|
216
216
|
MSG = 'Use the return of the conditional for variable assignment and comparison.'
|
217
|
-
ASSIGN_TO_CONDITION_MSG = 'Assign variables inside of conditionals'
|
217
|
+
ASSIGN_TO_CONDITION_MSG = 'Assign variables inside of conditionals.'
|
218
218
|
VARIABLE_ASSIGNMENT_TYPES = %i[casgn cvasgn gvasgn ivasgn lvasgn].freeze
|
219
219
|
ASSIGNMENT_TYPES = VARIABLE_ASSIGNMENT_TYPES + %i[and_asgn or_asgn op_asgn masgn].freeze
|
220
220
|
LINE_LENGTH = 'Layout/LineLength'
|