rubocop 0.48.1 → 0.49.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 (184) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +4 -3
  3. data/config/default.yml +397 -357
  4. data/config/disabled.yml +29 -29
  5. data/config/enabled.yml +366 -326
  6. data/lib/rubocop.rb +85 -70
  7. data/lib/rubocop/ast/builder.rb +4 -1
  8. data/lib/rubocop/ast/node.rb +2 -2
  9. data/lib/rubocop/ast/node/and_node.rb +1 -1
  10. data/lib/rubocop/ast/node/args_node.rb +24 -0
  11. data/lib/rubocop/ast/node/block_node.rb +107 -0
  12. data/lib/rubocop/ast/node/case_node.rb +1 -1
  13. data/lib/rubocop/ast/node/ensure_node.rb +1 -1
  14. data/lib/rubocop/ast/node/for_node.rb +1 -1
  15. data/lib/rubocop/ast/node/if_node.rb +1 -1
  16. data/lib/rubocop/ast/node/mixin/parameterized_node.rb +74 -0
  17. data/lib/rubocop/ast/node/or_node.rb +1 -1
  18. data/lib/rubocop/ast/node/pair_node.rb +1 -1
  19. data/lib/rubocop/ast/node/resbody_node.rb +1 -1
  20. data/lib/rubocop/ast/node/send_node.rb +36 -57
  21. data/lib/rubocop/ast/node/super_node.rb +42 -0
  22. data/lib/rubocop/ast/node/until_node.rb +1 -1
  23. data/lib/rubocop/ast/node/when_node.rb +1 -1
  24. data/lib/rubocop/ast/node/while_node.rb +1 -1
  25. data/lib/rubocop/cli.rb +10 -0
  26. data/lib/rubocop/config.rb +23 -7
  27. data/lib/rubocop/config_loader.rb +19 -3
  28. data/lib/rubocop/cop/badge.rb +1 -1
  29. data/lib/rubocop/cop/bundler/duplicated_gem.rb +2 -2
  30. data/lib/rubocop/cop/commissioner.rb +1 -1
  31. data/lib/rubocop/cop/cop.rb +10 -0
  32. data/lib/rubocop/cop/{style → layout}/access_modifier_indentation.rb +33 -3
  33. data/lib/rubocop/cop/{style → layout}/align_array.rb +16 -1
  34. data/lib/rubocop/cop/{style → layout}/align_hash.rb +1 -1
  35. data/lib/rubocop/cop/{style → layout}/align_parameters.rb +29 -1
  36. data/lib/rubocop/cop/{style → layout}/block_end_newline.rb +10 -5
  37. data/lib/rubocop/cop/{style → layout}/case_indentation.rb +64 -1
  38. data/lib/rubocop/cop/{style → layout}/closing_parenthesis_indentation.rb +2 -2
  39. data/lib/rubocop/cop/{style → layout}/comment_indentation.rb +1 -1
  40. data/lib/rubocop/cop/{style → layout}/dot_position.rb +1 -1
  41. data/lib/rubocop/cop/{style → layout}/else_alignment.rb +1 -1
  42. data/lib/rubocop/cop/{style → layout}/empty_line_after_magic_comment.rb +1 -1
  43. data/lib/rubocop/cop/{style → layout}/empty_line_between_defs.rb +1 -1
  44. data/lib/rubocop/cop/{style → layout}/empty_lines.rb +1 -1
  45. data/lib/rubocop/cop/{style → layout}/empty_lines_around_access_modifier.rb +2 -7
  46. data/lib/rubocop/cop/{style → layout}/empty_lines_around_begin_body.rb +1 -1
  47. data/lib/rubocop/cop/{style → layout}/empty_lines_around_block_body.rb +2 -4
  48. data/lib/rubocop/cop/{style → layout}/empty_lines_around_class_body.rb +1 -1
  49. data/lib/rubocop/cop/{style → layout}/empty_lines_around_exception_handling_keywords.rb +1 -1
  50. data/lib/rubocop/cop/{style → layout}/empty_lines_around_method_body.rb +1 -1
  51. data/lib/rubocop/cop/{style → layout}/empty_lines_around_module_body.rb +1 -1
  52. data/lib/rubocop/cop/{style → layout}/end_of_line.rb +1 -1
  53. data/lib/rubocop/cop/{style → layout}/extra_spacing.rb +1 -1
  54. data/lib/rubocop/cop/{style → layout}/first_array_element_line_break.rb +1 -1
  55. data/lib/rubocop/cop/{style → layout}/first_hash_element_line_break.rb +1 -1
  56. data/lib/rubocop/cop/{style → layout}/first_method_argument_line_break.rb +1 -1
  57. data/lib/rubocop/cop/{style → layout}/first_method_parameter_line_break.rb +1 -1
  58. data/lib/rubocop/cop/{style → layout}/first_parameter_indentation.rb +1 -1
  59. data/lib/rubocop/cop/{style → layout}/indent_array.rb +1 -1
  60. data/lib/rubocop/cop/{style → layout}/indent_assignment.rb +1 -1
  61. data/lib/rubocop/cop/{style → layout}/indent_hash.rb +2 -2
  62. data/lib/rubocop/cop/{style → layout}/indent_heredoc.rb +3 -3
  63. data/lib/rubocop/cop/{style → layout}/indentation_consistency.rb +1 -1
  64. data/lib/rubocop/cop/{style → layout}/indentation_width.rb +10 -12
  65. data/lib/rubocop/cop/{style → layout}/initial_indentation.rb +1 -1
  66. data/lib/rubocop/cop/{style → layout}/leading_comment_space.rb +1 -1
  67. data/lib/rubocop/cop/{style → layout}/multiline_array_brace_layout.rb +1 -1
  68. data/lib/rubocop/cop/{style → layout}/multiline_assignment_layout.rb +1 -1
  69. data/lib/rubocop/cop/{style → layout}/multiline_block_layout.rb +21 -36
  70. data/lib/rubocop/cop/{style → layout}/multiline_hash_brace_layout.rb +5 -1
  71. data/lib/rubocop/cop/{style → layout}/multiline_method_call_brace_layout.rb +1 -1
  72. data/lib/rubocop/cop/{style → layout}/multiline_method_call_indentation.rb +3 -3
  73. data/lib/rubocop/cop/{style → layout}/multiline_method_definition_brace_layout.rb +1 -1
  74. data/lib/rubocop/cop/{style → layout}/multiline_operation_indentation.rb +6 -5
  75. data/lib/rubocop/cop/{style → layout}/rescue_ensure_alignment.rb +1 -1
  76. data/lib/rubocop/cop/{style → layout}/space_after_colon.rb +2 -2
  77. data/lib/rubocop/cop/{style → layout}/space_after_comma.rb +2 -2
  78. data/lib/rubocop/cop/{style → layout}/space_after_method_name.rb +1 -1
  79. data/lib/rubocop/cop/{style → layout}/space_after_not.rb +1 -1
  80. data/lib/rubocop/cop/{style → layout}/space_after_semicolon.rb +2 -2
  81. data/lib/rubocop/cop/{style → layout}/space_around_block_parameters.rb +7 -5
  82. data/lib/rubocop/cop/{style → layout}/space_around_equals_in_parameter_default.rb +1 -1
  83. data/lib/rubocop/cop/{style → layout}/space_around_keyword.rb +1 -1
  84. data/lib/rubocop/cop/{style → layout}/space_around_operators.rb +6 -2
  85. data/lib/rubocop/cop/{style → layout}/space_before_block_braces.rb +6 -2
  86. data/lib/rubocop/cop/{style → layout}/space_before_comma.rb +1 -1
  87. data/lib/rubocop/cop/{style → layout}/space_before_comment.rb +1 -1
  88. data/lib/rubocop/cop/{style → layout}/space_before_first_arg.rb +4 -2
  89. data/lib/rubocop/cop/{style → layout}/space_before_semicolon.rb +1 -1
  90. data/lib/rubocop/cop/{style → layout}/space_in_lambda_literal.rb +1 -1
  91. data/lib/rubocop/cop/{style → layout}/space_inside_array_percent_literal.rb +1 -1
  92. data/lib/rubocop/cop/{style → layout}/space_inside_block_braces.rb +3 -4
  93. data/lib/rubocop/cop/{style → layout}/space_inside_brackets.rb +1 -1
  94. data/lib/rubocop/cop/{style → layout}/space_inside_hash_literal_braces.rb +1 -1
  95. data/lib/rubocop/cop/{style → layout}/space_inside_parens.rb +1 -1
  96. data/lib/rubocop/cop/{style → layout}/space_inside_percent_literal_delimiters.rb +8 -7
  97. data/lib/rubocop/cop/{style → layout}/space_inside_range_literal.rb +1 -1
  98. data/lib/rubocop/cop/{style → layout}/space_inside_string_interpolation.rb +1 -1
  99. data/lib/rubocop/cop/{style → layout}/tab.rb +1 -1
  100. data/lib/rubocop/cop/{style → layout}/trailing_blank_lines.rb +1 -1
  101. data/lib/rubocop/cop/{style → layout}/trailing_whitespace.rb +2 -2
  102. data/lib/rubocop/cop/lint/ambiguous_block_association.rb +1 -1
  103. data/lib/rubocop/cop/lint/ambiguous_operator.rb +4 -4
  104. data/lib/rubocop/cop/lint/debugger.rb +0 -15
  105. data/lib/rubocop/cop/lint/duplicate_methods.rb +2 -1
  106. data/lib/rubocop/cop/lint/rescue_type.rb +81 -0
  107. data/lib/rubocop/cop/lint/script_permission.rb +42 -0
  108. data/lib/rubocop/cop/lint/useless_access_modifier.rb +1 -1
  109. data/lib/rubocop/cop/message_annotator.rb +23 -13
  110. data/lib/rubocop/cop/metrics/block_length.rb +1 -1
  111. data/lib/rubocop/cop/mixin/array_min_size.rb +59 -0
  112. data/lib/rubocop/cop/mixin/configurable_enforced_style.rb +10 -11
  113. data/lib/rubocop/cop/mixin/def_node.rb +1 -1
  114. data/lib/rubocop/cop/mixin/empty_lines_around_body.rb +1 -1
  115. data/lib/rubocop/cop/mixin/enforce_superclass.rb +36 -0
  116. data/lib/rubocop/cop/mixin/hash_alignment.rb +1 -1
  117. data/lib/rubocop/cop/mixin/multiline_expression_indentation.rb +7 -3
  118. data/lib/rubocop/cop/mixin/space_before_punctuation.rb +1 -1
  119. data/lib/rubocop/cop/performance/caller.rb +41 -0
  120. data/lib/rubocop/cop/performance/compare_with_block.rb +60 -14
  121. data/lib/rubocop/cop/performance/double_start_end_with.rb +2 -2
  122. data/lib/rubocop/cop/performance/redundant_merge.rb +2 -0
  123. data/lib/rubocop/cop/rails/action_filter.rb +1 -3
  124. data/lib/rubocop/cop/rails/application_job.rb +32 -0
  125. data/lib/rubocop/cop/rails/application_record.rb +32 -0
  126. data/lib/rubocop/cop/rails/blank.rb +9 -3
  127. data/lib/rubocop/cop/rails/output_safety.rb +59 -15
  128. data/lib/rubocop/cop/rails/present.rb +9 -3
  129. data/lib/rubocop/cop/rails/relative_date_constant.rb +35 -4
  130. data/lib/rubocop/cop/rails/reversible_migration.rb +82 -18
  131. data/lib/rubocop/cop/rails/save_bang.rb +7 -2
  132. data/lib/rubocop/cop/rails/skips_model_validations.rb +7 -0
  133. data/lib/rubocop/cop/registry.rb +4 -3
  134. data/lib/rubocop/cop/security/eval.rb +9 -3
  135. data/lib/rubocop/cop/style/and_or.rb +1 -1
  136. data/lib/rubocop/cop/style/block_delimiters.rb +11 -17
  137. data/lib/rubocop/cop/style/braces_around_hash_parameters.rb +1 -1
  138. data/lib/rubocop/cop/style/collection_methods.rb +1 -3
  139. data/lib/rubocop/cop/style/conditional_assignment.rb +1 -1
  140. data/lib/rubocop/cop/style/copyright.rb +2 -2
  141. data/lib/rubocop/cop/style/documentation_method.rb +1 -1
  142. data/lib/rubocop/cop/style/each_for_simple_loop.rb +2 -1
  143. data/lib/rubocop/cop/style/each_with_object.rb +10 -6
  144. data/lib/rubocop/cop/style/empty_case_condition.rb +2 -2
  145. data/lib/rubocop/cop/style/for.rb +4 -5
  146. data/lib/rubocop/cop/style/format_string.rb +49 -0
  147. data/lib/rubocop/cop/style/format_string_token.rb +141 -0
  148. data/lib/rubocop/cop/style/hash_syntax.rb +1 -1
  149. data/lib/rubocop/cop/style/identical_conditional_branches.rb +2 -2
  150. data/lib/rubocop/cop/style/if_unless_modifier_of_if_unless.rb +1 -1
  151. data/lib/rubocop/cop/style/inverse_methods.rb +10 -1
  152. data/lib/rubocop/cop/style/lambda.rb +9 -9
  153. data/lib/rubocop/cop/style/line_end_concatenation.rb +4 -0
  154. data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +3 -3
  155. data/lib/rubocop/cop/style/method_called_on_do_end_block.rb +1 -2
  156. data/lib/rubocop/cop/style/method_name.rb +8 -2
  157. data/lib/rubocop/cop/style/mixin_grouping.rb +41 -3
  158. data/lib/rubocop/cop/style/multiline_block_chain.rb +7 -11
  159. data/lib/rubocop/cop/style/multiple_comparison.rb +77 -0
  160. data/lib/rubocop/cop/style/next.rb +11 -22
  161. data/lib/rubocop/cop/style/parallel_assignment.rb +10 -19
  162. data/lib/rubocop/cop/style/percent_literal_delimiters.rb +2 -2
  163. data/lib/rubocop/cop/style/self_assignment.rb +4 -0
  164. data/lib/rubocop/cop/style/single_line_block_params.rb +23 -17
  165. data/lib/rubocop/cop/style/symbol_array.rb +24 -13
  166. data/lib/rubocop/cop/style/symbol_proc.rb +4 -0
  167. data/lib/rubocop/cop/style/ternary_parentheses.rb +1 -1
  168. data/lib/rubocop/cop/style/unneeded_interpolation.rb +4 -0
  169. data/lib/rubocop/cop/style/word_array.rb +33 -53
  170. data/lib/rubocop/cop/style/yoda_condition.rb +78 -0
  171. data/lib/rubocop/cop/team.rb +1 -14
  172. data/lib/rubocop/cop/util.rb +16 -0
  173. data/lib/rubocop/formatter/simple_text_formatter.rb +0 -11
  174. data/lib/rubocop/node_pattern.rb +52 -52
  175. data/lib/rubocop/options.rb +25 -0
  176. data/lib/rubocop/path_util.rb +17 -1
  177. data/lib/rubocop/result_cache.rb +8 -7
  178. data/lib/rubocop/rspec/expect_offense.rb +167 -0
  179. data/lib/rubocop/rspec/shared_examples.rb +0 -8
  180. data/lib/rubocop/rspec/support.rb +1 -0
  181. data/lib/rubocop/runner.rb +12 -2
  182. data/lib/rubocop/target_finder.rb +5 -0
  183. data/lib/rubocop/version.rb +1 -1
  184. metadata +101 -72
@@ -12,7 +12,7 @@ module RuboCop
12
12
  #
13
13
  # The supported styles are:
14
14
  #
15
- # * ruby19 - forces use of the 1.9 syntax (e.g. {a: 1}) when hashes have
15
+ # * ruby19 - forces use of the 1.9 syntax (e.g. `{a: 1}`) when hashes have
16
16
  # all symbols for keys
17
17
  # * hash_rockets - forces use of hash rockets for all hashes
18
18
  # * no_mixed_keys - simply checks for hashes with mixed syntaxes
@@ -42,7 +42,7 @@ module RuboCop
42
42
  # end
43
43
  #
44
44
  # @bad
45
- # switch foo
45
+ # case foo
46
46
  # when 1
47
47
  # do_x
48
48
  # when 2
@@ -52,7 +52,7 @@ module RuboCop
52
52
  # end
53
53
  #
54
54
  # @good
55
- # switch foo
55
+ # case foo
56
56
  # when 1
57
57
  # do_x
58
58
  # do_y
@@ -3,7 +3,7 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Style
6
- # Checks for if and unless statements used as modifers of other if or
6
+ # Checks for if and unless statements used as modifiers of other if or
7
7
  # unless statements.
8
8
  #
9
9
  # @example
@@ -26,8 +26,9 @@ module RuboCop
26
26
  # foo.any? { |f| f.even? }
27
27
  # foo != bar
28
28
  # foo == bar
29
+ # !!('foo' =~ /^\w+$/)
29
30
  class InverseMethods < Cop
30
- MSG = 'Use `%{inverse}` instead of inverting `%{method}`.'.freeze
31
+ MSG = 'Use `%<inverse>s` instead of inverting `%<method>s`.'.freeze
31
32
  EQUALITY_METHODS = %i[== != =~ !~ <= >= < >].freeze
32
33
 
33
34
  def_node_matcher :inverse_candidate?, <<-PATTERN
@@ -49,6 +50,7 @@ module RuboCop
49
50
  def on_send(node)
50
51
  inverse_candidate?(node) do |_method_call, method|
51
52
  return unless inverse_methods.key?(method)
53
+ return if negated?(node)
52
54
 
53
55
  add_offense(node,
54
56
  :expression,
@@ -60,6 +62,7 @@ module RuboCop
60
62
  def on_block(node)
61
63
  inverse_block?(node) do |_method_call, method, _block|
62
64
  return unless inverse_blocks.key?(method)
65
+ return if negated?(node) && negated?(node.parent)
63
66
 
64
67
  add_offense(node,
65
68
  :expression,
@@ -103,6 +106,8 @@ module RuboCop
103
106
  end
104
107
  end
105
108
 
109
+ private
110
+
106
111
  def inverse_methods
107
112
  @inverse_methods ||= cop_config['InverseMethods']
108
113
  .merge(cop_config['InverseMethods'].invert)
@@ -113,6 +118,10 @@ module RuboCop
113
118
  .merge(cop_config['InverseBlocks'].invert)
114
119
  end
115
120
 
121
+ def negated?(node)
122
+ node.parent.respond_to?(:method?) && node.parent.method?(:!)
123
+ end
124
+
116
125
  def not_to_receiver(node, method_call)
117
126
  Parser::Source::Range.new(node.loc.expression.source_buffer,
118
127
  node.loc.selector.begin_pos,
@@ -73,15 +73,15 @@ module RuboCop
73
73
  def_node_matcher :lambda_node?, '(block $(send nil :lambda) ...)'
74
74
 
75
75
  def on_block(node)
76
- lambda_node?(node) do |block_method|
77
- selector = block_method.source
76
+ return unless node.lambda?
78
77
 
79
- return unless offending_selector?(node, selector)
78
+ selector = node.send_node.source
80
79
 
81
- add_offense(node,
82
- block_method.source_range,
83
- message(node, selector))
84
- end
80
+ return unless offending_selector?(node, selector)
81
+
82
+ add_offense(node,
83
+ node.send_node.source_range,
84
+ message(node, selector))
85
85
  end
86
86
 
87
87
  private
@@ -189,13 +189,13 @@ module RuboCop
189
189
  def remove_unparenthesized_whitespaces(corrector, node)
190
190
  block_method, args = *node
191
191
  return unless unparenthesized_literal_args?(args)
192
- # First, remove leading whitespaces (beetween arrow and args)
192
+ # First, remove leading whitespaces (between arrow and args)
193
193
  corrector.remove_preceding(
194
194
  args.source_range,
195
195
  args.source_range.begin_pos - block_method.source_range.end_pos
196
196
  )
197
197
 
198
- # Then, remove trailing whitespaces (beetween args and 'do')
198
+ # Then, remove trailing whitespaces (between args and 'do')
199
199
  delta = node.loc.begin.begin_pos - args.source_range.end_pos - 1
200
200
  corrector.remove_preceding(node.loc.begin, delta)
201
201
  end
@@ -29,6 +29,10 @@ module RuboCop
29
29
  tLBRACK2].freeze
30
30
  QUOTE_DELIMITERS = %w[' "].freeze
31
31
 
32
+ def self.autocorrect_incompatible_with
33
+ [Style::UnneededInterpolation]
34
+ end
35
+
32
36
  def investigate(processed_source)
33
37
  processed_source.tokens.each_index do |index|
34
38
  check_token_set(index)
@@ -50,8 +50,7 @@ module RuboCop
50
50
  end
51
51
 
52
52
  def on_super(node)
53
- # super nodetype implies call with arguments.
54
- return if parentheses?(node)
53
+ return if node.parenthesized?
55
54
 
56
55
  add_offense(node, :keyword)
57
56
  end
@@ -93,7 +92,8 @@ module RuboCop
93
92
 
94
93
  def args_begin(node)
95
94
  loc = node.loc
96
- selector = node.super_type? ? loc.keyword : loc.selector
95
+ selector =
96
+ node.super_type? || node.yield_type? ? loc.keyword : loc.selector
97
97
  selector.end.resize(1)
98
98
  end
99
99
 
@@ -16,13 +16,12 @@ module RuboCop
16
16
  MSG = 'Avoid chaining a method call on a do...end block.'.freeze
17
17
 
18
18
  def on_block(node)
19
- method, _args, _body = *node
20
19
  # If the method that is chained on the do...end block is itself a
21
20
  # method with a block, we allow it. It's pretty safe to assume that
22
21
  # these calls are not missed by anyone reading code. We also want to
23
22
  # avoid double reporting of offenses checked by the
24
23
  # MultilineBlockChain cop.
25
- ignore_node(method)
24
+ ignore_node(node.send_node)
26
25
  end
27
26
 
28
27
  def on_send(node)
@@ -11,17 +11,23 @@ module RuboCop
11
11
 
12
12
  def on_def(node)
13
13
  name, = *node
14
- check_name(node, name, node.loc.name)
14
+ check_name(node, sanitize_name(name), node.loc.name)
15
15
  end
16
16
 
17
17
  def on_defs(node)
18
18
  _object, name, = *node
19
- check_name(node, name, node.loc.name)
19
+ check_name(node, sanitize_name(name), node.loc.name)
20
20
  end
21
21
 
22
+ private
23
+
22
24
  def message(style)
23
25
  format('Use %s for method names.', style)
24
26
  end
27
+
28
+ def sanitize_name(name)
29
+ name.to_s.delete('@').to_sym
30
+ end
25
31
  end
26
32
  end
27
33
  end
@@ -46,6 +46,21 @@ module RuboCop
46
46
  check(node)
47
47
  end
48
48
 
49
+ def autocorrect(node)
50
+ if separated_style?
51
+ range = node.loc.expression
52
+ correction = separate_mixins(node)
53
+ else
54
+ mixins = sibling_mixins(node)
55
+ mixins.unshift(node)
56
+
57
+ range = node.loc.expression.join(mixins.last.loc.expression)
58
+ correction = group_mixins(node, mixins)
59
+ end
60
+
61
+ ->(corrector) { corrector.replace(range, correction) }
62
+ end
63
+
49
64
  private
50
65
 
51
66
  def check(send_node)
@@ -57,7 +72,7 @@ module RuboCop
57
72
  end
58
73
 
59
74
  def check_grouped_style(send_node)
60
- return unless sibling_mixins?(send_node)
75
+ return if sibling_mixins(send_node).empty?
61
76
 
62
77
  add_offense(send_node, :expression)
63
78
  end
@@ -68,11 +83,11 @@ module RuboCop
68
83
  add_offense(send_node, :expression)
69
84
  end
70
85
 
71
- def sibling_mixins?(send_node)
86
+ def sibling_mixins(send_node)
72
87
  siblings = send_node.parent.each_child_node(:send)
73
88
  .reject { |sibling| sibling == send_node }
74
89
 
75
- siblings.any? do |sibling_node|
90
+ siblings.select do |sibling_node|
76
91
  sibling_node.method_name == send_node.method_name
77
92
  end
78
93
  end
@@ -91,6 +106,29 @@ module RuboCop
91
106
  def separated_style?
92
107
  style == :separated
93
108
  end
109
+
110
+ def separate_mixins(node)
111
+ _receiver, mixin, *args = *node
112
+ args.reverse!
113
+ first_mixin = String.new("#{mixin} #{args.first.source}")
114
+
115
+ args[1..-1].inject(first_mixin) do |replacement, arg|
116
+ replacement << "\n#{indent(node)}#{mixin} #{arg.source}"
117
+ end
118
+ end
119
+
120
+ def group_mixins(node, mixins)
121
+ _receiver, mixin, *_args = *node
122
+ all_mixin_arguments = mixins.reverse.flat_map do |m|
123
+ m.arguments.map(&:source)
124
+ end
125
+
126
+ "#{mixin} #{all_mixin_arguments.join(', ')}"
127
+ end
128
+
129
+ def indent(node)
130
+ ' ' * node.loc.column
131
+ end
94
132
  end
95
133
  end
96
134
  end
@@ -17,20 +17,16 @@ module RuboCop
17
17
  MSG = 'Avoid multi-line chains of blocks.'.freeze
18
18
 
19
19
  def on_block(node)
20
- method, _args, _body = *node
21
- method.each_node(:send) do |send_node|
22
- receiver, _method_name, *_args = *send_node
23
- next unless receiver && receiver.block_type?
20
+ node.send_node.each_node(:send) do |send_node|
21
+ receiver = send_node.receiver
24
22
 
25
- # The begin and end could also be braces, but we call the
26
- # variables do... and end...
27
- do_kw_loc = receiver.loc.begin
28
- end_kw_loc = receiver.loc.end
29
- next if do_kw_loc.line == end_kw_loc.line
23
+ next unless receiver && receiver.block_type? && receiver.multiline?
24
+
25
+ range = range_between(receiver.loc.end.begin_pos,
26
+ node.send_node.source_range.end_pos)
30
27
 
31
- range = range_between(end_kw_loc.begin_pos,
32
- method.source_range.end_pos)
33
28
  add_offense(nil, range)
29
+
34
30
  # Done. If there are more blocks in the chain, they will be
35
31
  # found by subsequent calls to on_block.
36
32
  break
@@ -0,0 +1,77 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Style
6
+ # This cop checks against comparing a variable with multiple items, where
7
+ # `Array#include?` could be used instead to avoid code repetition.
8
+ #
9
+ # @example
10
+ # # bad
11
+ # a = 'a'
12
+ # foo if a == 'a' || a == 'b' || a == 'c'
13
+ #
14
+ # # good
15
+ # a = 'a'
16
+ # foo if ['a', 'b', 'c'].include?(a)
17
+ class MultipleComparison < Cop
18
+ MSG = 'Avoid comparing a variable with multiple items' \
19
+ 'in a conditional, use `Array#include?` instead.'.freeze
20
+
21
+ def on_if(node)
22
+ return unless nested_variable_comparison?(node.condition)
23
+ add_offense(node, :expression)
24
+ end
25
+
26
+ private
27
+
28
+ def_node_matcher :simple_double_comparison?, '(send $lvar :== $lvar)'
29
+ def_node_matcher :simple_comparison?, <<-PATTERN
30
+ {(send $lvar :== _)
31
+ (send _ :== $lvar)}
32
+ PATTERN
33
+
34
+ def nested_variable_comparison?(node)
35
+ return false unless nested_comparison?(node)
36
+ variables_in_node(node).count == 1
37
+ end
38
+
39
+ def variables_in_node(node)
40
+ if node.or_type?
41
+ node.node_parts
42
+ .flat_map { |node_part| variables_in_node(node_part) }
43
+ .uniq
44
+ else
45
+ variables_in_simple_node(node)
46
+ end
47
+ end
48
+
49
+ def variables_in_simple_node(node)
50
+ simple_double_comparison?(node) do |var1, var2|
51
+ return [variable_name(var1), variable_name(var2)]
52
+ end
53
+ simple_comparison?(node) do |var|
54
+ return [variable_name(var)]
55
+ end
56
+ []
57
+ end
58
+
59
+ def variable_name(node)
60
+ node.children[0]
61
+ end
62
+
63
+ def nested_comparison?(node)
64
+ if node.or_type?
65
+ node.node_parts.all? { |node_part| comparison? node_part }
66
+ else
67
+ false
68
+ end
69
+ end
70
+
71
+ def comparison?(node)
72
+ simple_comparison?(node) || nested_comparison?(node)
73
+ end
74
+ end
75
+ end
76
+ end
77
+ end
@@ -8,7 +8,7 @@ module RuboCop
8
8
  # @example
9
9
  # # bad
10
10
  # [1, 2].each do |a|
11
- # if a == 1 do
11
+ # if a == 1
12
12
  # puts a
13
13
  # end
14
14
  # end
@@ -24,11 +24,6 @@ module RuboCop
24
24
 
25
25
  MSG = 'Use `next` to skip iteration.'.freeze
26
26
  EXIT_TYPES = %i[break return].freeze
27
- EACH_ = 'each_'.freeze
28
- ENUMERATORS = %i[collect collect_concat detect downto each
29
- find find_all find_index inject loop map!
30
- map reduce reject reject! reverse_each select
31
- select! times upto].freeze
32
27
 
33
28
  def investigate(_processed_source)
34
29
  # When correcting nested offenses, we need to keep track of how much
@@ -37,32 +32,26 @@ module RuboCop
37
32
  end
38
33
 
39
34
  def on_block(node)
40
- block_owner, _, body = *node
41
- return unless block_owner.send_type?
42
- return unless body && ends_with_condition?(body)
35
+ return unless node.send_node.send_type? &&
36
+ node.send_node.enumerator_method?
43
37
 
44
- _, method_name = *block_owner
45
- return unless enumerator?(method_name)
46
-
47
- offense_node = offense_node(body)
48
- add_offense(offense_node, offense_location(offense_node), MSG)
38
+ check(node)
49
39
  end
50
40
 
51
41
  def on_while(node)
52
- return unless node.body && ends_with_condition?(node.body)
53
-
54
- offending_node = offense_node(node.body)
55
-
56
- add_offense(offending_node, offense_location(offending_node), MSG)
42
+ check(node)
57
43
  end
58
44
  alias on_until on_while
59
45
  alias on_for on_while
60
46
 
61
47
  private
62
48
 
63
- def enumerator?(method_name)
64
- ENUMERATORS.include?(method_name) ||
65
- method_name.to_s.start_with?(EACH_)
49
+ def check(node)
50
+ return unless node.body && ends_with_condition?(node.body)
51
+
52
+ offending_node = offense_node(node.body)
53
+
54
+ add_offense(offending_node, offense_location(offending_node))
66
55
  end
67
56
 
68
57
  def ends_with_condition?(body)
@@ -142,13 +142,18 @@ module RuboCop
142
142
 
143
143
  @assignments.each do |other|
144
144
  _other_lhs, other_rhs = *other
145
- if ((var = var_name(my_lhs)) && uses_var?(other_rhs, var)) ||
146
- (my_lhs.asgn_method_call? && accesses?(other_rhs, my_lhs))
147
- yield other
148
- end
145
+
146
+ next unless dependency?(my_lhs, other_rhs)
147
+
148
+ yield other
149
149
  end
150
150
  end
151
151
 
152
+ def dependency?(lhs, rhs)
153
+ uses_var?(rhs, var_name(lhs)) ||
154
+ lhs.send_type? && lhs.assignment_method? && accesses?(rhs, lhs)
155
+ end
156
+
152
157
  # `lhs` is an assignment method call like `obj.attr=` or `ary[idx]=`.
153
158
  # Does `rhs` access the same value which is assigned by `lhs`?
154
159
  def accesses?(rhs, lhs)
@@ -164,21 +169,7 @@ module RuboCop
164
169
  end
165
170
 
166
171
  def modifier_statement?(node)
167
- node &&
168
- ((node.if_type? && node.modifier_form?) ||
169
- ((node.while_type? || node.until_type?) && modifier_while?(node)))
170
- end
171
-
172
- def modifier_while?(node)
173
- node.loc.respond_to?(:keyword) &&
174
- %w[while until].include?(node.loc.keyword.source) &&
175
- node.modifier_form?
176
- end
177
-
178
- def rescue_modifier_old?(node)
179
- node && node.rescue_type? &&
180
- (node.parent.nil? || !(node.parent.kwbegin_type? ||
181
- node.parent.ensure_type?))
172
+ node && %i[if while until].include?(node.type) && node.modifier_form?
182
173
  end
183
174
 
184
175
  # An internal class for correcting parallel assignment