rubocop 0.46.0 → 0.47.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of rubocop might be problematic. Click here for more details.

Files changed (214) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE.txt +1 -1
  3. data/README.md +77 -2
  4. data/config/default.yml +151 -74
  5. data/config/disabled.yml +9 -0
  6. data/config/enabled.yml +49 -9
  7. data/lib/rubocop.rb +36 -8
  8. data/lib/rubocop/ast/builder.rb +59 -0
  9. data/lib/rubocop/ast/node.rb +607 -0
  10. data/lib/rubocop/ast/node/array_node.rb +45 -0
  11. data/lib/rubocop/ast/node/case_node.rb +63 -0
  12. data/lib/rubocop/ast/node/for_node.rb +53 -0
  13. data/lib/rubocop/ast/node/hash_node.rb +102 -0
  14. data/lib/rubocop/ast/node/if_node.rb +136 -0
  15. data/lib/rubocop/ast/node/keyword_splat_node.rb +45 -0
  16. data/lib/rubocop/ast/node/mixin/conditional_node.rb +45 -0
  17. data/lib/rubocop/ast/node/mixin/hash_element_node.rb +125 -0
  18. data/lib/rubocop/ast/node/mixin/modifier_node.rb +17 -0
  19. data/lib/rubocop/ast/node/pair_node.rb +64 -0
  20. data/lib/rubocop/ast/node/until_node.rb +43 -0
  21. data/lib/rubocop/ast/node/when_node.rb +61 -0
  22. data/lib/rubocop/ast/node/while_node.rb +43 -0
  23. data/lib/rubocop/ast/sexp.rb +16 -0
  24. data/lib/rubocop/{ast_node → ast}/traversal.rb +1 -1
  25. data/lib/rubocop/cli.rb +18 -14
  26. data/lib/rubocop/comment_config.rb +1 -3
  27. data/lib/rubocop/config.rb +93 -35
  28. data/lib/rubocop/config_loader.rb +1 -1
  29. data/lib/rubocop/cop/badge.rb +73 -0
  30. data/lib/rubocop/cop/bundler/duplicated_gem.rb +2 -2
  31. data/lib/rubocop/cop/bundler/ordered_gems.rb +43 -3
  32. data/lib/rubocop/cop/commissioner.rb +17 -6
  33. data/lib/rubocop/cop/cop.rb +25 -112
  34. data/lib/rubocop/cop/lint/ambiguous_operator.rb +9 -4
  35. data/lib/rubocop/cop/lint/ambiguous_regexp_literal.rb +7 -0
  36. data/lib/rubocop/cop/lint/assignment_in_condition.rb +18 -4
  37. data/lib/rubocop/cop/lint/block_alignment.rb +40 -9
  38. data/lib/rubocop/cop/lint/circular_argument_reference.rb +14 -0
  39. data/lib/rubocop/cop/lint/condition_position.rb +14 -16
  40. data/lib/rubocop/cop/lint/debugger.rb +28 -0
  41. data/lib/rubocop/cop/lint/def_end_alignment.rb +21 -1
  42. data/lib/rubocop/cop/lint/deprecated_class_methods.rb +13 -1
  43. data/lib/rubocop/cop/lint/duplicate_case_condition.rb +26 -22
  44. data/lib/rubocop/cop/lint/duplicate_methods.rb +15 -1
  45. data/lib/rubocop/cop/lint/duplicated_key.rb +16 -8
  46. data/lib/rubocop/cop/lint/each_with_object_argument.rb +9 -0
  47. data/lib/rubocop/cop/lint/else_layout.rb +26 -29
  48. data/lib/rubocop/cop/lint/empty_ensure.rb +38 -0
  49. data/lib/rubocop/cop/lint/empty_expression.rb +11 -1
  50. data/lib/rubocop/cop/lint/empty_interpolation.rb +8 -0
  51. data/lib/rubocop/cop/lint/empty_when.rb +14 -16
  52. data/lib/rubocop/cop/lint/end_alignment.rb +48 -28
  53. data/lib/rubocop/cop/lint/end_in_method.rb +23 -0
  54. data/lib/rubocop/cop/lint/ensure_return.rb +21 -0
  55. data/lib/rubocop/cop/lint/float_out_of_range.rb +5 -0
  56. data/lib/rubocop/cop/lint/format_parameter_mismatch.rb +29 -4
  57. data/lib/rubocop/cop/lint/handle_exceptions.rb +40 -0
  58. data/lib/rubocop/cop/lint/implicit_string_concatenation.rb +7 -2
  59. data/lib/rubocop/cop/lint/ineffective_access_modifier.rb +11 -2
  60. data/lib/rubocop/cop/lint/invalid_character_literal.rb +3 -0
  61. data/lib/rubocop/cop/lint/literal_in_condition.rb +34 -36
  62. data/lib/rubocop/cop/lint/literal_in_interpolation.rb +8 -0
  63. data/lib/rubocop/cop/lint/loop.rb +36 -0
  64. data/lib/rubocop/cop/lint/multiple_compare.rb +46 -0
  65. data/lib/rubocop/cop/lint/nested_method_definition.rb +22 -0
  66. data/lib/rubocop/cop/lint/next_without_accumulator.rb +5 -0
  67. data/lib/rubocop/cop/lint/parentheses_as_grouped_expression.rb +8 -0
  68. data/lib/rubocop/cop/lint/percent_string_array.rb +27 -13
  69. data/lib/rubocop/cop/lint/percent_symbol_array.rb +14 -4
  70. data/lib/rubocop/cop/lint/rand_one.rb +7 -3
  71. data/lib/rubocop/cop/lint/require_parentheses.rb +20 -19
  72. data/lib/rubocop/cop/lint/rescue_exception.rb +20 -0
  73. data/lib/rubocop/cop/lint/safe_navigation_chain.rb +66 -0
  74. data/lib/rubocop/cop/lint/shadowed_exception.rb +6 -1
  75. data/lib/rubocop/cop/lint/shadowing_outer_local_variable.rb +24 -0
  76. data/lib/rubocop/cop/lint/string_conversion_in_interpolation.rb +8 -0
  77. data/lib/rubocop/cop/lint/underscore_prefixed_variable_name.rb +24 -0
  78. data/lib/rubocop/cop/lint/unified_integer.rb +5 -0
  79. data/lib/rubocop/cop/lint/unneeded_disable.rb +2 -2
  80. data/lib/rubocop/cop/lint/unneeded_splat_expansion.rb +5 -0
  81. data/lib/rubocop/cop/lint/unreachable_code.rb +17 -0
  82. data/lib/rubocop/cop/lint/unused_block_argument.rb +2 -0
  83. data/lib/rubocop/cop/lint/unused_method_argument.rb +10 -0
  84. data/lib/rubocop/cop/lint/useless_access_modifier.rb +28 -1
  85. data/lib/rubocop/cop/lint/useless_assignment.rb +18 -0
  86. data/lib/rubocop/cop/lint/useless_comparison.rb +3 -1
  87. data/lib/rubocop/cop/lint/useless_else_without_rescue.rb +16 -1
  88. data/lib/rubocop/cop/lint/useless_setter_call.rb +16 -4
  89. data/lib/rubocop/cop/lint/void.rb +52 -0
  90. data/lib/rubocop/cop/message_annotator.rb +102 -0
  91. data/lib/rubocop/cop/metrics/block_length.rb +6 -0
  92. data/lib/rubocop/cop/metrics/block_nesting.rb +17 -5
  93. data/lib/rubocop/cop/metrics/line_length.rb +11 -4
  94. data/lib/rubocop/cop/metrics/perceived_complexity.rb +1 -2
  95. data/lib/rubocop/cop/mixin/array_syntax.rb +2 -11
  96. data/lib/rubocop/cop/mixin/configurable_enforced_style.rb +12 -5
  97. data/lib/rubocop/cop/mixin/configurable_formatting.rb +48 -0
  98. data/lib/rubocop/cop/mixin/configurable_max.rb +3 -3
  99. data/lib/rubocop/cop/mixin/configurable_naming.rb +5 -33
  100. data/lib/rubocop/cop/mixin/configurable_numbering.rb +6 -47
  101. data/lib/rubocop/cop/mixin/documentation_comment.rb +7 -1
  102. data/lib/rubocop/cop/mixin/duplication.rb +46 -0
  103. data/lib/rubocop/cop/mixin/end_keyword_alignment.rb +2 -2
  104. data/lib/rubocop/cop/mixin/frozen_string_literal.rb +14 -11
  105. data/lib/rubocop/cop/mixin/hash_alignment.rb +114 -0
  106. data/lib/rubocop/cop/mixin/multiline_expression_indentation.rb +3 -3
  107. data/lib/rubocop/cop/mixin/negative_conditional.rb +21 -7
  108. data/lib/rubocop/cop/mixin/on_method_def.rb +14 -0
  109. data/lib/rubocop/cop/mixin/on_normal_if_unless.rb +1 -24
  110. data/lib/rubocop/cop/mixin/statement_modifier.rb +8 -13
  111. data/lib/rubocop/cop/mixin/target_ruby_version.rb +16 -0
  112. data/lib/rubocop/cop/mixin/trailing_comma.rb +2 -3
  113. data/lib/rubocop/cop/offense.rb +1 -1
  114. data/lib/rubocop/cop/performance/case_when_splat.rb +56 -59
  115. data/lib/rubocop/cop/performance/detect.rb +2 -2
  116. data/lib/rubocop/cop/performance/flat_map.rb +3 -3
  117. data/lib/rubocop/cop/performance/redundant_merge.rb +3 -6
  118. data/lib/rubocop/cop/performance/regexp_match.rb +201 -0
  119. data/lib/rubocop/cop/rails/delegate.rb +2 -2
  120. data/lib/rubocop/cop/rails/delegate_allow_blank.rb +10 -19
  121. data/lib/rubocop/cop/rails/enum_uniqueness.rb +12 -40
  122. data/lib/rubocop/cop/rails/file_path.rb +80 -0
  123. data/lib/rubocop/cop/rails/find_each.rb +5 -14
  124. data/lib/rubocop/cop/rails/http_positional_arguments.rb +30 -24
  125. data/lib/rubocop/cop/rails/not_null_column.rb +23 -0
  126. data/lib/rubocop/cop/rails/reversible_migration.rb +217 -0
  127. data/lib/rubocop/cop/rails/safe_navigation.rb +4 -2
  128. data/lib/rubocop/cop/rails/skips_model_validations.rb +46 -0
  129. data/lib/rubocop/cop/rails/time_zone.rb +1 -1
  130. data/lib/rubocop/cop/rails/uniq_before_pluck.rb +7 -5
  131. data/lib/rubocop/cop/registry.rb +170 -0
  132. data/lib/rubocop/cop/{lint → security}/eval.rb +7 -1
  133. data/lib/rubocop/cop/security/marshal_load.rb +33 -0
  134. data/lib/rubocop/cop/security/yaml_load.rb +37 -0
  135. data/lib/rubocop/cop/style/align_hash.rb +138 -169
  136. data/lib/rubocop/cop/style/and_or.rb +1 -1
  137. data/lib/rubocop/cop/style/braces_around_hash_parameters.rb +10 -15
  138. data/lib/rubocop/cop/style/case_indentation.rb +36 -27
  139. data/lib/rubocop/cop/style/conditional_assignment.rb +64 -47
  140. data/lib/rubocop/cop/style/each_with_object.rb +4 -1
  141. data/lib/rubocop/cop/style/else_alignment.rb +14 -20
  142. data/lib/rubocop/cop/style/empty_case_condition.rb +16 -25
  143. data/lib/rubocop/cop/style/empty_else.rb +20 -22
  144. data/lib/rubocop/cop/style/empty_literal.rb +4 -4
  145. data/lib/rubocop/cop/style/empty_method.rb +12 -6
  146. data/lib/rubocop/cop/style/encoding.rb +1 -1
  147. data/lib/rubocop/cop/style/file_name.rb +24 -4
  148. data/lib/rubocop/cop/style/first_method_argument_line_break.rb +1 -1
  149. data/lib/rubocop/cop/style/format_string.rb +17 -48
  150. data/lib/rubocop/cop/style/frozen_string_literal_comment.rb +40 -11
  151. data/lib/rubocop/cop/style/guard_clause.rb +11 -17
  152. data/lib/rubocop/cop/style/hash_syntax.rb +24 -42
  153. data/lib/rubocop/cop/style/identical_conditional_branches.rb +40 -28
  154. data/lib/rubocop/cop/style/if_inside_else.rb +6 -9
  155. data/lib/rubocop/cop/style/if_unless_modifier.rb +16 -25
  156. data/lib/rubocop/cop/style/if_unless_modifier_of_if_unless.rb +3 -9
  157. data/lib/rubocop/cop/style/indent_array.rb +1 -1
  158. data/lib/rubocop/cop/style/indentation_width.rb +29 -60
  159. data/lib/rubocop/cop/style/infinite_loop.rb +21 -22
  160. data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +86 -0
  161. data/lib/rubocop/cop/style/{method_call_parentheses.rb → method_call_without_args_parentheses.rb} +8 -1
  162. data/lib/rubocop/cop/style/missing_else.rb +40 -14
  163. data/lib/rubocop/cop/style/multiline_if_modifier.rb +5 -15
  164. data/lib/rubocop/cop/style/multiline_if_then.rb +14 -8
  165. data/lib/rubocop/cop/style/multiline_method_call_indentation.rb +3 -3
  166. data/lib/rubocop/cop/style/multiline_ternary_operator.rb +1 -5
  167. data/lib/rubocop/cop/style/mutable_constant.rb +3 -2
  168. data/lib/rubocop/cop/style/negated_if.rb +3 -19
  169. data/lib/rubocop/cop/style/negated_while.rb +2 -17
  170. data/lib/rubocop/cop/style/nested_modifier.rb +16 -43
  171. data/lib/rubocop/cop/style/nested_ternary_operator.rb +3 -5
  172. data/lib/rubocop/cop/style/next.rb +23 -21
  173. data/lib/rubocop/cop/style/non_nil_check.rb +2 -3
  174. data/lib/rubocop/cop/style/not.rb +1 -3
  175. data/lib/rubocop/cop/style/numeric_literals.rb +2 -2
  176. data/lib/rubocop/cop/style/one_line_conditional.rb +12 -22
  177. data/lib/rubocop/cop/style/option_hash.rb +4 -15
  178. data/lib/rubocop/cop/style/parallel_assignment.rb +1 -3
  179. data/lib/rubocop/cop/style/parentheses_around_condition.rb +8 -12
  180. data/lib/rubocop/cop/style/percent_q_literals.rb +15 -12
  181. data/lib/rubocop/cop/style/redundant_freeze.rb +3 -2
  182. data/lib/rubocop/cop/style/redundant_parentheses.rb +27 -4
  183. data/lib/rubocop/cop/style/redundant_return.rb +4 -8
  184. data/lib/rubocop/cop/style/safe_navigation.rb +13 -6
  185. data/lib/rubocop/cop/style/space_after_colon.rb +2 -4
  186. data/lib/rubocop/cop/style/space_around_block_parameters.rb +1 -1
  187. data/lib/rubocop/cop/style/space_around_operators.rb +15 -13
  188. data/lib/rubocop/cop/style/string_methods.rb +1 -3
  189. data/lib/rubocop/cop/style/symbol_array.rb +1 -5
  190. data/lib/rubocop/cop/style/ternary_parentheses.rb +5 -6
  191. data/lib/rubocop/cop/style/trailing_comma_in_arguments.rb +2 -5
  192. data/lib/rubocop/cop/style/trailing_comma_in_literal.rb +1 -1
  193. data/lib/rubocop/cop/style/unless_else.rb +1 -5
  194. data/lib/rubocop/cop/style/when_then.rb +4 -2
  195. data/lib/rubocop/cop/style/while_until_do.rb +9 -13
  196. data/lib/rubocop/cop/style/while_until_modifier.rb +12 -11
  197. data/lib/rubocop/cop/style/word_array.rb +5 -9
  198. data/lib/rubocop/cop/team.rb +16 -15
  199. data/lib/rubocop/cop/util.rb +13 -3
  200. data/lib/rubocop/formatter/clang_style_formatter.rb +2 -2
  201. data/lib/rubocop/formatter/disabled_config_formatter.rb +2 -1
  202. data/lib/rubocop/magic_comment.rb +196 -0
  203. data/lib/rubocop/options.rb +5 -4
  204. data/lib/rubocop/processed_source.rb +1 -1
  205. data/lib/rubocop/rspec/cop_helper.rb +9 -0
  206. data/lib/rubocop/rspec/shared_examples.rb +1 -1
  207. data/lib/rubocop/runner.rb +7 -2
  208. data/lib/rubocop/version.rb +1 -1
  209. metadata +41 -14
  210. data/lib/rubocop/ast_node.rb +0 -624
  211. data/lib/rubocop/ast_node/builder.rb +0 -30
  212. data/lib/rubocop/ast_node/sexp.rb +0 -13
  213. data/lib/rubocop/cop/mixin/hash_node.rb +0 -14
  214. data/lib/rubocop/cop/mixin/if_node.rb +0 -42
@@ -44,7 +44,7 @@ module RuboCop
44
44
  def on_conditionals(node)
45
45
  condition_node, = *node
46
46
 
47
- condition_node.each_node(:and, :or) do |logical_node|
47
+ condition_node.each_node(*LOGICAL_OPERATOR_NODES) do |logical_node|
48
48
  process_logical_op(logical_node)
49
49
  end
50
50
  end
@@ -11,25 +11,24 @@ module RuboCop
11
11
  MSG = '%s curly braces around a hash parameter.'.freeze
12
12
 
13
13
  def on_send(node)
14
+ return if node.asgn_method_call?
15
+
14
16
  _receiver, method_name, *args = *node
15
17
 
16
- # Discard attr writer methods.
17
- return if node.asgn_method_call?
18
- # Discard operator methods.
19
18
  return if operator?(method_name)
19
+ return if args.empty?
20
20
 
21
- # We care only for the last argument.
22
- arg = args.last
21
+ return unless args.last.hash_type? && !args.last.pairs.empty?
23
22
 
24
- check(arg, args) if non_empty_hash?(arg)
23
+ check(args.last, args)
25
24
  end
26
25
 
27
26
  private
28
27
 
29
28
  def check(arg, args)
30
- if style == :braces && !braces?(arg)
29
+ if style == :braces && !arg.braces?
31
30
  add_offense(arg.parent, arg.source_range, format(MSG, 'Missing'))
32
- elsif style == :no_braces && braces?(arg)
31
+ elsif style == :no_braces && arg.braces?
33
32
  add_offense(arg.parent, arg.source_range,
34
33
  format(MSG, 'Redundant'))
35
34
  elsif style == :context_dependent
@@ -38,8 +37,8 @@ module RuboCop
38
37
  end
39
38
 
40
39
  def check_context_dependent(arg, args)
41
- braces_around_second_from_end = args.length > 1 && args[-2].hash_type?
42
- if braces?(arg)
40
+ braces_around_second_from_end = args.size > 1 && args[-2].hash_type?
41
+ if arg.braces?
43
42
  unless braces_around_second_from_end
44
43
  add_offense(arg.parent, arg.source_range,
45
44
  format(MSG, 'Redundant'))
@@ -57,7 +56,7 @@ module RuboCop
57
56
  _receiver, _method_name, *args = *send_node
58
57
  node = args.last
59
58
  lambda do |corrector|
60
- if braces?(node)
59
+ if node.braces?
61
60
  remove_braces_with_whitespace(corrector, node)
62
61
  else
63
62
  add_braces(corrector, node)
@@ -100,10 +99,6 @@ module RuboCop
100
99
  corrector.insert_after(node.source_range, '}')
101
100
  end
102
101
 
103
- def non_empty_hash?(arg)
104
- arg && arg.hash_type? && !arg.children.empty?
105
- end
106
-
107
102
  def braces?(arg)
108
103
  arg.loc.begin
109
104
  end
@@ -11,39 +11,41 @@ module RuboCop
11
11
  include AutocorrectAlignment
12
12
  include ConfigurableEnforcedStyle
13
13
 
14
- def on_case(case_node)
15
- _condition, *whens, _else = *case_node
16
-
17
- base = style
18
- indent = cop_config['IndentOneStep']
19
- base_column = base_column(case_node, base)
14
+ MSG = 'Indent `when` %s `%s`.'.freeze
20
15
 
21
- whens.each do |when_node|
22
- check_when(when_node, case_node, base, indent, base_column)
16
+ def on_case(case_node)
17
+ case_node.each_when do |when_node|
18
+ check_when(when_node)
23
19
  end
24
20
  end
25
21
 
26
22
  private
27
23
 
28
- def check_when(when_node, case_node, base, indent, base_column)
29
- pos = when_node.loc.keyword
30
- expected_column = base_column +
31
- (indent ? configured_indentation_width : 0)
32
- if pos.column == expected_column
24
+ def check_when(when_node)
25
+ when_column = when_node.loc.keyword.column
26
+ base_column = base_column(when_node.parent, style)
27
+
28
+ if when_column == base_column + indentation_width
33
29
  correct_style_detected
34
30
  else
35
- incorrect_style(when_node, case_node, base, pos, indent)
31
+ incorrect_style(when_node)
36
32
  end
37
33
  end
38
34
 
39
- def incorrect_style(when_node, case_node, base, pos, indent)
40
- msg = 'Indent `when` ' + if indent
41
- "one step more than `#{base}`."
42
- else
43
- "as deep as `#{base}`."
44
- end
45
- add_offense(when_node, pos, msg) do
46
- if pos.column == base_column(case_node, alternative_style)
35
+ def indent_one_step?
36
+ cop_config['IndentOneStep']
37
+ end
38
+
39
+ def indentation_width
40
+ indent_one_step? ? configured_indentation_width : 0
41
+ end
42
+
43
+ def incorrect_style(when_node)
44
+ when_column = when_node.loc.keyword.column
45
+ base_column = base_column(when_node.parent, alternative_style)
46
+
47
+ add_offense(when_node, :keyword, message(style)) do
48
+ if when_column == base_column
47
49
  opposite_style_detected
48
50
  else
49
51
  unrecognized_style_detected
@@ -51,8 +53,10 @@ module RuboCop
51
53
  end
52
54
  end
53
55
 
54
- def parameter_name
55
- 'IndentWhenRelativeTo'
56
+ def message(base)
57
+ depth = indent_one_step? ? 'one step more than' : 'as deep as'
58
+
59
+ format(MSG, depth, base)
56
60
  end
57
61
 
58
62
  def base_column(case_node, base)
@@ -64,9 +68,12 @@ module RuboCop
64
68
 
65
69
  def autocorrect(node)
66
70
  whitespace = whitespace_range(node)
71
+
67
72
  return false unless whitespace.source.strip.empty?
68
73
 
69
- ->(corrector) { corrector.replace(whitespace, replacement(node)) }
74
+ lambda do |corrector|
75
+ corrector.replace(whitespace, replacement(node))
76
+ end
70
77
  end
71
78
 
72
79
  def whitespace_range(node)
@@ -78,9 +85,11 @@ module RuboCop
78
85
 
79
86
  def replacement(node)
80
87
  case_node = node.each_ancestor(:case).first
81
- base_type = cop_config[parameter_name] == 'end' ? :end : :case
88
+ base_type = cop_config[style_parameter_name] == 'end' ? :end : :case
89
+
82
90
  column = base_column(case_node, base_type)
83
- column += configured_indentation_width if cop_config['IndentOneStep']
91
+ column += indentation_width
92
+
84
93
  ' ' * column
85
94
  end
86
95
  end
@@ -8,7 +8,7 @@ module RuboCop
8
8
  module ConditionalAssignmentHelper
9
9
  EQUAL = '='.freeze
10
10
  END_ALIGNMENT = 'Lint/EndAlignment'.freeze
11
- ALIGN_WITH = 'AlignWith'.freeze
11
+ ALIGN_WITH = 'EnforcedStyleAlignWith'.freeze
12
12
  KEYWORD = 'keyword'.freeze
13
13
 
14
14
  # `elsif` branches show up in the `node` as an `else`. We need
@@ -92,6 +92,12 @@ module RuboCop
92
92
  method_name.to_s.end_with?(EQUAL) &&
93
93
  ![:!=, :==, :===, :>=, :<=].include?(method_name)
94
94
  end
95
+
96
+ def assignment_rhs_exist?(node)
97
+ parent = node.parent
98
+ return true unless parent
99
+ !(parent.mlhs_type? || parent.resbody_type?)
100
+ end
95
101
  end
96
102
 
97
103
  # Check for `if` and `case` statements where each branch is used for
@@ -190,7 +196,6 @@ module RuboCop
190
196
  # bar = 2
191
197
  # end
192
198
  class ConditionalAssignment < Cop
193
- include IfNode
194
199
  include ConditionalAssignmentHelper
195
200
  include ConfigurableEnforcedStyle
196
201
  include IgnoredNode
@@ -201,10 +206,8 @@ module RuboCop
201
206
  'Assign variables inside of conditionals'.freeze
202
207
  VARIABLE_ASSIGNMENT_TYPES =
203
208
  [:casgn, :cvasgn, :gvasgn, :ivasgn, :lvasgn].freeze
204
- ASSIGNMENT_TYPES =
205
- VARIABLE_ASSIGNMENT_TYPES + [:and_asgn, :or_asgn, :op_asgn].freeze
206
- IF = 'if'.freeze
207
- UNLESS = 'unless'.freeze
209
+ ASSIGNMENT_TYPES = VARIABLE_ASSIGNMENT_TYPES +
210
+ [:and_asgn, :or_asgn, :op_asgn, :masgn].freeze
208
211
  LINE_LENGTH = 'Metrics/LineLength'.freeze
209
212
  INDENTATION_WIDTH = 'Style/IndentationWidth'.freeze
210
213
  ENABLED = 'Enabled'.freeze
@@ -218,6 +221,7 @@ module RuboCop
218
221
  define_method "on_#{type}" do |node|
219
222
  return if part_of_ignored_node?(node)
220
223
  return unless style == :assign_inside_condition
224
+ return unless assignment_rhs_exist?(node)
221
225
 
222
226
  check_assignment_to_condition(node)
223
227
  end
@@ -226,53 +230,56 @@ module RuboCop
226
230
  def on_send(node)
227
231
  return unless assignment_type?(node)
228
232
  return unless style == :assign_inside_condition
233
+ return unless assignment_rhs_exist?(node)
229
234
 
230
235
  check_assignment_to_condition(node)
231
236
  end
232
237
 
233
- def check_assignment_to_condition(node)
234
- ignore_node(node)
235
-
236
- assignment = assignment_node(node)
237
- return unless condition?(assignment)
238
-
239
- _condition, *branches, else_branch = *assignment
240
- return unless else_branch # empty else
241
- return if single_line_conditions_only? &&
242
- [*branches, else_branch].any?(&:begin_type?)
243
-
244
- add_offense(node, :expression, ASSIGN_TO_CONDITION_MSG)
245
- end
246
-
247
238
  def on_if(node)
248
239
  return unless style == :assign_to_condition
249
- return if elsif?(node)
250
-
251
- if ternary?(node) || node.loc.keyword.is?('if')
252
- _condition, if_branch, else_branch = *node
253
- else
254
- _condition, else_branch, if_branch = *node
255
- end
240
+ return if node.elsif?
256
241
 
242
+ else_branch = node.else_branch
257
243
  elsif_branches, else_branch = expand_elses(else_branch)
258
- return unless else_branch # empty else
259
244
 
260
- branches = [if_branch, *elsif_branches, else_branch]
245
+ return unless else_branch
246
+
247
+ branches = [node.if_branch, *elsif_branches, else_branch]
261
248
 
262
249
  check_node(node, branches)
263
250
  end
264
251
 
265
252
  def on_case(node)
266
253
  return unless style == :assign_to_condition
267
- _condition, *when_branches, else_branch = *node
268
- return unless else_branch # empty else
254
+ return unless node.else_branch
269
255
 
270
- when_branches = expand_when_branches(when_branches)
271
- branches = [*when_branches, else_branch]
256
+ when_branches = expand_when_branches(node.when_branches)
257
+ branches = [*when_branches, node.else_branch]
272
258
 
273
259
  check_node(node, branches)
274
260
  end
275
261
 
262
+ private
263
+
264
+ def check_assignment_to_condition(node)
265
+ ignore_node(node)
266
+
267
+ assignment = assignment_node(node)
268
+ return unless condition?(assignment)
269
+ return if allowed_ternary?(assignment)
270
+
271
+ _condition, *branches, else_branch = *assignment
272
+ return unless else_branch # empty else
273
+ return if single_line_conditions_only? &&
274
+ [*branches, else_branch].any?(&:begin_type?)
275
+
276
+ add_offense(node, :expression, ASSIGN_TO_CONDITION_MSG)
277
+ end
278
+
279
+ def allowed_ternary?(assignment)
280
+ assignment.if_type? && assignment.ternary? && !include_ternary?
281
+ end
282
+
276
283
  def autocorrect(node)
277
284
  if assignment_type?(node)
278
285
  move_assignment_inside_condition(node)
@@ -281,8 +288,6 @@ module RuboCop
281
288
  end
282
289
  end
283
290
 
284
- private
285
-
286
291
  def assignment_node(node)
287
292
  *_variable, assignment = *node
288
293
 
@@ -298,20 +303,21 @@ module RuboCop
298
303
  end
299
304
 
300
305
  def move_assignment_outside_condition(node)
301
- if ternary?(node)
306
+ if node.case_type?
307
+ CaseCorrector.correct(self, node)
308
+ elsif node.ternary?
302
309
  TernaryCorrector.correct(node)
303
- elsif node.loc.keyword.is?(IF)
310
+ elsif node.if?
304
311
  IfCorrector.correct(self, node)
305
- elsif node.loc.keyword.is?(UNLESS)
312
+ elsif node.unless?
306
313
  UnlessCorrector.correct(self, node)
307
- else
308
- CaseCorrector.correct(self, node)
309
314
  end
310
315
  end
311
316
 
312
317
  def move_assignment_inside_condition(node)
313
318
  *_assignment, condition = *node
314
- if ternary?(condition) || ternary?(condition.children[0])
319
+
320
+ if ternary_condition?(condition)
315
321
  TernaryCorrector.move_assignment_inside_condition(node)
316
322
  elsif condition.case_type?
317
323
  CaseCorrector.move_assignment_inside_condition(node)
@@ -320,6 +326,10 @@ module RuboCop
320
326
  end
321
327
  end
322
328
 
329
+ def ternary_condition?(node)
330
+ [node, node.children.first].any? { |n| n.if_type? && n.ternary? }
331
+ end
332
+
323
333
  def lhs_all_match?(branches)
324
334
  first_lhs = lhs(branches.first)
325
335
  branches.all? { |branch| lhs(branch) == first_lhs }
@@ -327,8 +337,8 @@ module RuboCop
327
337
 
328
338
  def assignment_types_match?(*nodes)
329
339
  return unless assignment_type?(nodes.first)
330
- first_type = nodes.first.type
331
- nodes.all? { |node| node.type == first_type }
340
+
341
+ nodes.map(&:type).uniq.one?
332
342
  end
333
343
 
334
344
  # The shovel operator `<<` does not have its own type. It is a `send`
@@ -337,15 +347,15 @@ module RuboCop
337
347
  return true if ASSIGNMENT_TYPES.include?(branch.type)
338
348
 
339
349
  if branch.send_type?
340
- _receiver, method, = *branch
341
- return true if METHODS.include?(method)
342
- return true if method.to_s.end_with?(EQUAL)
350
+ return true if METHODS.include?(branch.method_name) ||
351
+ branch.method_name.to_s.end_with?(EQUAL)
343
352
  end
344
353
 
345
354
  false
346
355
  end
347
356
 
348
357
  def check_node(node, branches)
358
+ return if allowed_ternary?(node)
349
359
  return unless allowed_statements?(branches)
350
360
  return if single_line_conditions_only? && branches.any?(&:begin_type?)
351
361
  return if correction_exceeds_line_limit?(node, branches)
@@ -400,7 +410,10 @@ module RuboCop
400
410
  end
401
411
 
402
412
  def longest_rhs(branches)
403
- branches.map { |branch| branch.children.last.source.length }.max
413
+ line_lengths = branches.flat_map do |branch|
414
+ branch.children.last.source.split("\n").map(&:length)
415
+ end
416
+ line_lengths.max
404
417
  end
405
418
 
406
419
  def line_length_cop_enabled?
@@ -418,6 +431,10 @@ module RuboCop
418
431
  def single_line_conditions_only?
419
432
  cop_config[SINGLE_LINE_CONDITIONS_ONLY]
420
433
  end
434
+
435
+ def include_ternary?
436
+ cop_config['IncludeTernaryExpressions']
437
+ end
421
438
  end
422
439
 
423
440
  # Helper module to provide common methods to ConditionalAssignment
@@ -40,11 +40,14 @@ module RuboCop
40
40
 
41
41
  def autocorrect(node)
42
42
  lambda do |corrector|
43
- method, args, _body = *node
43
+ method, args, body = *node
44
44
  corrector.replace(method.loc.selector, 'each_with_object')
45
45
  first_arg, second_arg = *args
46
46
  corrector.replace(first_arg.loc.expression, second_arg.source)
47
47
  corrector.replace(second_arg.loc.expression, first_arg.source)
48
+
49
+ return_value = return_value(body)
50
+ corrector.remove(return_value.loc.expression)
48
51
  end
49
52
  end
50
53
 
@@ -11,34 +11,31 @@ module RuboCop
11
11
  include EndKeywordAlignment
12
12
  include AutocorrectAlignment
13
13
  include CheckAssignment
14
- include IfNode
15
14
 
16
15
  MSG = 'Align `%s` with `%s`.'.freeze
17
16
 
18
17
  def on_if(node, base = nil)
19
18
  return if ignored_node?(node)
20
- return unless if_else?(node)
19
+ return unless node.else? && begins_its_line?(node.loc.else)
21
20
 
22
- else_range = node.loc.else
23
- return unless begins_its_line?(else_range)
24
-
25
- check_alignment(base_range(node, base), else_range)
21
+ check_alignment(base_range(node, base), node.loc.else)
26
22
 
27
- _, _, else_body = *node
23
+ else_branch = node.else_branch
28
24
 
29
- return unless else_body && elsif?(else_body)
25
+ return unless else_branch && else_branch.if_type? &&
26
+ else_branch.elsif?
30
27
 
31
28
  # If the `else` part is actually an `elsif`, we check the `elsif`
32
29
  # node in case it contains an `else` within, because that `else`
33
30
  # should have the same alignment (base).
34
- on_if(else_body, base)
31
+ on_if(else_branch, base)
35
32
  # The `elsif` node will get an `on_if` call from the framework later,
36
33
  # but we're done here, so we set it to ignored.
37
- ignore_node(else_body)
34
+ ignore_node(else_branch)
38
35
  end
39
36
 
40
37
  def on_rescue(node)
41
- return unless if_else?(node)
38
+ return unless node.loc.respond_to?(:else) && node.loc.else
42
39
 
43
40
  parent = node.parent
44
41
  parent = parent.parent if parent.ensure_type?
@@ -51,9 +48,9 @@ module RuboCop
51
48
  end
52
49
 
53
50
  def on_case(node)
54
- _cond, *whens, _else = *node
55
- return unless if_else?(node)
56
- check_alignment(whens.last.loc.keyword, node.loc.else)
51
+ return unless node.else?
52
+
53
+ check_alignment(node.when_branches.last.loc.keyword, node.loc.else)
57
54
  end
58
55
 
59
56
  private
@@ -62,11 +59,8 @@ module RuboCop
62
59
  if base
63
60
  base.source_range
64
61
  else
65
- base = node
66
- until %w(if unless).include?(base.loc.keyword.source)
67
- base = base.parent
68
- end
69
- base.loc.keyword
62
+ lineage = [node, *node.each_ancestor(:if)]
63
+ lineage.find { |parent| parent.if? || parent.unless? }.loc.keyword
70
64
  end
71
65
  end
72
66
 
@@ -87,7 +81,7 @@ module RuboCop
87
81
  return unless rhs
88
82
 
89
83
  end_config = config.for_cop('Lint/EndAlignment')
90
- style = end_config['AlignWith'] || 'keyword'
84
+ style = end_config['EnforcedStyleAlignWith'] || 'keyword'
91
85
  base = variable_alignment?(node.loc, rhs, style.to_sym) ? node : rhs
92
86
 
93
87
  return unless rhs.if_type?