rubocop 1.31.1 → 1.33.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 (84) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +2 -2
  3. data/config/default.yml +68 -16
  4. data/config/obsoletion.yml +23 -1
  5. data/lib/rubocop/cache_config.rb +29 -0
  6. data/lib/rubocop/cli/command/auto_genenerate_config.rb +2 -2
  7. data/lib/rubocop/cli/command/init_dotfile.rb +1 -1
  8. data/lib/rubocop/cli.rb +1 -0
  9. data/lib/rubocop/config.rb +1 -1
  10. data/lib/rubocop/config_finder.rb +68 -0
  11. data/lib/rubocop/config_loader.rb +5 -45
  12. data/lib/rubocop/config_loader_resolver.rb +1 -1
  13. data/lib/rubocop/config_obsoletion/changed_parameter.rb +5 -0
  14. data/lib/rubocop/config_obsoletion/parameter_rule.rb +4 -0
  15. data/lib/rubocop/config_obsoletion.rb +7 -2
  16. data/lib/rubocop/cop/base.rb +1 -1
  17. data/lib/rubocop/cop/generator.rb +4 -0
  18. data/lib/rubocop/cop/internal_affairs/useless_restrict_on_send.rb +60 -0
  19. data/lib/rubocop/cop/internal_affairs.rb +1 -0
  20. data/lib/rubocop/cop/layout/block_end_newline.rb +32 -5
  21. data/lib/rubocop/cop/layout/first_argument_indentation.rb +6 -1
  22. data/lib/rubocop/cop/layout/first_array_element_indentation.rb +4 -3
  23. data/lib/rubocop/cop/layout/first_hash_element_indentation.rb +3 -3
  24. data/lib/rubocop/cop/layout/line_continuation_leading_space.rb +57 -13
  25. data/lib/rubocop/cop/layout/line_length.rb +2 -0
  26. data/lib/rubocop/cop/layout/multiline_method_argument_line_breaks.rb +4 -1
  27. data/lib/rubocop/cop/layout/multiline_method_parameter_line_breaks.rb +45 -0
  28. data/lib/rubocop/cop/lint/ambiguous_block_association.rb +26 -6
  29. data/lib/rubocop/cop/lint/debugger.rb +11 -1
  30. data/lib/rubocop/cop/lint/deprecated_class_methods.rb +10 -4
  31. data/lib/rubocop/cop/lint/empty_conditional_body.rb +60 -1
  32. data/lib/rubocop/cop/lint/non_atomic_file_operation.rb +60 -25
  33. data/lib/rubocop/cop/lint/number_conversion.rb +28 -6
  34. data/lib/rubocop/cop/lint/redundant_safe_navigation.rb +7 -0
  35. data/lib/rubocop/cop/lint/require_range_parentheses.rb +57 -0
  36. data/lib/rubocop/cop/lint/safe_navigation_chain.rb +35 -1
  37. data/lib/rubocop/cop/metrics/abc_size.rb +3 -1
  38. data/lib/rubocop/cop/metrics/block_length.rb +6 -6
  39. data/lib/rubocop/cop/metrics/method_length.rb +8 -7
  40. data/lib/rubocop/cop/mixin/allowed_methods.rb +15 -1
  41. data/lib/rubocop/cop/mixin/allowed_pattern.rb +9 -1
  42. data/lib/rubocop/cop/mixin/check_line_breakable.rb +4 -0
  43. data/lib/rubocop/cop/mixin/comments_help.rb +5 -1
  44. data/lib/rubocop/cop/mixin/def_node.rb +2 -7
  45. data/lib/rubocop/cop/mixin/method_complexity.rb +4 -9
  46. data/lib/rubocop/cop/mixin/multiline_element_indentation.rb +6 -13
  47. data/lib/rubocop/cop/mixin/percent_array.rb +60 -1
  48. data/lib/rubocop/cop/naming/predicate_name.rb +30 -1
  49. data/lib/rubocop/cop/style/block_delimiters.rb +26 -7
  50. data/lib/rubocop/cop/style/class_and_module_children.rb +4 -4
  51. data/lib/rubocop/cop/style/class_equality_comparison.rb +50 -3
  52. data/lib/rubocop/cop/style/empty_else.rb +37 -0
  53. data/lib/rubocop/cop/style/empty_heredoc.rb +73 -0
  54. data/lib/rubocop/cop/style/fetch_env_var.rb +10 -177
  55. data/lib/rubocop/cop/style/format_string_token.rb +25 -6
  56. data/lib/rubocop/cop/style/hash_except.rb +0 -4
  57. data/lib/rubocop/cop/style/if_with_boolean_literal_branches.rb +2 -0
  58. data/lib/rubocop/cop/style/method_call_with_args_parentheses/require_parentheses.rb +5 -1
  59. data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +7 -7
  60. data/lib/rubocop/cop/style/method_call_without_args_parentheses.rb +19 -2
  61. data/lib/rubocop/cop/style/module_function.rb +2 -2
  62. data/lib/rubocop/cop/style/nested_parenthesized_calls.rb +9 -0
  63. data/lib/rubocop/cop/style/numeric_predicate.rb +43 -9
  64. data/lib/rubocop/cop/style/redundant_condition.rb +19 -4
  65. data/lib/rubocop/cop/style/redundant_parentheses.rb +2 -1
  66. data/lib/rubocop/cop/style/redundant_sort.rb +21 -6
  67. data/lib/rubocop/cop/style/semicolon.rb +27 -3
  68. data/lib/rubocop/cop/style/symbol_array.rb +2 -3
  69. data/lib/rubocop/cop/style/symbol_proc.rb +35 -7
  70. data/lib/rubocop/cop/style/trivial_accessors.rb +3 -0
  71. data/lib/rubocop/cop/style/word_array.rb +2 -3
  72. data/lib/rubocop/options.rb +3 -6
  73. data/lib/rubocop/rake_task.rb +5 -1
  74. data/lib/rubocop/result_cache.rb +22 -20
  75. data/lib/rubocop/rspec/shared_contexts.rb +14 -14
  76. data/lib/rubocop/rspec/support.rb +14 -0
  77. data/lib/rubocop/runner.rb +4 -0
  78. data/lib/rubocop/server/cache.rb +33 -1
  79. data/lib/rubocop/server/cli.rb +19 -2
  80. data/lib/rubocop/server/client_command/base.rb +1 -1
  81. data/lib/rubocop/version.rb +1 -1
  82. data/lib/rubocop.rb +4 -2
  83. metadata +12 -7
  84. data/lib/rubocop/cop/mixin/ignored_methods.rb +0 -52
@@ -11,7 +11,8 @@ module RuboCop
11
11
  # The reason is that _unannotated_ format is very similar
12
12
  # to encoded URLs or Date/Time formatting strings.
13
13
  #
14
- # This cop can be customized ignored methods with `IgnoredMethods`.
14
+ # This cop can be customized allowed methods with `AllowedMethods`.
15
+ # By default, there are no methods to allowed.
15
16
  #
16
17
  # @example EnforcedStyle: annotated (default)
17
18
  #
@@ -61,18 +62,34 @@ module RuboCop
61
62
  # # good
62
63
  # format('%06d', 10)
63
64
  #
64
- # @example IgnoredMethods: [redirect]
65
+ # @example AllowedMethods: [] (default)
66
+ #
67
+ # # bad
68
+ # redirect('foo/%{bar_id}')
69
+ #
70
+ # @example AllowedMethods: [redirect]
71
+ #
72
+ # # good
73
+ # redirect('foo/%{bar_id}')
74
+ #
75
+ # @example AllowedPatterns: [] (default)
76
+ #
77
+ # # bad
78
+ # redirect('foo/%{bar_id}')
79
+ #
80
+ # @example AllowedPatterns: [/redirect/]
65
81
  #
66
82
  # # good
67
83
  # redirect('foo/%{bar_id}')
68
84
  #
69
85
  class FormatStringToken < Base
70
86
  include ConfigurableEnforcedStyle
71
- include IgnoredMethods
87
+ include AllowedMethods
88
+ include AllowedPattern
72
89
  extend AutoCorrector
73
90
 
74
91
  def on_str(node)
75
- return if format_string_token?(node) || use_ignored_method?(node)
92
+ return if format_string_token?(node) || use_allowed_method?(node)
76
93
 
77
94
  detections = collect_detections(node)
78
95
  return if detections.empty?
@@ -97,9 +114,11 @@ module RuboCop
97
114
  !node.value.include?('%') || node.each_ancestor(:xstr, :regexp).any?
98
115
  end
99
116
 
100
- def use_ignored_method?(node)
117
+ def use_allowed_method?(node)
101
118
  send_parent = node.each_ancestor(:send).first
102
- send_parent && ignored_method?(send_parent.method_name)
119
+ send_parent &&
120
+ (allowed_method?(send_parent.method_name) ||
121
+ matches_allowed_pattern?(send_parent.method_name))
103
122
  end
104
123
 
105
124
  def check_sequence(detected_sequence, token_range)
@@ -159,10 +159,6 @@ module RuboCop
159
159
  key_argument = node.argument_list.first.source
160
160
  body = extract_body_if_nagated(node.body)
161
161
  lhs, _method_name, rhs = *body
162
-
163
- return lhs if body.method?('include?')
164
- return lhs if body.method?('exclude?')
165
- return rhs if body.method?('in?')
166
162
  return if [lhs, rhs].map(&:source).none?(key_argument)
167
163
 
168
164
  [lhs, rhs].find { |operand| operand.source != key_argument }
@@ -6,6 +6,8 @@ module RuboCop
6
6
  # Checks for redundant `if` with boolean literal branches.
7
7
  # It checks only conditions to return boolean value (`true` or `false`) for safe detection.
8
8
  # The conditions to be checked are comparison methods, predicate methods, and double negative.
9
+ # `nonzero?` method is allowed by default.
10
+ # These are customizable with `AllowedMethods` option.
9
11
  #
10
12
  # @safety
11
13
  # Autocorrection is unsafe because there is no guarantee that all predicate methods
@@ -12,7 +12,7 @@ module RuboCop
12
12
  private
13
13
 
14
14
  def require_parentheses(node)
15
- return if ignored_method?(node.method_name)
15
+ return if allowed_method_name?(node.method_name)
16
16
  return if matches_allowed_pattern?(node.method_name)
17
17
  return if eligible_for_parentheses_omission?(node)
18
18
  return unless node.arguments? && !node.parenthesized?
@@ -24,6 +24,10 @@ module RuboCop
24
24
  end
25
25
  end
26
26
 
27
+ def allowed_method_name?(name)
28
+ allowed_method?(name) || matches_allowed_pattern?(name)
29
+ end
30
+
27
31
  def eligible_for_parentheses_omission?(node)
28
32
  node.operator_method? || node.setter_method? || ignored_macro?(node)
29
33
  end
@@ -6,8 +6,8 @@ module RuboCop
6
6
  # Enforces the presence (default) or absence of parentheses in
7
7
  # method calls containing parameters.
8
8
  #
9
- # In the default style (require_parentheses), macro methods are ignored.
10
- # Additional methods can be added to the `IgnoredMethods`
9
+ # In the default style (require_parentheses), macro methods are allowed.
10
+ # Additional methods can be added to the `AllowedMethods`
11
11
  # or `AllowedPatterns` list. These options are
12
12
  # valid only in the default style. Macros can be included by
13
13
  # either setting `IgnoreMacros` to false or adding specific macros to
@@ -15,13 +15,13 @@ module RuboCop
15
15
  #
16
16
  # Precedence of options is all follows:
17
17
  #
18
- # 1. `IgnoredMethods`
18
+ # 1. `AllowedMethods`
19
19
  # 2. `AllowedPatterns`
20
20
  # 3. `IncludedMacros`
21
21
  #
22
22
  # eg. If a method is listed in both
23
- # `IncludedMacros` and `IgnoredMethods`, then the latter takes
24
- # precedence (that is, the method is ignored).
23
+ # `IncludedMacros` and `AllowedMethods`, then the latter takes
24
+ # precedence (that is, the method is allowed).
25
25
  #
26
26
  # In the alternative style (omit_parentheses), there are three additional
27
27
  # options.
@@ -65,7 +65,7 @@ module RuboCop
65
65
  # # Setter methods don't need parens
66
66
  # foo.bar = baz
67
67
  #
68
- # # okay with `puts` listed in `IgnoredMethods`
68
+ # # okay with `puts` listed in `AllowedMethods`
69
69
  # puts 'test'
70
70
  #
71
71
  # # okay with `^assert` listed in `AllowedPatterns`
@@ -197,7 +197,7 @@ module RuboCop
197
197
  require_relative 'method_call_with_args_parentheses/require_parentheses'
198
198
 
199
199
  include ConfigurableEnforcedStyle
200
- include IgnoredMethods
200
+ include AllowedMethods
201
201
  include AllowedPattern
202
202
  include RequireParentheses
203
203
  include OmitParentheses
@@ -5,14 +5,27 @@ module RuboCop
5
5
  module Style
6
6
  # Checks for unwanted parentheses in parameterless method calls.
7
7
  #
8
+ # This cop can be customized allowed methods with `AllowedMethods`.
9
+ # By default, there are no methods to allowed.
10
+ #
8
11
  # @example
9
12
  # # bad
10
13
  # object.some_method()
11
14
  #
12
15
  # # good
13
16
  # object.some_method
17
+ #
18
+ # @example AllowedMethods: [] (default)
19
+ # # bad
20
+ # object.foo()
21
+ #
22
+ # @example AllowedMethods: [foo]
23
+ # # good
24
+ # object.foo()
25
+ #
14
26
  class MethodCallWithoutArgsParentheses < Base
15
- include IgnoredMethods
27
+ include AllowedMethods
28
+ include AllowedPattern
16
29
  extend AutoCorrector
17
30
 
18
31
  MSG = 'Do not use parentheses for method calls with no arguments.'
@@ -21,7 +34,7 @@ module RuboCop
21
34
  return unless !node.arguments? && node.parenthesized?
22
35
  return if ineligible_node?(node)
23
36
  return if default_argument?(node)
24
- return if ignored_method?(node.method_name)
37
+ return if allowed_method_name?(node.method_name)
25
38
  return if same_name_assignment?(node)
26
39
 
27
40
  register_offense(node)
@@ -44,6 +57,10 @@ module RuboCop
44
57
  node.parent&.optarg_type?
45
58
  end
46
59
 
60
+ def allowed_method_name?(name)
61
+ allowed_method?(name) || matches_allowed_pattern?(name)
62
+ end
63
+
47
64
  def same_name_assignment?(node)
48
65
  any_assignment?(node) do |asgn_node|
49
66
  next variable_in_mass_assignment?(node.method_name, asgn_node) if asgn_node.masgn_type?
@@ -117,10 +117,10 @@ module RuboCop
117
117
  end
118
118
 
119
119
  def check_module_function(nodes)
120
- private_directive = nodes.any? { |node| private_directive?(node) }
120
+ return if nodes.any? { |node| private_directive?(node) }
121
121
 
122
122
  nodes.each do |node|
123
- yield node if extend_self_node?(node) && !private_directive
123
+ yield node if extend_self_node?(node)
124
124
  end
125
125
  end
126
126
 
@@ -5,6 +5,10 @@ module RuboCop
5
5
  module Style
6
6
  # Checks for unparenthesized method calls in the argument list
7
7
  # of a parenthesized method call.
8
+ # `be`, `be_a`, `be_an`, `be_between`, `be_falsey`, `be_kind_of`, `be_instance_of`,
9
+ # `be_truthy`, `be_within`, `eq`, `eql`, `end_with`, `include`, `match`, `raise_error`,
10
+ # `respond_to`, and `start_with` methods are allowed by default.
11
+ # These are customizable with `AllowedMethods` option.
8
12
  #
9
13
  # @example
10
14
  # # good
@@ -12,6 +16,11 @@ module RuboCop
12
16
  #
13
17
  # # bad
14
18
  # method1(method2 arg)
19
+ #
20
+ # @example AllowedMethods: [foo]
21
+ # # good
22
+ # method1(foo arg)
23
+ #
15
24
  class NestedParenthesizedCalls < Base
16
25
  include RangeHelp
17
26
  include AllowedMethods
@@ -6,13 +6,16 @@ module RuboCop
6
6
  # Checks for usage of comparison operators (`==`,
7
7
  # `>`, `<`) to test numbers as zero, positive, or negative.
8
8
  # These can be replaced by their respective predicate methods.
9
- # The cop can also be configured to do the reverse.
9
+ # This cop can also be configured to do the reverse.
10
10
  #
11
- # The cop disregards `#nonzero?` as its value is truthy or falsey,
11
+ # This cop can be customized allowed methods with `AllowedMethods`.
12
+ # By default, there are no methods to allowed.
13
+ #
14
+ # This cop disregards `#nonzero?` as its value is truthy or falsey,
12
15
  # but not `true` and `false`, and thus not always interchangeable with
13
16
  # `!= 0`.
14
17
  #
15
- # The cop ignores comparisons to global variables, since they are often
18
+ # This cop allows comparisons to global variables, since they are often
16
19
  # populated with objects which can be compared with integers, but are
17
20
  # not themselves `Integer` polymorphic.
18
21
  #
@@ -23,32 +26,59 @@ module RuboCop
23
26
  #
24
27
  # @example EnforcedStyle: predicate (default)
25
28
  # # bad
26
- #
27
29
  # foo == 0
28
30
  # 0 > foo
29
31
  # bar.baz > 0
30
32
  #
31
33
  # # good
32
- #
33
34
  # foo.zero?
34
35
  # foo.negative?
35
36
  # bar.baz.positive?
36
37
  #
37
38
  # @example EnforcedStyle: comparison
38
39
  # # bad
39
- #
40
40
  # foo.zero?
41
41
  # foo.negative?
42
42
  # bar.baz.positive?
43
43
  #
44
44
  # # good
45
+ # foo == 0
46
+ # 0 > foo
47
+ # bar.baz > 0
48
+ #
49
+ # @example AllowedMethods: [] (default) with EnforcedStyle: predicate
50
+ # # bad
51
+ # foo == 0
52
+ # 0 > foo
53
+ # bar.baz > 0
45
54
  #
55
+ # @example AllowedMethods: [==] with EnforcedStyle: predicate
56
+ # # good
46
57
  # foo == 0
58
+ #
59
+ # # bad
47
60
  # 0 > foo
48
61
  # bar.baz > 0
62
+ #
63
+ # @example AllowedPatterns: [] (default) with EnforcedStyle: comparison
64
+ # # bad
65
+ # foo.zero?
66
+ # foo.negative?
67
+ # bar.baz.positive?
68
+ #
69
+ # @example AllowedPatterns: [/zero/] with EnforcedStyle: predicate
70
+ # # good
71
+ # # bad
72
+ # foo.zero?
73
+ #
74
+ # # bad
75
+ # foo.negative?
76
+ # bar.baz.positive?
77
+ #
49
78
  class NumericPredicate < Base
50
79
  include ConfigurableEnforcedStyle
51
- include IgnoredMethods
80
+ include AllowedMethods
81
+ include AllowedPattern
52
82
  extend AutoCorrector
53
83
 
54
84
  MSG = 'Use `%<prefer>s` instead of `%<current>s`.'
@@ -61,9 +91,9 @@ module RuboCop
61
91
  numeric, replacement = check(node)
62
92
  return unless numeric
63
93
 
64
- return if ignored_method?(node.method_name) ||
94
+ return if allowed_method_name?(node.method_name) ||
65
95
  node.each_ancestor(:send, :block).any? do |ancestor|
66
- ignored_method?(ancestor.method_name)
96
+ allowed_method_name?(ancestor.method_name)
67
97
  end
68
98
 
69
99
  message = format(MSG, prefer: replacement, current: node.source)
@@ -74,6 +104,10 @@ module RuboCop
74
104
 
75
105
  private
76
106
 
107
+ def allowed_method_name?(name)
108
+ allowed_method?(name) || matches_allowed_pattern?(name)
109
+ end
110
+
77
111
  def check(node)
78
112
  numeric, operator =
79
113
  if style == :predicate
@@ -154,16 +154,22 @@ module RuboCop
154
154
  if_branch.method?(else_branch.method_name) && if_branch.receiver == else_branch.receiver
155
155
  end
156
156
 
157
- def if_source(if_branch)
157
+ def if_source(if_branch, arithmetic_operation)
158
158
  if branches_have_method?(if_branch.parent) && if_branch.parenthesized?
159
159
  if_branch.source.delete_suffix(')')
160
+ elsif arithmetic_operation
161
+ argument_source = if_branch.first_argument.source
162
+
163
+ "#{if_branch.receiver.source} #{if_branch.method_name} (#{argument_source}"
160
164
  else
161
165
  if_branch.source
162
166
  end
163
167
  end
164
168
 
165
- def else_source(else_branch)
166
- if branches_have_method?(else_branch.parent)
169
+ def else_source(else_branch, arithmetic_operation) # rubocop:disable Metrics/AbcSize
170
+ if arithmetic_operation
171
+ "#{else_branch.first_argument.source})"
172
+ elsif branches_have_method?(else_branch.parent)
167
173
  else_source_if_has_method(else_branch)
168
174
  elsif require_parentheses?(else_branch)
169
175
  "(#{else_branch.source})"
@@ -198,7 +204,12 @@ module RuboCop
198
204
 
199
205
  def make_ternary_form(node)
200
206
  _condition, if_branch, else_branch = *node
201
- ternary_form = [if_source(if_branch), else_source(else_branch)].join(' || ')
207
+ arithmetic_operation = use_arithmetic_operation?(if_branch)
208
+
209
+ ternary_form = [
210
+ if_source(if_branch, arithmetic_operation),
211
+ else_source(else_branch, arithmetic_operation)
212
+ ].join(' || ')
202
213
  ternary_form += ')' if branches_have_method?(node) && if_branch.parenthesized?
203
214
 
204
215
  if node.parent&.send_type?
@@ -227,6 +238,10 @@ module RuboCop
227
238
  node.hash_type? && !node.braces?
228
239
  end
229
240
 
241
+ def use_arithmetic_operation?(node)
242
+ node.respond_to?(:arithmetic_operation?) && node.arithmetic_operation?
243
+ end
244
+
230
245
  def without_argument_parentheses_method?(node)
231
246
  node.send_type? && !node.arguments.empty? &&
232
247
  !node.parenthesized? && !node.operator_method? && !node.assignment_method?
@@ -81,7 +81,8 @@ module RuboCop
81
81
  end
82
82
 
83
83
  def like_method_argument_parentheses?(node)
84
- node.send_type? && node.arguments.size == 1 && !node.arithmetic_operation?
84
+ node.send_type? && node.arguments.one? &&
85
+ !node.arithmetic_operation? && node.first_argument.begin_type?
85
86
  end
86
87
 
87
88
  def empty_parentheses?(node)
@@ -123,13 +123,8 @@ module RuboCop
123
123
 
124
124
  def register_offense(node, sort_node, sorter, accessor)
125
125
  message = message(node, sorter, accessor)
126
-
127
126
  add_offense(offense_range(sort_node, node), message: message) do |corrector|
128
- # Remove accessor, e.g. `first` or `[-1]`.
129
- corrector.remove(range_between(accessor_start(node), node.loc.expression.end_pos))
130
-
131
- # Replace "sort" or "sort_by" with the appropriate min/max method.
132
- corrector.replace(sort_node.loc.selector, suggestion(sorter, accessor, arg_value(node)))
127
+ autocorrect(corrector, node, sort_node, sorter, accessor)
133
128
  end
134
129
  end
135
130
 
@@ -149,6 +144,20 @@ module RuboCop
149
144
  accessor_source: accessor_source)
150
145
  end
151
146
 
147
+ def autocorrect(corrector, node, sort_node, sorter, accessor)
148
+ # Remove accessor, e.g. `first` or `[-1]`.
149
+ corrector.remove(range_between(accessor_start(node), node.loc.expression.end_pos))
150
+ # Replace "sort" or "sort_by" with the appropriate min/max method.
151
+ corrector.replace(sort_node.loc.selector, suggestion(sorter, accessor, arg_value(node)))
152
+ # Replace to avoid syntax errors when followed by a logical operator.
153
+ replace_with_logical_operator(corrector, node) if with_logical_operator?(node)
154
+ end
155
+
156
+ def replace_with_logical_operator(corrector, node)
157
+ corrector.insert_after(node.child_nodes.first, " #{node.parent.loc.operator.source}")
158
+ corrector.remove(node.parent.loc.operator)
159
+ end
160
+
152
161
  def suggestion(sorter, accessor, arg)
153
162
  base(accessor, arg) + suffix(sorter)
154
163
  end
@@ -187,6 +196,12 @@ module RuboCop
187
196
  node.loc.selector.begin_pos
188
197
  end
189
198
  end
199
+
200
+ def with_logical_operator?(node)
201
+ return unless (parent = node.parent)
202
+
203
+ parent.or_type? || parent.and_type?
204
+ end
190
205
  end
191
206
  end
192
207
  end
@@ -64,12 +64,14 @@ module RuboCop
64
64
  # Make the obvious check first
65
65
  return unless processed_source.raw_source.include?(';')
66
66
 
67
- each_semicolon { |line, column| register_semicolon(line, column, false) }
67
+ each_semicolon do |line, column, token_before_semicolon|
68
+ register_semicolon(line, column, false, token_before_semicolon)
69
+ end
68
70
  end
69
71
 
70
72
  def each_semicolon
71
73
  tokens_for_lines.each do |line, tokens|
72
- yield line, tokens.last.column if tokens.last.semicolon?
74
+ yield line, tokens.last.column, tokens[-2] if tokens.last.semicolon?
73
75
  yield line, tokens.first.column if tokens.first.semicolon?
74
76
  end
75
77
  end
@@ -78,13 +80,21 @@ module RuboCop
78
80
  processed_source.tokens.group_by(&:line)
79
81
  end
80
82
 
81
- def register_semicolon(line, column, after_expression)
83
+ def register_semicolon(line, column, after_expression, token_before_semicolon = nil)
82
84
  range = source_range(processed_source.buffer, line, column)
83
85
 
84
86
  add_offense(range) do |corrector|
85
87
  if after_expression
86
88
  corrector.replace(range, "\n")
87
89
  else
90
+ # Prevents becoming one range instance with subsequent line when endless range
91
+ # without parentheses.
92
+ # See: https://github.com/rubocop/rubocop/issues/10791
93
+ if token_before_semicolon&.regexp_dots?
94
+ range_node = find_range_node(token_before_semicolon)
95
+ corrector.wrap(range_node, '(', ')') if range_node
96
+ end
97
+
88
98
  corrector.remove(range)
89
99
  end
90
100
  end
@@ -103,6 +113,20 @@ module RuboCop
103
113
  yield Regexp.last_match.begin(0)
104
114
  end
105
115
  end
116
+
117
+ def find_range_node(token_before_semicolon)
118
+ range_nodes.detect do |range_node|
119
+ range_node.source_range.contains?(token_before_semicolon.pos)
120
+ end
121
+ end
122
+
123
+ def range_nodes
124
+ return @range_nodes if instance_variable_defined?(:@range_nodes)
125
+
126
+ ast = processed_source.ast
127
+ @range_nodes = ast.range_type? ? [ast] : []
128
+ @range_nodes.concat(ast.each_descendant(:irange, :erange).to_a)
129
+ end
106
130
  end
107
131
  end
108
132
  end
@@ -39,7 +39,7 @@ module RuboCop
39
39
  minimum_target_ruby_version 2.0
40
40
 
41
41
  PERCENT_MSG = 'Use `%i` or `%I` for an array of symbols.'
42
- ARRAY_MSG = 'Use `%<prefer>s` for an array of symbols.'
42
+ ARRAY_MSG = 'Use %<prefer>s for an array of symbols.'
43
43
 
44
44
  class << self
45
45
  attr_accessor :largest_brackets
@@ -74,8 +74,7 @@ module RuboCop
74
74
  to_symbol_literal(c.value.to_s)
75
75
  end
76
76
  end
77
-
78
- "[#{syms.join(', ')}]"
77
+ build_bracketed_array_with_appropriate_whitespace(elements: syms, node: node)
79
78
  end
80
79
 
81
80
  def to_symbol_literal(string)
@@ -7,11 +7,13 @@ module RuboCop
7
7
  #
8
8
  # If you prefer a style that allows block for method with arguments,
9
9
  # please set `true` to `AllowMethodsWithArguments`.
10
+ # respond_to , and `define_method?` methods are allowed by default.
11
+ # These are customizable with `AllowedMethods` option.
10
12
  #
11
13
  # @safety
12
14
  # This cop is unsafe because `proc`s and blocks work differently
13
15
  # when additional arguments are passed in. A block will silently
14
- # ignore additional arguments, but a `proc` will raise
16
+ # allow additional arguments, but a `proc` will raise
15
17
  # an `ArgumentError`.
16
18
  #
17
19
  # For example:
@@ -68,10 +70,26 @@ module RuboCop
68
70
  # s.upcase # some comment
69
71
  # # some comment
70
72
  # end
73
+ #
74
+ # @example AllowedMethods: [respond_to, define_method] (default)
75
+ # # good
76
+ # respond_to { |foo| foo.bar }
77
+ # define_method(:foo) { |foo| foo.bar }
78
+ #
79
+ #
80
+ # @example AllowedPatterns: [] (default)
81
+ # # bad
82
+ # something.map { |s| s.upcase }
83
+ #
84
+ # @example AllowedPatterns: [/map/] (default)
85
+ # # good
86
+ # something.map { |s| s.upcase }
87
+ #
71
88
  class SymbolProc < Base
72
89
  include CommentsHelp
73
90
  include RangeHelp
74
- include IgnoredMethods
91
+ include AllowedMethods
92
+ include AllowedPattern
75
93
  extend AutoCorrector
76
94
 
77
95
  MSG = 'Pass `&:%<method>s` as an argument to `%<block_method>s` instead of a block.'
@@ -81,7 +99,7 @@ module RuboCop
81
99
  def_node_matcher :proc_node?, '(send (const {nil? cbase} :Proc) :new)'
82
100
 
83
101
  # @!method symbol_proc_receiver?(node)
84
- def_node_matcher :symbol_proc_receiver?, '{(send ...) (super ...) zsuper}'
102
+ def_node_matcher :symbol_proc_receiver?, '{(call ...) (super ...) zsuper}'
85
103
 
86
104
  # @!method symbol_proc?(node)
87
105
  def_node_matcher :symbol_proc?, <<~PATTERN
@@ -95,15 +113,16 @@ module RuboCop
95
113
  [Layout::SpaceBeforeBlockBraces]
96
114
  end
97
115
 
98
- # rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
116
+ # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
99
117
  def on_block(node)
100
118
  symbol_proc?(node) do |dispatch_node, arguments_node, method_name|
101
119
  # TODO: Rails-specific handling that we should probably make
102
120
  # configurable - https://github.com/rubocop/rubocop/issues/1485
103
- # we should ignore lambdas & procs
121
+ # we should allow lambdas & procs
104
122
  return if proc_node?(dispatch_node)
123
+ return if unsafe_hash_usage?(dispatch_node)
105
124
  return if %i[lambda proc].include?(dispatch_node.method_name)
106
- return if ignored_method?(dispatch_node.method_name)
125
+ return if allowed_method_name?(dispatch_node.method_name)
107
126
  return if allow_if_method_has_argument?(node.send_node)
108
127
  return if node.block_type? && destructuring_block_argument?(arguments_node)
109
128
  return if allow_comments? && contains_comments?(node)
@@ -111,7 +130,7 @@ module RuboCop
111
130
  register_offense(node, method_name, dispatch_node.method_name)
112
131
  end
113
132
  end
114
- # rubocop:enable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
133
+ # rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
115
134
  alias on_numblock on_block
116
135
 
117
136
  def destructuring_block_argument?(argument_node)
@@ -120,6 +139,15 @@ module RuboCop
120
139
 
121
140
  private
122
141
 
142
+ # See: https://github.com/rubocop/rubocop/issues/10864
143
+ def unsafe_hash_usage?(node)
144
+ node.receiver&.hash_type? && %i[reject select].include?(node.method_name)
145
+ end
146
+
147
+ def allowed_method_name?(name)
148
+ allowed_method?(name) || matches_allowed_pattern?(name)
149
+ end
150
+
123
151
  def register_offense(node, method_name, block_method_name)
124
152
  block_start = node.loc.begin.begin_pos
125
153
  block_end = node.loc.end.end_pos
@@ -5,6 +5,9 @@ module RuboCop
5
5
  module Style
6
6
  # Looks for trivial reader/writer methods, that could
7
7
  # have been created with the attr_* family of functions automatically.
8
+ # `to_ary`, `to_a`, `to_c`, `to_enum`, `to_h`, `to_hash`, `to_i`, `to_int`, `to_io`,
9
+ # `to_open`, `to_path`, `to_proc`, `to_r`, `to_regexp`, `to_str`, `to_s`, and `to_sym` methods
10
+ # are allowed by default. These are customizable with `AllowedMethods` option.
8
11
  #
9
12
  # @example
10
13
  # # bad
@@ -44,7 +44,7 @@ module RuboCop
44
44
  extend AutoCorrector
45
45
 
46
46
  PERCENT_MSG = 'Use `%w` or `%W` for an array of words.'
47
- ARRAY_MSG = 'Use `%<prefer>s` for an array of words.'
47
+ ARRAY_MSG = 'Use %<prefer>s for an array of words.'
48
48
 
49
49
  class << self
50
50
  attr_accessor :largest_brackets
@@ -92,8 +92,7 @@ module RuboCop
92
92
  to_string_literal(word.children[0])
93
93
  end
94
94
  end
95
-
96
- "[#{words.join(', ')}]"
95
+ build_bracketed_array_with_appropriate_whitespace(elements: words, node: node)
97
96
  end
98
97
  end
99
98
  end