rubocop 1.35.1 → 1.37.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +1 -1
- data/config/default.yml +32 -1
- data/lib/rubocop/arguments_env.rb +17 -0
- data/lib/rubocop/arguments_file.rb +17 -0
- data/lib/rubocop/cli/command/execute_runner.rb +7 -7
- data/lib/rubocop/cop/generator.rb +1 -2
- data/lib/rubocop/cop/layout/block_alignment.rb +14 -12
- data/lib/rubocop/cop/layout/first_argument_indentation.rb +1 -0
- data/lib/rubocop/cop/layout/indentation_width.rb +4 -2
- data/lib/rubocop/cop/layout/space_inside_array_literal_brackets.rb +13 -9
- data/lib/rubocop/cop/layout/space_inside_block_braces.rb +25 -9
- data/lib/rubocop/cop/layout/space_inside_hash_literal_braces.rb +28 -3
- data/lib/rubocop/cop/lint/ambiguous_block_association.rb +2 -2
- data/lib/rubocop/cop/lint/duplicate_magic_comment.rb +73 -0
- data/lib/rubocop/cop/lint/duplicate_methods.rb +11 -1
- data/lib/rubocop/cop/lint/duplicate_regexp_character_class_element.rb +25 -6
- data/lib/rubocop/cop/lint/duplicate_require.rb +1 -1
- data/lib/rubocop/cop/lint/empty_class.rb +3 -1
- data/lib/rubocop/cop/lint/empty_conditional_body.rb +46 -4
- data/lib/rubocop/cop/lint/nested_method_definition.rb +50 -1
- data/lib/rubocop/cop/lint/number_conversion.rb +1 -1
- data/lib/rubocop/cop/lint/ordered_magic_comments.rb +4 -5
- data/lib/rubocop/cop/lint/out_of_range_regexp_ref.rb +1 -1
- data/lib/rubocop/cop/lint/redundant_cop_disable_directive.rb +12 -1
- data/lib/rubocop/cop/lint/redundant_dir_glob_sort.rb +7 -0
- data/lib/rubocop/cop/lint/redundant_require_statement.rb +29 -9
- data/lib/rubocop/cop/lint/require_parentheses.rb +1 -1
- data/lib/rubocop/cop/lint/safe_navigation_chain.rb +3 -2
- data/lib/rubocop/cop/lint/shadowed_exception.rb +1 -11
- data/lib/rubocop/cop/lint/shadowing_outer_local_variable.rb +17 -2
- data/lib/rubocop/cop/lint/unreachable_loop.rb +2 -2
- data/lib/rubocop/cop/lint/unused_method_argument.rb +4 -0
- data/lib/rubocop/cop/lint/useless_access_modifier.rb +2 -2
- data/lib/rubocop/cop/lint/useless_ruby2_keywords.rb +1 -1
- data/lib/rubocop/cop/mixin/allowed_methods.rb +10 -5
- data/lib/rubocop/cop/mixin/allowed_pattern.rb +13 -5
- data/lib/rubocop/cop/mixin/comments_help.rb +12 -0
- data/lib/rubocop/cop/mixin/frozen_string_literal.rb +4 -0
- data/lib/rubocop/cop/mixin/hash_shorthand_syntax.rb +6 -3
- data/lib/rubocop/cop/mixin/hash_transform_method.rb +9 -5
- data/lib/rubocop/cop/mixin/rescue_node.rb +3 -1
- data/lib/rubocop/cop/mixin/surrounding_space.rb +6 -5
- data/lib/rubocop/cop/naming/inclusive_language.rb +1 -1
- data/lib/rubocop/cop/style/access_modifier_declarations.rb +97 -1
- data/lib/rubocop/cop/style/accessor_grouping.rb +7 -3
- data/lib/rubocop/cop/style/block_delimiters.rb +1 -1
- data/lib/rubocop/cop/style/case_equality.rb +40 -10
- data/lib/rubocop/cop/style/class_equality_comparison.rb +1 -1
- data/lib/rubocop/cop/style/collection_compact.rb +6 -1
- data/lib/rubocop/cop/style/each_for_simple_loop.rb +40 -5
- data/lib/rubocop/cop/style/empty_method.rb +1 -1
- data/lib/rubocop/cop/style/endless_method.rb +1 -1
- data/lib/rubocop/cop/style/explicit_block_argument.rb +4 -0
- data/lib/rubocop/cop/style/format_string_token.rb +1 -1
- data/lib/rubocop/cop/style/hash_syntax.rb +1 -1
- data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +13 -2
- data/lib/rubocop/cop/style/negated_if_else_condition.rb +7 -1
- data/lib/rubocop/cop/style/numeric_predicate.rb +1 -1
- data/lib/rubocop/cop/style/operator_method_call.rb +39 -0
- data/lib/rubocop/cop/style/perl_backrefs.rb +22 -1
- data/lib/rubocop/cop/style/redundant_begin.rb +1 -0
- data/lib/rubocop/cop/style/redundant_condition.rb +5 -2
- data/lib/rubocop/cop/style/redundant_initialize.rb +3 -1
- data/lib/rubocop/cop/style/redundant_parentheses.rb +4 -0
- data/lib/rubocop/cop/style/redundant_regexp_character_class.rb +8 -1
- data/lib/rubocop/cop/style/redundant_string_escape.rb +173 -0
- data/lib/rubocop/cop/style/rescue_modifier.rb +1 -1
- data/lib/rubocop/cop/style/static_class.rb +32 -1
- data/lib/rubocop/cop/style/symbol_array.rb +2 -0
- data/lib/rubocop/cop/style/symbol_proc.rb +6 -5
- data/lib/rubocop/cop/style/word_array.rb +2 -0
- data/lib/rubocop/formatter/disabled_config_formatter.rb +8 -2
- data/lib/rubocop/options.rb +13 -13
- data/lib/rubocop/rspec/shared_contexts.rb +13 -1
- data/lib/rubocop/runner.rb +4 -0
- data/lib/rubocop/server/cache.rb +5 -1
- data/lib/rubocop/server/cli.rb +9 -2
- data/lib/rubocop/server/client_command/exec.rb +5 -0
- data/lib/rubocop/server/core.rb +2 -1
- data/lib/rubocop/server/socket_reader.rb +5 -1
- data/lib/rubocop/server.rb +1 -1
- data/lib/rubocop/version.rb +8 -2
- data/lib/rubocop.rb +3 -0
- metadata +10 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e928a8547def9cafd9cddc36b5a407aef7d46fdf9825941c7906073492d88668
|
4
|
+
data.tar.gz: 3ef9727850f93815ba310b7c3a8cf74e53a0ee18a0fcf6731fd97a3640ffe28d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f57e5d25375fe47734a6e198924db74b341501762dc8f54277a888788ab821215c96847940cec1af4d90673fe79ab906b451bf25bec90f9c8c080e78efc01111
|
7
|
+
data.tar.gz: 69cafbca956eaa49887596d255f6888057ede94f3621349398de95da5c477201f7bee7eae074ab4750ce0131dcb26d6dfdc77c31f5fcb478d2fc25d5ca73e68c
|
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.37', 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
@@ -1707,6 +1707,11 @@ Lint/DuplicateHashKey:
|
|
1707
1707
|
VersionAdded: '0.34'
|
1708
1708
|
VersionChanged: '0.77'
|
1709
1709
|
|
1710
|
+
Lint/DuplicateMagicComment:
|
1711
|
+
Description: 'Check for duplicated magic comments.'
|
1712
|
+
Enabled: pending
|
1713
|
+
VersionAdded: '1.37'
|
1714
|
+
|
1710
1715
|
Lint/DuplicateMethods:
|
1711
1716
|
Description: 'Check for duplicate method definitions.'
|
1712
1717
|
Enabled: true
|
@@ -1957,6 +1962,8 @@ Lint/NestedMethodDefinition:
|
|
1957
1962
|
Description: 'Do not use nested method definitions.'
|
1958
1963
|
StyleGuide: '#no-nested-methods'
|
1959
1964
|
Enabled: true
|
1965
|
+
AllowedMethods: []
|
1966
|
+
AllowedPatterns: []
|
1960
1967
|
VersionAdded: '0.32'
|
1961
1968
|
|
1962
1969
|
Lint/NestedPercentLiteral:
|
@@ -2021,7 +2028,9 @@ Lint/OrAssignmentToConstant:
|
|
2021
2028
|
Lint/OrderedMagicComments:
|
2022
2029
|
Description: 'Checks the proper ordering of magic comments and whether a magic comment is not placed before a shebang.'
|
2023
2030
|
Enabled: true
|
2031
|
+
SafeAutoCorrect: false
|
2024
2032
|
VersionAdded: '0.53'
|
2033
|
+
VersionChanged: '1.37'
|
2025
2034
|
|
2026
2035
|
Lint/OutOfRangeRegexpRef:
|
2027
2036
|
Description: 'Checks for out of range reference for Regexp because it always returns nil.'
|
@@ -2794,6 +2803,7 @@ Naming/MethodParameterName:
|
|
2794
2803
|
AllowNamesEndingInNumbers: true
|
2795
2804
|
# Allowed names that will not register an offense
|
2796
2805
|
AllowedNames:
|
2806
|
+
- as
|
2797
2807
|
- at
|
2798
2808
|
- by
|
2799
2809
|
- db
|
@@ -2948,6 +2958,7 @@ Style/AccessModifierDeclarations:
|
|
2948
2958
|
- inline
|
2949
2959
|
- group
|
2950
2960
|
AllowModifiersOnSymbols: true
|
2961
|
+
SafeAutoCorrect: false
|
2951
2962
|
|
2952
2963
|
Style/AccessorGrouping:
|
2953
2964
|
Description: 'Checks for grouping of accessors in `class` and `module` bodies.'
|
@@ -3186,6 +3197,15 @@ Style/CaseEquality:
|
|
3186
3197
|
# # good
|
3187
3198
|
# String === "string"
|
3188
3199
|
AllowOnConstant: false
|
3200
|
+
# If `AllowOnSelfClass` option is enabled, the cop will ignore violations when the receiver of
|
3201
|
+
# the case equality operator is `self.class`.
|
3202
|
+
#
|
3203
|
+
# # bad
|
3204
|
+
# some_class === object
|
3205
|
+
#
|
3206
|
+
# # good
|
3207
|
+
# self.class === object
|
3208
|
+
AllowOnSelfClass: false
|
3189
3209
|
|
3190
3210
|
Style/CaseLikeIf:
|
3191
3211
|
Description: 'Identifies places where `if-elsif` constructions can be replaced with `case-when`.'
|
@@ -3839,7 +3859,7 @@ Style/HashSyntax:
|
|
3839
3859
|
- never
|
3840
3860
|
# accepts both shorthand and explicit use of hash literal value.
|
3841
3861
|
- either
|
3842
|
-
# like "
|
3862
|
+
# like "either", but will avoid mixing styles in a single hash
|
3843
3863
|
- consistent
|
3844
3864
|
# Force hashes that have a symbol value to use hash rockets
|
3845
3865
|
UseHashRocketsWithSymbolValues: false
|
@@ -4487,6 +4507,12 @@ Style/OpenStructUse:
|
|
4487
4507
|
Enabled: pending
|
4488
4508
|
VersionAdded: '1.23'
|
4489
4509
|
|
4510
|
+
Style/OperatorMethodCall:
|
4511
|
+
Description: 'Checks for redundant dot before operator method call.'
|
4512
|
+
StyleGuide: '#operator-method-call'
|
4513
|
+
Enabled: pending
|
4514
|
+
VersionAdded: '1.37'
|
4515
|
+
|
4490
4516
|
Style/OptionHash:
|
4491
4517
|
Description: "Don't use option hashes when you can use keyword arguments."
|
4492
4518
|
Enabled: false
|
@@ -4781,6 +4807,11 @@ Style/RedundantSortBy:
|
|
4781
4807
|
Enabled: true
|
4782
4808
|
VersionAdded: '0.36'
|
4783
4809
|
|
4810
|
+
Style/RedundantStringEscape:
|
4811
|
+
Description: 'Checks for redundant escapes in string literals.'
|
4812
|
+
Enabled: pending
|
4813
|
+
VersionAdded: '1.37'
|
4814
|
+
|
4784
4815
|
Style/RegexpLiteral:
|
4785
4816
|
Description: 'Use / or %r around regular expressions.'
|
4786
4817
|
StyleGuide: '#percent-r'
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
# This is a class that reads optional command line arguments to rubocop from environment variable.
|
5
|
+
# @api private
|
6
|
+
class ArgumentsEnv
|
7
|
+
def self.read_as_arguments
|
8
|
+
if (arguments = ENV.fetch('RUBOCOP_OPTS', '')).empty?
|
9
|
+
[]
|
10
|
+
else
|
11
|
+
require 'shellwords'
|
12
|
+
|
13
|
+
Shellwords.split(arguments)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
# This is a class that reads optional command line arguments to rubocop from .rubocop file.
|
5
|
+
# @api private
|
6
|
+
class ArgumentsFile
|
7
|
+
def self.read_as_arguments
|
8
|
+
if File.exist?('.rubocop') && !File.directory?('.rubocop')
|
9
|
+
require 'shellwords'
|
10
|
+
|
11
|
+
File.read('.rubocop').shellsplit
|
12
|
+
else
|
13
|
+
[]
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -41,13 +41,13 @@ module RuboCop
|
|
41
41
|
|
42
42
|
def with_redirect
|
43
43
|
if @options[:stderr]
|
44
|
-
orig_stdout = $stdout
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
44
|
+
orig_stdout = $stdout
|
45
|
+
begin
|
46
|
+
$stdout = $stderr
|
47
|
+
yield
|
48
|
+
ensure
|
49
|
+
$stdout = orig_stdout
|
50
|
+
end
|
51
51
|
else
|
52
52
|
yield
|
53
53
|
end
|
@@ -206,9 +206,8 @@ module RuboCop
|
|
206
206
|
end
|
207
207
|
|
208
208
|
def snake_case(camel_case_string)
|
209
|
-
return 'rspec' if camel_case_string == 'RSpec'
|
210
|
-
|
211
209
|
camel_case_string
|
210
|
+
.gsub('RSpec', 'Rspec')
|
212
211
|
.gsub(%r{([^A-Z/])([A-Z]+)}, '\1_\2')
|
213
212
|
.gsub(%r{([A-Z])([A-Z][^A-Z\d/]+)}, '\1_\2')
|
214
213
|
.downcase
|
@@ -22,23 +22,24 @@ module RuboCop
|
|
22
22
|
# # bad
|
23
23
|
#
|
24
24
|
# foo.bar
|
25
|
-
#
|
26
|
-
#
|
27
|
-
#
|
25
|
+
# .each do
|
26
|
+
# baz
|
27
|
+
# end
|
28
28
|
#
|
29
29
|
# # good
|
30
30
|
#
|
31
|
-
#
|
32
|
-
#
|
31
|
+
# foo.bar
|
32
|
+
# .each do
|
33
|
+
# baz
|
33
34
|
# end
|
34
35
|
#
|
35
36
|
# @example EnforcedStyleAlignWith: start_of_block
|
36
37
|
# # bad
|
37
38
|
#
|
38
39
|
# foo.bar
|
39
|
-
#
|
40
|
-
#
|
41
|
-
#
|
40
|
+
# .each do
|
41
|
+
# baz
|
42
|
+
# end
|
42
43
|
#
|
43
44
|
# # good
|
44
45
|
#
|
@@ -51,16 +52,17 @@ module RuboCop
|
|
51
52
|
# # bad
|
52
53
|
#
|
53
54
|
# foo.bar
|
54
|
-
#
|
55
|
-
#
|
56
|
-
#
|
55
|
+
# .each do
|
56
|
+
# baz
|
57
|
+
# end
|
57
58
|
#
|
58
59
|
# # good
|
59
60
|
#
|
60
61
|
# foo.bar
|
61
62
|
# .each do
|
62
|
-
#
|
63
|
+
# baz
|
63
64
|
# end
|
65
|
+
#
|
64
66
|
class BlockAlignment < Base
|
65
67
|
include ConfigurableEnforcedStyle
|
66
68
|
include RangeHelp
|
@@ -148,7 +148,9 @@ module RuboCop
|
|
148
148
|
check_indentation(in_pattern_node.loc.keyword, in_pattern_node.body)
|
149
149
|
end
|
150
150
|
|
151
|
-
|
151
|
+
else_branch = case_match.else_branch&.empty_else_type? ? nil : case_match.else_branch
|
152
|
+
|
153
|
+
check_indentation(case_match.in_pattern_branches.last.loc.keyword, else_branch)
|
152
154
|
end
|
153
155
|
|
154
156
|
def on_if(node, base = node)
|
@@ -341,7 +343,7 @@ module RuboCop
|
|
341
343
|
end
|
342
344
|
|
343
345
|
def skip_check?(base_loc, body_node)
|
344
|
-
return true if
|
346
|
+
return true if allowed_line?(base_loc)
|
345
347
|
return true unless body_node
|
346
348
|
|
347
349
|
# Don't check if expression is on same line as "then" keyword, etc.
|
@@ -169,19 +169,22 @@ module RuboCop
|
|
169
169
|
|
170
170
|
def qualifies_for_compact?(node, token, side: :right)
|
171
171
|
if side == :right
|
172
|
-
multi_dimensional_array?(node, token) &&
|
172
|
+
multi_dimensional_array?(node, token) && token.space_before?
|
173
173
|
else
|
174
|
-
multi_dimensional_array?(node, token, side: :left) &&
|
175
|
-
!next_to_bracket?(token, side: :left)
|
174
|
+
multi_dimensional_array?(node, token, side: :left) && token.space_after?
|
176
175
|
end
|
177
176
|
end
|
178
177
|
|
179
178
|
def multi_dimensional_array?(node, token, side: :right)
|
180
|
-
|
179
|
+
offset = side == :right ? -1 : +1
|
180
|
+
i = index_for(node, token) + offset
|
181
|
+
# TODO: change this type check once
|
182
|
+
# https://github.com/rubocop/rubocop-ast/pull/240 is merged
|
183
|
+
i += offset while processed_source.tokens_within(node)[i].new_line?
|
181
184
|
if side == :right
|
182
|
-
processed_source.tokens_within(node)[i
|
185
|
+
processed_source.tokens_within(node)[i].right_bracket?
|
183
186
|
else
|
184
|
-
processed_source.tokens_within(node)[i
|
187
|
+
processed_source.tokens_within(node)[i].left_array_bracket?
|
185
188
|
end
|
186
189
|
end
|
187
190
|
|
@@ -200,12 +203,13 @@ module RuboCop
|
|
200
203
|
end
|
201
204
|
|
202
205
|
def compact_corrections(corrector, node, left, right)
|
203
|
-
if
|
206
|
+
if multi_dimensional_array?(node, left, side: :left)
|
204
207
|
compact(corrector, left, :right)
|
205
208
|
elsif !left.space_after?
|
206
209
|
corrector.insert_after(left.pos, ' ')
|
207
210
|
end
|
208
|
-
|
211
|
+
|
212
|
+
if multi_dimensional_array?(node, right)
|
209
213
|
compact(corrector, right, :left)
|
210
214
|
elsif !right.space_before?
|
211
215
|
corrector.insert_before(right.pos, ' ')
|
@@ -213,7 +217,7 @@ module RuboCop
|
|
213
217
|
end
|
214
218
|
|
215
219
|
def compact(corrector, bracket, side)
|
216
|
-
range = side_space_range(range: bracket.pos, side: side)
|
220
|
+
range = side_space_range(range: bracket.pos, side: side, include_newlines: true)
|
217
221
|
corrector.remove(range)
|
218
222
|
end
|
219
223
|
end
|
@@ -131,7 +131,7 @@ module RuboCop
|
|
131
131
|
args_delimiter = node.arguments.loc.begin if node.block_type? # Can be ( | or nil.
|
132
132
|
|
133
133
|
check_left_brace(inner, node.loc.begin, args_delimiter)
|
134
|
-
check_right_brace(inner, node.loc.begin, node.loc.end, node.single_line?)
|
134
|
+
check_right_brace(node, inner, node.loc.begin, node.loc.end, node.single_line?)
|
135
135
|
end
|
136
136
|
|
137
137
|
def check_left_brace(inner, left_brace, args_delimiter)
|
@@ -142,14 +142,15 @@ module RuboCop
|
|
142
142
|
end
|
143
143
|
end
|
144
144
|
|
145
|
-
def check_right_brace(inner, left_brace, right_brace, single_line)
|
145
|
+
def check_right_brace(node, inner, left_brace, right_brace, single_line)
|
146
146
|
if single_line && /\S$/.match?(inner)
|
147
147
|
no_space(right_brace.begin_pos, right_brace.end_pos, 'Space missing inside }.')
|
148
148
|
else
|
149
|
+
column = node.loc.expression.column
|
149
150
|
return if multiline_block?(left_brace, right_brace) &&
|
150
|
-
aligned_braces?(
|
151
|
+
aligned_braces?(inner, right_brace, column)
|
151
152
|
|
152
|
-
space_inside_right_brace(right_brace)
|
153
|
+
space_inside_right_brace(inner, right_brace, column)
|
153
154
|
end
|
154
155
|
end
|
155
156
|
|
@@ -157,8 +158,12 @@ module RuboCop
|
|
157
158
|
left_brace.first_line != right_brace.first_line
|
158
159
|
end
|
159
160
|
|
160
|
-
def aligned_braces?(
|
161
|
-
|
161
|
+
def aligned_braces?(inner, right_brace, column)
|
162
|
+
column == right_brace.column || column == inner_last_space_count(inner)
|
163
|
+
end
|
164
|
+
|
165
|
+
def inner_last_space_count(inner)
|
166
|
+
inner.split("\n").last.count(' ')
|
162
167
|
end
|
163
168
|
|
164
169
|
def no_space_inside_left_brace(left_brace, args_delimiter)
|
@@ -197,10 +202,21 @@ module RuboCop
|
|
197
202
|
args_delimiter&.is?('|')
|
198
203
|
end
|
199
204
|
|
200
|
-
def space_inside_right_brace(right_brace)
|
205
|
+
def space_inside_right_brace(inner, right_brace, column)
|
201
206
|
brace_with_space = range_with_surrounding_space(right_brace, side: :left)
|
202
|
-
|
203
|
-
|
207
|
+
begin_pos = brace_with_space.begin_pos
|
208
|
+
end_pos = brace_with_space.end_pos - 1
|
209
|
+
|
210
|
+
if brace_with_space.source.match?(/\R/)
|
211
|
+
begin_pos = end_pos - (right_brace.column - column)
|
212
|
+
end
|
213
|
+
|
214
|
+
if inner.end_with?(']')
|
215
|
+
end_pos -= 1
|
216
|
+
begin_pos = end_pos - (inner_last_space_count(inner) - column)
|
217
|
+
end
|
218
|
+
|
219
|
+
space(begin_pos, end_pos, 'Space inside } detected.')
|
204
220
|
end
|
205
221
|
|
206
222
|
def no_space(begin_pos, end_pos, msg)
|
@@ -46,10 +46,13 @@ module RuboCop
|
|
46
46
|
# # bad
|
47
47
|
# foo = { }
|
48
48
|
# bar = { }
|
49
|
+
# baz = {
|
50
|
+
# }
|
49
51
|
#
|
50
52
|
# # good
|
51
53
|
# foo = {}
|
52
54
|
# bar = {}
|
55
|
+
# baz = {}
|
53
56
|
#
|
54
57
|
# @example EnforcedStyleForEmptyBraces: space
|
55
58
|
# # The `space` EnforcedStyleForEmptyBraces style enforces that
|
@@ -60,8 +63,9 @@ module RuboCop
|
|
60
63
|
#
|
61
64
|
# # good
|
62
65
|
# foo = { }
|
63
|
-
# foo = {
|
64
|
-
# foo = {
|
66
|
+
# foo = { }
|
67
|
+
# foo = {
|
68
|
+
# }
|
65
69
|
#
|
66
70
|
class SpaceInsideHashLiteralBraces < Base
|
67
71
|
include SurroundingSpace
|
@@ -77,6 +81,7 @@ module RuboCop
|
|
77
81
|
|
78
82
|
check(tokens[0], tokens[1])
|
79
83
|
check(tokens[-2], tokens[-1]) if tokens.size > 2
|
84
|
+
check_whitespace_only_hash(node) if enforce_no_space_style_for_empty_braces?
|
80
85
|
end
|
81
86
|
|
82
87
|
private
|
@@ -103,7 +108,7 @@ module RuboCop
|
|
103
108
|
if is_same_braces && style == :compact
|
104
109
|
false
|
105
110
|
elsif is_empty_braces
|
106
|
-
|
111
|
+
!enforce_no_space_style_for_empty_braces?
|
107
112
|
else
|
108
113
|
style != :no_space
|
109
114
|
end
|
@@ -175,6 +180,26 @@ module RuboCop
|
|
175
180
|
|
176
181
|
range_between(begin_pos, range.end_pos - 1)
|
177
182
|
end
|
183
|
+
|
184
|
+
def check_whitespace_only_hash(node)
|
185
|
+
range = range_inside_hash(node)
|
186
|
+
return unless range.source.match?(/\A\s+\z/m)
|
187
|
+
|
188
|
+
add_offense(
|
189
|
+
range,
|
190
|
+
message: format(MSG, problem: 'empty hash literal braces detected')
|
191
|
+
) do |corrector|
|
192
|
+
corrector.remove(range)
|
193
|
+
end
|
194
|
+
end
|
195
|
+
|
196
|
+
def range_inside_hash(node)
|
197
|
+
range_between(node.location.begin.end_pos, node.location.end.begin_pos)
|
198
|
+
end
|
199
|
+
|
200
|
+
def enforce_no_space_style_for_empty_braces?
|
201
|
+
cop_config['EnforcedStyleForEmptyBraces'] == 'no_space'
|
202
|
+
end
|
178
203
|
end
|
179
204
|
end
|
180
205
|
end
|
@@ -45,7 +45,7 @@ module RuboCop
|
|
45
45
|
# # bad
|
46
46
|
# expect { do_something }.to change { object.attribute }
|
47
47
|
#
|
48
|
-
# @example AllowedPatterns: [
|
48
|
+
# @example AllowedPatterns: ['change']
|
49
49
|
#
|
50
50
|
# # good
|
51
51
|
# expect { do_something }.to change { object.attribute }
|
@@ -81,7 +81,7 @@ module RuboCop
|
|
81
81
|
def allowed_method_pattern?(node)
|
82
82
|
node.assignment? || node.operator_method? || node.method?(:[]) ||
|
83
83
|
allowed_method?(node.last_argument.method_name) ||
|
84
|
-
matches_allowed_pattern?(node.last_argument.
|
84
|
+
matches_allowed_pattern?(node.last_argument.send_node.source)
|
85
85
|
end
|
86
86
|
|
87
87
|
def message(send_node)
|
@@ -0,0 +1,73 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Lint
|
6
|
+
# Checks for duplicated magic comments.
|
7
|
+
#
|
8
|
+
# @example
|
9
|
+
#
|
10
|
+
# # bad
|
11
|
+
#
|
12
|
+
# # encoding: ascii
|
13
|
+
# # encoding: ascii
|
14
|
+
#
|
15
|
+
# # good
|
16
|
+
#
|
17
|
+
# # encoding: ascii
|
18
|
+
#
|
19
|
+
# # bad
|
20
|
+
#
|
21
|
+
# # frozen_string_literal: true
|
22
|
+
# # frozen_string_literal: true
|
23
|
+
#
|
24
|
+
# # good
|
25
|
+
#
|
26
|
+
# # frozen_string_literal: true
|
27
|
+
#
|
28
|
+
class DuplicateMagicComment < Base
|
29
|
+
include FrozenStringLiteral
|
30
|
+
include RangeHelp
|
31
|
+
extend AutoCorrector
|
32
|
+
|
33
|
+
MSG = 'Duplicate magic comment detected.'
|
34
|
+
|
35
|
+
def on_new_investigation
|
36
|
+
return if processed_source.buffer.source.empty?
|
37
|
+
|
38
|
+
magic_comment_lines.each_value do |comment_lines|
|
39
|
+
next if comment_lines.count <= 1
|
40
|
+
|
41
|
+
comment_lines[1..].each do |comment_line|
|
42
|
+
range = processed_source.buffer.line_range(comment_line + 1)
|
43
|
+
|
44
|
+
register_offense(range)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
private
|
50
|
+
|
51
|
+
def magic_comment_lines
|
52
|
+
comment_lines = { encoding_magic_comments: [], frozen_string_literal_magic_comments: [] }
|
53
|
+
|
54
|
+
leading_magic_comments.each.with_index do |magic_comment, index|
|
55
|
+
if magic_comment.encoding_specified?
|
56
|
+
comment_lines[:encoding_magic_comments] << index
|
57
|
+
elsif magic_comment.frozen_string_literal_specified?
|
58
|
+
comment_lines[:frozen_string_literal_magic_comments] << index
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
comment_lines
|
63
|
+
end
|
64
|
+
|
65
|
+
def register_offense(range)
|
66
|
+
add_offense(range) do |corrector|
|
67
|
+
corrector.remove(range_by_whole_lines(range, include_final_newline: true))
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
@@ -133,7 +133,7 @@ module RuboCop
|
|
133
133
|
end
|
134
134
|
|
135
135
|
def found_instance_method(node, name)
|
136
|
-
return unless (scope = node.parent_module_name)
|
136
|
+
return found_sclass_method(node, name) unless (scope = node.parent_module_name)
|
137
137
|
|
138
138
|
# Humanize the scope
|
139
139
|
scope = scope.sub(
|
@@ -145,6 +145,16 @@ module RuboCop
|
|
145
145
|
found_method(node, "#{scope}#{name}")
|
146
146
|
end
|
147
147
|
|
148
|
+
def found_sclass_method(node, name)
|
149
|
+
singleton_ancestor = node.each_ancestor.find(&:sclass_type?)
|
150
|
+
return unless singleton_ancestor
|
151
|
+
|
152
|
+
singleton_receiver_node = singleton_ancestor.children[0]
|
153
|
+
return unless singleton_receiver_node.send_type?
|
154
|
+
|
155
|
+
found_method(node, "#{singleton_receiver_node.method_name}.#{name}")
|
156
|
+
end
|
157
|
+
|
148
158
|
def found_method(node, method_name)
|
149
159
|
if @definitions.key?(method_name)
|
150
160
|
loc = case node.type
|
@@ -32,26 +32,40 @@ module RuboCop
|
|
32
32
|
end
|
33
33
|
end
|
34
34
|
|
35
|
+
# rubocop:disable Metrics/AbcSize, Metrics/MethodLength
|
35
36
|
def each_repeated_character_class_element_loc(node)
|
36
37
|
node.parsed_tree&.each_expression do |expr|
|
37
|
-
next if expr
|
38
|
+
next if skip_expression?(expr)
|
38
39
|
|
39
40
|
seen = Set.new
|
41
|
+
enum = expr.expressions.to_enum
|
42
|
+
expression_count = expr.expressions.count
|
40
43
|
|
41
|
-
|
42
|
-
|
44
|
+
expression_count.times do |current_number|
|
45
|
+
current_child = enum.next
|
46
|
+
next if within_interpolation?(node, current_child)
|
43
47
|
|
44
|
-
|
48
|
+
current_child_source = current_child.to_s
|
49
|
+
next_child = enum.peek if current_number + 1 < expression_count
|
45
50
|
|
46
|
-
|
51
|
+
if seen.include?(current_child_source)
|
52
|
+
next if start_with_escaped_zero_number?(current_child_source, next_child.to_s)
|
47
53
|
|
48
|
-
|
54
|
+
yield current_child.expression
|
55
|
+
end
|
56
|
+
|
57
|
+
seen << current_child_source
|
49
58
|
end
|
50
59
|
end
|
51
60
|
end
|
61
|
+
# rubocop:enable Metrics/AbcSize, Metrics/MethodLength
|
52
62
|
|
53
63
|
private
|
54
64
|
|
65
|
+
def skip_expression?(expr)
|
66
|
+
expr.type != :set || expr.token == :intersection
|
67
|
+
end
|
68
|
+
|
55
69
|
# Since we blank interpolations with a space for every char of the interpolation, we would
|
56
70
|
# mark every space (except the first) as duplicate if we do not skip regexp_parser nodes
|
57
71
|
# that are within an interpolation.
|
@@ -61,6 +75,11 @@ module RuboCop
|
|
61
75
|
interpolation_locs(node).any? { |il| il.overlaps?(parse_tree_child_loc) }
|
62
76
|
end
|
63
77
|
|
78
|
+
def start_with_escaped_zero_number?(current_child, next_child)
|
79
|
+
# Represents escaped code from `"\00"` (`"\u0000"`) to `"\07"` (`"\a"`).
|
80
|
+
current_child == '\\0' && next_child.match?(/[0-7]/)
|
81
|
+
end
|
82
|
+
|
64
83
|
def interpolation_locs(node)
|
65
84
|
@interpolation_locs ||= {}
|
66
85
|
|
@@ -85,7 +85,9 @@ module RuboCop
|
|
85
85
|
private
|
86
86
|
|
87
87
|
def body_or_allowed_comment_lines?(node)
|
88
|
-
|
88
|
+
return true if node.body
|
89
|
+
|
90
|
+
cop_config['AllowComments'] && processed_source.contains_comment?(node.source_range)
|
89
91
|
end
|
90
92
|
end
|
91
93
|
end
|