rubocop 1.35.1 → 1.37.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.
Files changed (85) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/config/default.yml +32 -1
  4. data/lib/rubocop/arguments_env.rb +17 -0
  5. data/lib/rubocop/arguments_file.rb +17 -0
  6. data/lib/rubocop/cli/command/execute_runner.rb +7 -7
  7. data/lib/rubocop/cop/generator.rb +1 -2
  8. data/lib/rubocop/cop/layout/block_alignment.rb +14 -12
  9. data/lib/rubocop/cop/layout/first_argument_indentation.rb +1 -0
  10. data/lib/rubocop/cop/layout/indentation_width.rb +4 -2
  11. data/lib/rubocop/cop/layout/space_inside_array_literal_brackets.rb +13 -9
  12. data/lib/rubocop/cop/layout/space_inside_block_braces.rb +25 -9
  13. data/lib/rubocop/cop/layout/space_inside_hash_literal_braces.rb +28 -3
  14. data/lib/rubocop/cop/lint/ambiguous_block_association.rb +2 -2
  15. data/lib/rubocop/cop/lint/duplicate_magic_comment.rb +73 -0
  16. data/lib/rubocop/cop/lint/duplicate_methods.rb +11 -1
  17. data/lib/rubocop/cop/lint/duplicate_regexp_character_class_element.rb +25 -6
  18. data/lib/rubocop/cop/lint/duplicate_require.rb +1 -1
  19. data/lib/rubocop/cop/lint/empty_class.rb +3 -1
  20. data/lib/rubocop/cop/lint/empty_conditional_body.rb +46 -4
  21. data/lib/rubocop/cop/lint/nested_method_definition.rb +50 -1
  22. data/lib/rubocop/cop/lint/number_conversion.rb +1 -1
  23. data/lib/rubocop/cop/lint/ordered_magic_comments.rb +4 -5
  24. data/lib/rubocop/cop/lint/out_of_range_regexp_ref.rb +1 -1
  25. data/lib/rubocop/cop/lint/redundant_cop_disable_directive.rb +12 -1
  26. data/lib/rubocop/cop/lint/redundant_dir_glob_sort.rb +7 -0
  27. data/lib/rubocop/cop/lint/redundant_require_statement.rb +29 -9
  28. data/lib/rubocop/cop/lint/require_parentheses.rb +1 -1
  29. data/lib/rubocop/cop/lint/safe_navigation_chain.rb +3 -2
  30. data/lib/rubocop/cop/lint/shadowed_exception.rb +1 -11
  31. data/lib/rubocop/cop/lint/shadowing_outer_local_variable.rb +17 -2
  32. data/lib/rubocop/cop/lint/unreachable_loop.rb +2 -2
  33. data/lib/rubocop/cop/lint/unused_method_argument.rb +4 -0
  34. data/lib/rubocop/cop/lint/useless_access_modifier.rb +2 -2
  35. data/lib/rubocop/cop/lint/useless_ruby2_keywords.rb +1 -1
  36. data/lib/rubocop/cop/mixin/allowed_methods.rb +10 -5
  37. data/lib/rubocop/cop/mixin/allowed_pattern.rb +13 -5
  38. data/lib/rubocop/cop/mixin/comments_help.rb +12 -0
  39. data/lib/rubocop/cop/mixin/frozen_string_literal.rb +4 -0
  40. data/lib/rubocop/cop/mixin/hash_shorthand_syntax.rb +6 -3
  41. data/lib/rubocop/cop/mixin/hash_transform_method.rb +9 -5
  42. data/lib/rubocop/cop/mixin/rescue_node.rb +3 -1
  43. data/lib/rubocop/cop/mixin/surrounding_space.rb +6 -5
  44. data/lib/rubocop/cop/naming/inclusive_language.rb +1 -1
  45. data/lib/rubocop/cop/style/access_modifier_declarations.rb +97 -1
  46. data/lib/rubocop/cop/style/accessor_grouping.rb +7 -3
  47. data/lib/rubocop/cop/style/block_delimiters.rb +1 -1
  48. data/lib/rubocop/cop/style/case_equality.rb +40 -10
  49. data/lib/rubocop/cop/style/class_equality_comparison.rb +1 -1
  50. data/lib/rubocop/cop/style/collection_compact.rb +6 -1
  51. data/lib/rubocop/cop/style/each_for_simple_loop.rb +40 -5
  52. data/lib/rubocop/cop/style/empty_method.rb +1 -1
  53. data/lib/rubocop/cop/style/endless_method.rb +1 -1
  54. data/lib/rubocop/cop/style/explicit_block_argument.rb +4 -0
  55. data/lib/rubocop/cop/style/format_string_token.rb +1 -1
  56. data/lib/rubocop/cop/style/hash_syntax.rb +1 -1
  57. data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +13 -2
  58. data/lib/rubocop/cop/style/negated_if_else_condition.rb +7 -1
  59. data/lib/rubocop/cop/style/numeric_predicate.rb +1 -1
  60. data/lib/rubocop/cop/style/operator_method_call.rb +39 -0
  61. data/lib/rubocop/cop/style/perl_backrefs.rb +22 -1
  62. data/lib/rubocop/cop/style/redundant_begin.rb +1 -0
  63. data/lib/rubocop/cop/style/redundant_condition.rb +5 -2
  64. data/lib/rubocop/cop/style/redundant_initialize.rb +3 -1
  65. data/lib/rubocop/cop/style/redundant_parentheses.rb +4 -0
  66. data/lib/rubocop/cop/style/redundant_regexp_character_class.rb +8 -1
  67. data/lib/rubocop/cop/style/redundant_string_escape.rb +173 -0
  68. data/lib/rubocop/cop/style/rescue_modifier.rb +1 -1
  69. data/lib/rubocop/cop/style/static_class.rb +32 -1
  70. data/lib/rubocop/cop/style/symbol_array.rb +2 -0
  71. data/lib/rubocop/cop/style/symbol_proc.rb +6 -5
  72. data/lib/rubocop/cop/style/word_array.rb +2 -0
  73. data/lib/rubocop/formatter/disabled_config_formatter.rb +8 -2
  74. data/lib/rubocop/options.rb +13 -13
  75. data/lib/rubocop/rspec/shared_contexts.rb +13 -1
  76. data/lib/rubocop/runner.rb +4 -0
  77. data/lib/rubocop/server/cache.rb +5 -1
  78. data/lib/rubocop/server/cli.rb +9 -2
  79. data/lib/rubocop/server/client_command/exec.rb +5 -0
  80. data/lib/rubocop/server/core.rb +2 -1
  81. data/lib/rubocop/server/socket_reader.rb +5 -1
  82. data/lib/rubocop/server.rb +1 -1
  83. data/lib/rubocop/version.rb +8 -2
  84. data/lib/rubocop.rb +3 -0
  85. metadata +10 -5
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 52ce553282d97fbec24636f7104e3c1c1ceb32b27610542ae22470d84a6421ce
4
- data.tar.gz: 6176cfc6699491e9d755e323a813964c1dd244a16d61ad2545e93f8109d69fa6
3
+ metadata.gz: e928a8547def9cafd9cddc36b5a407aef7d46fdf9825941c7906073492d88668
4
+ data.tar.gz: 3ef9727850f93815ba310b7c3a8cf74e53a0ee18a0fcf6731fd97a3640ffe28d
5
5
  SHA512:
6
- metadata.gz: 69e648784e186575033e4f8b65be6f5fb8f456e557d597e5321bbe0f70d9aef39b0a4c974347d13498b5e88c664177b72aae809b5f39bec98292cb0e7a4fb18a
7
- data.tar.gz: 866c506305659953fe31ea005c51d936dcfed82429e7582f7d64daab5ea5b077ef1fb619f7932c204749582dc1bec695e090c32d5b81450984d30e7a2e3125b4
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.35', require: false
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 "always", but will avoid mixing styles in a single hash
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.dup
45
- $stdout.reopen($stderr)
46
-
47
- result = yield
48
-
49
- $stdout.reopen(orig_stdout)
50
- result
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
- # .each do
26
- # baz
27
- # end
25
+ # .each do
26
+ # baz
27
+ # end
28
28
  #
29
29
  # # good
30
30
  #
31
- # variable = lambda do |i|
32
- # i
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
- # .each do
40
- # baz
41
- # end
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
- # .each do
55
- # baz
56
- # end
55
+ # .each do
56
+ # baz
57
+ # end
57
58
  #
58
59
  # # good
59
60
  #
60
61
  # foo.bar
61
62
  # .each do
62
- # baz
63
+ # baz
63
64
  # end
65
+ #
64
66
  class BlockAlignment < Base
65
67
  include ConfigurableEnforcedStyle
66
68
  include RangeHelp
@@ -162,6 +162,7 @@ module RuboCop
162
162
  check_alignment([node.first_argument], indent)
163
163
  end
164
164
  alias on_csend on_send
165
+ alias on_super on_send
165
166
 
166
167
  private
167
168
 
@@ -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
- check_indentation(case_match.in_pattern_branches.last.loc.keyword, case_match.else_branch)
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 ignored_line?(base_loc)
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) && !next_to_bracket?(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
- i = index_for(node, token)
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 - 1].right_bracket?
185
+ processed_source.tokens_within(node)[i].right_bracket?
183
186
  else
184
- processed_source.tokens_within(node)[i + 1].left_array_bracket?
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 qualifies_for_compact?(node, left, side: :left)
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
- if qualifies_for_compact?(node, right)
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?(left_brace, right_brace)
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?(left_brace, right_brace)
161
- left_brace.first_line == right_brace.last_column
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
- space(brace_with_space.begin_pos, brace_with_space.end_pos - 1,
203
- 'Space inside } detected.')
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
- cop_config['EnforcedStyleForEmptyBraces'] != 'no_space'
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: [/change/]
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.method_name)
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.type != :set || expr.token == :intersection
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
- expr.expressions.each do |child|
42
- next if within_interpolation?(node, child)
44
+ expression_count.times do |current_number|
45
+ current_child = enum.next
46
+ next if within_interpolation?(node, current_child)
43
47
 
44
- child_source = child.to_s
48
+ current_child_source = current_child.to_s
49
+ next_child = enum.peek if current_number + 1 < expression_count
45
50
 
46
- yield child.expression if seen.include?(child_source)
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
- seen << child_source
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
 
@@ -3,7 +3,7 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Lint
6
- # Checks for duplicate `require`s and `require_relative`s.
6
+ # Checks for duplicate ``require``s and ``require_relative``s.
7
7
  #
8
8
  # @safety
9
9
  # This cop's autocorrection is unsafe because it may break the dependency order
@@ -85,7 +85,9 @@ module RuboCop
85
85
  private
86
86
 
87
87
  def body_or_allowed_comment_lines?(node)
88
- node.body || (cop_config['AllowComments'] && comment_lines?(node))
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