rubocop 0.60.0 → 0.61.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 (63) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +4 -4
  3. data/config/default.yml +573 -560
  4. data/lib/rubocop.rb +5 -0
  5. data/lib/rubocop/ast/node.rb +1 -1
  6. data/lib/rubocop/ast/sexp.rb +1 -1
  7. data/lib/rubocop/cli.rb +9 -14
  8. data/lib/rubocop/config.rb +4 -3
  9. data/lib/rubocop/config_loader.rb +25 -22
  10. data/lib/rubocop/config_loader_resolver.rb +3 -2
  11. data/lib/rubocop/cop/correctors/each_to_for_corrector.rb +53 -0
  12. data/lib/rubocop/cop/correctors/for_to_each_corrector.rb +73 -0
  13. data/lib/rubocop/cop/correctors/lambda_literal_to_method_corrector.rb +138 -0
  14. data/lib/rubocop/cop/correctors/multiline_literal_brace_corrector.rb +52 -46
  15. data/lib/rubocop/cop/generator.rb +13 -17
  16. data/lib/rubocop/cop/generator/configuration_injector.rb +60 -0
  17. data/lib/rubocop/cop/layout/align_hash.rb +3 -0
  18. data/lib/rubocop/cop/layout/comment_indentation.rb +32 -2
  19. data/lib/rubocop/cop/layout/indent_heredoc.rb +11 -5
  20. data/lib/rubocop/cop/layout/indentation_width.rb +7 -1
  21. data/lib/rubocop/cop/layout/multiline_array_brace_layout.rb +11 -11
  22. data/lib/rubocop/cop/layout/multiline_hash_brace_layout.rb +1 -1
  23. data/lib/rubocop/cop/layout/multiline_method_call_brace_layout.rb +1 -1
  24. data/lib/rubocop/cop/layout/multiline_method_definition_brace_layout.rb +1 -1
  25. data/lib/rubocop/cop/layout/rescue_ensure_alignment.rb +16 -3
  26. data/lib/rubocop/cop/layout/space_around_block_parameters.rb +30 -17
  27. data/lib/rubocop/cop/lint/format_parameter_mismatch.rb +11 -0
  28. data/lib/rubocop/cop/lint/shadowed_exception.rb +2 -5
  29. data/lib/rubocop/cop/lint/useless_access_modifier.rb +1 -1
  30. data/lib/rubocop/cop/metrics/line_length.rb +2 -2
  31. data/lib/rubocop/cop/mixin/trailing_comma.rb +11 -15
  32. data/lib/rubocop/cop/offense.rb +1 -1
  33. data/lib/rubocop/cop/performance/open_struct.rb +46 -0
  34. data/lib/rubocop/cop/performance/redundant_merge.rb +18 -4
  35. data/lib/rubocop/cop/rails/bulk_change_table.rb +2 -2
  36. data/lib/rubocop/cop/rails/dynamic_find_by.rb +15 -8
  37. data/lib/rubocop/cop/rails/http_positional_arguments.rb +17 -14
  38. data/lib/rubocop/cop/rails/http_status.rb +4 -4
  39. data/lib/rubocop/cop/rails/inverse_of.rb +2 -2
  40. data/lib/rubocop/cop/rails/reversible_migration.rb +1 -1
  41. data/lib/rubocop/cop/rails/skips_model_validations.rb +1 -1
  42. data/lib/rubocop/cop/rails/validation.rb +4 -4
  43. data/lib/rubocop/cop/security/open.rb +31 -11
  44. data/lib/rubocop/cop/style/begin_block.rb +6 -0
  45. data/lib/rubocop/cop/style/braces_around_hash_parameters.rb +1 -1
  46. data/lib/rubocop/cop/style/empty_case_condition.rb +13 -7
  47. data/lib/rubocop/cop/style/for.rb +9 -78
  48. data/lib/rubocop/cop/style/frozen_string_literal_comment.rb +6 -4
  49. data/lib/rubocop/cop/style/global_vars.rb +1 -1
  50. data/lib/rubocop/cop/style/infinite_loop.rb +42 -6
  51. data/lib/rubocop/cop/style/lambda.rb +4 -87
  52. data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +221 -16
  53. data/lib/rubocop/cop/style/raise_args.rb +1 -1
  54. data/lib/rubocop/cop/style/regexp_literal.rb +62 -10
  55. data/lib/rubocop/cop/style/unneeded_condition.rb +2 -2
  56. data/lib/rubocop/cop/variable_force.rb +4 -2
  57. data/lib/rubocop/cop/variable_force/variable.rb +2 -0
  58. data/lib/rubocop/magic_comment.rb +1 -1
  59. data/lib/rubocop/remote_config.rb +13 -4
  60. data/lib/rubocop/rspec/expect_offense.rb +1 -1
  61. data/lib/rubocop/runner.rb +15 -4
  62. data/lib/rubocop/version.rb +1 -1
  63. metadata +7 -2
@@ -3,11 +3,26 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Style
6
- # This cop checks presence of parentheses in method calls containing
7
- # parameters. By default, macro methods are ignored. Additional methods
8
- # can be added to the `IgnoredMethods` list.
6
+ # This cop enforces the presence (default) or absence of parentheses in
7
+ # method calls containing parameters.
8
+ #
9
+ # In the default style (require_parentheses), macro methods are ignored.
10
+ # Additional methods can be added to the `IgnoredMethods` list. This
11
+ # option is valid only in the default style.
12
+ #
13
+ # In the alternative style (omit_parentheses), there are two additional
14
+ # options.
15
+ #
16
+ # 1. `AllowParenthesesInChaining` is `false` by default. Setting it to
17
+ # `true` allows the presence of parentheses in the last call during
18
+ # method chaining.
19
+ #
20
+ # 2. `AllowParenthesesInMultilineCall` is `false` by default. Setting it
21
+ # to `true` allows the presence of parentheses in multi-line method
22
+ # calls.
23
+ #
24
+ # @example EnforcedStyle: require_parentheses
9
25
  #
10
- # @example
11
26
  #
12
27
  # # bad
13
28
  # array.delete e
@@ -39,21 +54,114 @@ module RuboCop
39
54
  # class Foo
40
55
  # bar :baz
41
56
  # end
57
+ #
58
+ # @example EnforcedStyle: omit_parentheses
59
+ #
60
+ # # bad
61
+ # array.delete(e)
62
+ #
63
+ # # good
64
+ # array.delete e
65
+ #
66
+ # # bad
67
+ # foo.enforce(strict: true)
68
+ #
69
+ # # good
70
+ # foo.enforce strict: true
71
+ #
72
+ # # AllowParenthesesInMultilineCall: false (default)
73
+ #
74
+ # # bad
75
+ # foo.enforce(
76
+ # strict: true
77
+ # )
78
+ #
79
+ # # good
80
+ # foo.enforce \
81
+ # strict: true
82
+ #
83
+ # # AllowParenthesesInMultilineCall: true
84
+ #
85
+ # # good
86
+ # foo.enforce(
87
+ # strict: true
88
+ # )
89
+ #
90
+ # # good
91
+ # foo.enforce \
92
+ # strict: true
93
+ #
94
+ # # AllowParenthesesInChaining: false (default)
95
+ #
96
+ # # bad
97
+ # foo().bar(1)
98
+ #
99
+ # # good
100
+ # foo().bar 1
101
+ #
102
+ # # AllowParenthesesInChaining: true
103
+ #
104
+ # # good
105
+ # foo().bar(1)
106
+ #
107
+ # # good
108
+ # foo().bar 1
42
109
  class MethodCallWithArgsParentheses < Cop
110
+ include ConfigurableEnforcedStyle
43
111
  include IgnoredMethods
44
112
 
45
- MSG = 'Use parentheses for method calls with arguments.'.freeze
113
+ TRAILING_WHITESPACE_REGEX = /\s+\Z/.freeze
46
114
 
47
115
  def on_send(node)
48
- return if ignored_method?(node)
49
- return unless node.arguments? && !node.parenthesized?
50
-
51
- add_offense(node)
116
+ case style
117
+ when :require_parentheses
118
+ add_offense_for_require_parentheses(node)
119
+ when :omit_parentheses
120
+ add_offense_for_omit_parentheses(node)
121
+ end
52
122
  end
53
123
  alias on_super on_send
54
124
  alias on_yield on_send
55
125
 
56
126
  def autocorrect(node)
127
+ case style
128
+ when :require_parentheses
129
+ autocorrect_for_require_parentheses(node)
130
+ when :omit_parentheses
131
+ autocorrect_for_omit_parentheses(node)
132
+ end
133
+ end
134
+
135
+ def message(_node = nil)
136
+ case style
137
+ when :require_parentheses
138
+ 'Use parentheses for method calls with arguments.'.freeze
139
+ when :omit_parentheses
140
+ 'Omit parentheses for method calls with arguments.'.freeze
141
+ end
142
+ end
143
+
144
+ private
145
+
146
+ def add_offense_for_require_parentheses(node)
147
+ return if ignored_method?(node.method_name)
148
+ return if eligible_for_parentheses_omission?(node)
149
+ return unless node.arguments? && !node.parenthesized?
150
+
151
+ add_offense(node)
152
+ end
153
+
154
+ def add_offense_for_omit_parentheses(node)
155
+ return unless node.parenthesized?
156
+ return if node.implicit_call?
157
+ return if super_call_without_arguments?(node)
158
+ return if camel_case_method_call_without_arguments?(node)
159
+ return if eligible_for_parentheses_presence?(node)
160
+
161
+ add_offense(node, location: node.loc.begin.join(node.loc.end))
162
+ end
163
+
164
+ def autocorrect_for_require_parentheses(node)
57
165
  lambda do |corrector|
58
166
  corrector.replace(args_begin(node), '(')
59
167
 
@@ -63,16 +171,23 @@ module RuboCop
63
171
  end
64
172
  end
65
173
 
66
- private
174
+ def autocorrect_for_omit_parentheses(node)
175
+ lambda do |corrector|
176
+ if parentheses_at_the_end_of_multiline_call?(node)
177
+ corrector.replace(args_begin(node), ' \\')
178
+ else
179
+ corrector.replace(args_begin(node), ' ')
180
+ end
181
+ corrector.remove(node.loc.end)
182
+ end
183
+ end
67
184
 
68
- def ignored_method?(node)
69
- node.operator_method? || node.setter_method? ||
70
- ignore_macros? && node.macro? ||
71
- super(node.method_name)
185
+ def eligible_for_parentheses_omission?(node)
186
+ node.operator_method? || node.setter_method? || ignore_macros?(node)
72
187
  end
73
188
 
74
- def ignore_macros?
75
- cop_config['IgnoreMacros']
189
+ def ignore_macros?(node)
190
+ cop_config['IgnoreMacros'] && node.macro?
76
191
  end
77
192
 
78
193
  def args_begin(node)
@@ -94,6 +209,96 @@ module RuboCop
94
209
  first_node = node.arguments.first
95
210
  first_node.begin_type? && first_node.parenthesized_call?
96
211
  end
212
+
213
+ def parentheses_at_the_end_of_multiline_call?(node)
214
+ node.multiline? &&
215
+ node.loc.begin.source_line
216
+ .gsub(TRAILING_WHITESPACE_REGEX, '')
217
+ .end_with?('(')
218
+ end
219
+
220
+ def super_call_without_arguments?(node)
221
+ node.super_type? && node.arguments.none?
222
+ end
223
+
224
+ def camel_case_method_call_without_arguments?(node)
225
+ node.camel_case_method? && node.arguments.none?
226
+ end
227
+
228
+ def eligible_for_parentheses_presence?(node)
229
+ call_in_literals?(node) ||
230
+ call_with_ambiguous_arguments?(node) ||
231
+ call_in_logical_operators?(node) ||
232
+ allowed_multiline_call_with_parentheses?(node) ||
233
+ allowed_chained_call_with_parentheses?(node)
234
+ end
235
+
236
+ def call_in_literals?(node)
237
+ node.parent &&
238
+ (node.parent.pair_type? ||
239
+ node.parent.array_type? ||
240
+ ternary_if?(node.parent))
241
+ end
242
+
243
+ def call_in_logical_operators?(node)
244
+ node.parent &&
245
+ (logical_operator?(node.parent) ||
246
+ node.parent.descendants.any?(&method(:logical_operator?)))
247
+ end
248
+
249
+ def call_with_ambiguous_arguments?(node)
250
+ call_with_braced_block?(node) ||
251
+ call_as_argument?(node) ||
252
+ hash_literal_in_arguments?(node) ||
253
+ node.descendants.any? do |n|
254
+ splat?(n) || ternary_if?(n) || logical_operator?(n)
255
+ end
256
+ end
257
+
258
+ def call_with_braced_block?(node)
259
+ node.block_node && node.block_node.braces?
260
+ end
261
+
262
+ def call_as_argument?(node)
263
+ node.parent && node.parent.send_type?
264
+ end
265
+
266
+ def hash_literal_in_arguments?(node)
267
+ node.arguments.any? do |n|
268
+ hash_literal?(n) ||
269
+ n.send_type? && node.descendants.any?(&method(:hash_literal?))
270
+ end
271
+ end
272
+
273
+ def allowed_multiline_call_with_parentheses?(node)
274
+ cop_config['AllowParenthesesInMultilineCall'] && node.multiline?
275
+ end
276
+
277
+ def allowed_chained_call_with_parentheses?(node)
278
+ return unless cop_config['AllowParenthesesInChaining']
279
+
280
+ previous = node.descendants.first
281
+ return false unless previous && previous.send_type?
282
+
283
+ previous.parenthesized? ||
284
+ allowed_chained_call_with_parentheses?(previous)
285
+ end
286
+
287
+ def splat?(node)
288
+ node.splat_type? || node.kwsplat_type? || node.block_pass_type?
289
+ end
290
+
291
+ def ternary_if?(node)
292
+ node.if_type? && node.ternary?
293
+ end
294
+
295
+ def logical_operator?(node)
296
+ (node.and_type? || node.or_type?) && node.logical_operator?
297
+ end
298
+
299
+ def hash_literal?(node)
300
+ node.hash_type? && node.braces?
301
+ end
97
302
  end
98
303
  end
99
304
  end
@@ -68,7 +68,7 @@ module RuboCop
68
68
 
69
69
  message = message_node && message_node.source
70
70
 
71
- correction = exception_node.const_name.to_s
71
+ correction = exception_node.source
72
72
  correction = "#{correction}, #{message}" if message
73
73
 
74
74
  "#{node.method_name} #{correction}"
@@ -83,6 +83,7 @@ module RuboCop
83
83
  # x =~ /home\//
84
84
  class RegexpLiteral < Cop
85
85
  include ConfigurableEnforcedStyle
86
+ include RangeHelp
86
87
 
87
88
  MSG_USE_SLASHES = 'Use `//` around regular expression.'.freeze
88
89
  MSG_USE_PERCENT_R = 'Use `%r` around regular expression.'.freeze
@@ -96,17 +97,9 @@ module RuboCop
96
97
  end
97
98
 
98
99
  def autocorrect(node)
99
- return if contains_slash?(node)
100
-
101
- replacement = if slash_literal?(node)
102
- ['%r', ''].zip(preferred_delimiters).map(&:join)
103
- else
104
- %w[/ /]
105
- end
106
-
107
100
  lambda do |corrector|
108
- corrector.replace(node.loc.begin, replacement.first)
109
- corrector.replace(node.loc.end, replacement.last)
101
+ correct_delimiters(node, corrector)
102
+ correct_inner_slashes(node, corrector)
110
103
  end
111
104
  end
112
105
 
@@ -169,6 +162,65 @@ module RuboCop
169
162
  config.for_cop('Style/PercentLiteralDelimiters') \
170
163
  ['PreferredDelimiters']['%r'].split(//)
171
164
  end
165
+
166
+ def correct_delimiters(node, corrector)
167
+ replacement = calculate_replacement(node)
168
+ corrector.replace(node.loc.begin, replacement.first)
169
+ corrector.replace(node.loc.end, replacement.last)
170
+ end
171
+
172
+ def correct_inner_slashes(node, corrector)
173
+ regexp_begin = node.loc.begin.end_pos
174
+
175
+ inner_slash_indices(node).each do |index|
176
+ start = regexp_begin + index
177
+
178
+ corrector.replace(
179
+ range_between(
180
+ start,
181
+ start + inner_slash_before_correction(node).length
182
+ ),
183
+ inner_slash_after_correction(node)
184
+ )
185
+ end
186
+ end
187
+
188
+ def inner_slash_indices(node)
189
+ text = node_body(node)
190
+ pattern = inner_slash_before_correction(node)
191
+ index = -1
192
+ indices = []
193
+
194
+ while (index = text.index(pattern, index + 1))
195
+ indices << index
196
+ end
197
+
198
+ indices
199
+ end
200
+
201
+ def inner_slash_before_correction(node)
202
+ inner_slash_for(node.loc.begin.source)
203
+ end
204
+
205
+ def inner_slash_after_correction(node)
206
+ inner_slash_for(calculate_replacement(node).first)
207
+ end
208
+
209
+ def inner_slash_for(opening_delimiter)
210
+ if ['/', '%r/'].include?(opening_delimiter)
211
+ '\/'
212
+ else
213
+ '/'
214
+ end
215
+ end
216
+
217
+ def calculate_replacement(node)
218
+ if slash_literal?(node)
219
+ ['%r', ''].zip(preferred_delimiters).map(&:join)
220
+ else
221
+ %w[/ /]
222
+ end
223
+ end
172
224
  end
173
225
  end
174
226
  end
@@ -47,7 +47,7 @@ module RuboCop
47
47
  lambda do |corrector|
48
48
  if node.ternary?
49
49
  corrector.replace(range_of_offense(node), '||')
50
- elsif node.modifier_form?
50
+ elsif node.modifier_form? || !node.else_branch
51
51
  corrector.replace(node.source_range, node.if_branch.source)
52
52
  else
53
53
  corrected = make_ternary_form(node)
@@ -60,7 +60,7 @@ module RuboCop
60
60
  private
61
61
 
62
62
  def message(node)
63
- if node.modifier_form?
63
+ if node.modifier_form? || !node.else_branch
64
64
  UNNEEDED_CONDITION
65
65
  else
66
66
  MSG
@@ -50,8 +50,8 @@ module RuboCop
50
50
 
51
51
  ZERO_ARITY_SUPER_TYPE = :zsuper
52
52
 
53
- TWISTED_SCOPE_TYPES = %i[block class sclass defs].freeze
54
- SCOPE_TYPES = (TWISTED_SCOPE_TYPES + %i[module def]).freeze
53
+ TWISTED_SCOPE_TYPES = %i[block class sclass defs module].freeze
54
+ SCOPE_TYPES = (TWISTED_SCOPE_TYPES + [:def]).freeze
55
55
 
56
56
  SEND_TYPE = :send
57
57
 
@@ -196,6 +196,7 @@ module RuboCop
196
196
  regexp.named_captures.keys
197
197
  end
198
198
 
199
+ # rubocop:disable Metrics/AbcSize
199
200
  def process_variable_operator_assignment(node)
200
201
  if LOGICAL_OPERATOR_ASSIGNMENT_TYPES.include?(node.type)
201
202
  asgn_node, rhs_node = *node
@@ -232,6 +233,7 @@ module RuboCop
232
233
 
233
234
  skip_children!
234
235
  end
236
+ # rubocop:enable Metrics/AbcSize
235
237
 
236
238
  def process_variable_multiple_assignment(node)
237
239
  lhs_node, rhs_node = *node
@@ -37,6 +37,7 @@ module RuboCop
37
37
  !@references.empty?
38
38
  end
39
39
 
40
+ # rubocop:disable Metrics/AbcSize
40
41
  def reference!(node)
41
42
  reference = Reference.new(node, @scope)
42
43
  @references << reference
@@ -56,6 +57,7 @@ module RuboCop
56
57
  end
57
58
  end
58
59
  end
60
+ # rubocop:enable Metrics/AbcSize
59
61
 
60
62
  def capture_with_block!
61
63
  @captured_by_block = true
@@ -134,7 +134,7 @@ module RuboCop
134
134
  OPERATOR = ':'.freeze
135
135
 
136
136
  def encoding
137
- match('encoding')
137
+ match('(?:en)?coding')
138
138
  end
139
139
 
140
140
  private