rubocop 0.48.1 → 0.49.0

Sign up to get free protection for your applications and to get access to all the features.
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