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
@@ -36,7 +36,6 @@ module RuboCop
36
36
  # raise 'exception' if something
37
37
  # ok
38
38
  class GuardClause < Cop
39
- include IfNode
40
39
  include MinBodyLength
41
40
  include OnMethodDef
42
41
 
@@ -48,7 +47,7 @@ module RuboCop
48
47
 
49
48
  if body.if_type?
50
49
  check_ending_if(body)
51
- elsif body.begin_type?
50
+ elsif body.begin_type? && body.children.last.if_type?
52
51
  check_ending_if(body.children.last)
53
52
  end
54
53
  end
@@ -56,39 +55,34 @@ module RuboCop
56
55
  def on_if(node)
57
56
  return if accepted_form?(node) || !contains_guard_clause?(node)
58
57
 
59
- add_offense(node, :keyword, MSG)
58
+ add_offense(node, :keyword)
60
59
  end
61
60
 
62
61
  private
63
62
 
64
63
  def check_ending_if(node)
65
- return if !node.if_type? ||
66
- accepted_form?(node, true) ||
67
- !min_body_length?(node)
64
+ return if accepted_form?(node, true) || !min_body_length?(node)
68
65
 
69
- add_offense(node, :keyword, MSG)
66
+ add_offense(node, :keyword)
70
67
  end
71
68
 
72
69
  def accepted_form?(node, ending = false)
73
- condition, = *node
74
-
75
- ignored_node?(node, ending) || condition.multiline?
70
+ accepted_if?(node, ending) || node.condition.multiline?
76
71
  end
77
72
 
78
- def ignored_node?(node, ending)
79
- return true if modifier_if?(node) || ternary?(node)
73
+ def accepted_if?(node, ending)
74
+ return true if node.modifier_form? || node.ternary?
80
75
 
81
76
  if ending
82
- if_else?(node)
77
+ node.else?
83
78
  else
84
- !if_else?(node) || elsif?(node)
79
+ !node.else? || node.elsif?
85
80
  end
86
81
  end
87
82
 
88
83
  def contains_guard_clause?(node)
89
- _, body, else_body = *node
90
-
91
- guard_clause?(body) || guard_clause?(else_body)
84
+ node.if_branch && node.if_branch.guard_clause? ||
85
+ node.else_branch && node.else_branch.guard_clause?
92
86
  end
93
87
  end
94
88
  end
@@ -69,43 +69,31 @@ module RuboCop
69
69
  MSG_NO_MIXED_KEYS = "Don't mix styles in the same hash.".freeze
70
70
  MSG_HASH_ROCKETS = 'Use hash rockets syntax.'.freeze
71
71
 
72
- def initialize(*)
73
- @force_hash_rockets = false
74
- super
75
- end
76
-
77
72
  def on_hash(node)
78
- if cop_config['UseHashRocketsWithSymbolValues']
79
- pairs = *node
80
- @force_hash_rockets = pairs.any? { |p| symbol_value?(p) }
81
- end
73
+ return if node.pairs.empty?
74
+
75
+ @force_hash_rockets = force_hash_rockets?(node.pairs)
82
76
 
83
77
  if style == :hash_rockets || @force_hash_rockets
84
- hash_rockets_check(node)
78
+ hash_rockets_check(node.pairs)
85
79
  elsif style == :ruby19_no_mixed_keys
86
- ruby19_no_mixed_keys_check(node)
80
+ ruby19_no_mixed_keys_check(node.pairs)
87
81
  elsif style == :no_mixed_keys
88
- no_mixed_keys_check(node)
82
+ no_mixed_keys_check(node.pairs)
89
83
  else
90
- ruby19_check(node)
84
+ ruby19_check(node.pairs)
91
85
  end
92
86
  end
93
87
 
94
- def ruby19_check(node)
95
- pairs = *node
96
-
88
+ def ruby19_check(pairs)
97
89
  check(pairs, '=>', MSG_19) if sym_indices?(pairs)
98
90
  end
99
91
 
100
- def hash_rockets_check(node)
101
- pairs = *node
102
-
92
+ def hash_rockets_check(pairs)
103
93
  check(pairs, ':', MSG_HASH_ROCKETS)
104
94
  end
105
95
 
106
- def ruby19_no_mixed_keys_check(node)
107
- pairs = *node
108
-
96
+ def ruby19_no_mixed_keys_check(pairs)
109
97
  if @force_hash_rockets
110
98
  check(pairs, ':', MSG_HASH_ROCKETS)
111
99
  elsif sym_indices?(pairs)
@@ -115,14 +103,11 @@ module RuboCop
115
103
  end
116
104
  end
117
105
 
118
- def no_mixed_keys_check(node)
119
- pairs = *node
120
-
106
+ def no_mixed_keys_check(pairs)
121
107
  if !sym_indices?(pairs)
122
108
  check(pairs, ':', MSG_NO_MIXED_KEYS)
123
109
  else
124
- delim = pairs.first.loc.operator.source == ':' ? '=>' : ':'
125
- check(pairs, delim, MSG_NO_MIXED_KEYS)
110
+ check(pairs, pairs.first.inverse_delimiter, MSG_NO_MIXED_KEYS)
126
111
  end
127
112
  end
128
113
 
@@ -149,22 +134,14 @@ module RuboCop
149
134
 
150
135
  private
151
136
 
152
- def symbol_value?(pair)
153
- _key, value = *pair
154
-
155
- value.sym_type?
156
- end
157
-
158
137
  def sym_indices?(pairs)
159
138
  pairs.all? { |p| word_symbol_pair?(p) }
160
139
  end
161
140
 
162
141
  def word_symbol_pair?(pair)
163
- key, _value = *pair
142
+ return false unless pair.key.sym_type?
164
143
 
165
- return false unless key.sym_type?
166
-
167
- acceptable_19_syntax_symbol?(key.source)
144
+ acceptable_19_syntax_symbol?(pair.key.source)
168
145
  end
169
146
 
170
147
  def acceptable_19_syntax_symbol?(sym_name)
@@ -186,7 +163,7 @@ module RuboCop
186
163
 
187
164
  def check(pairs, delim, msg)
188
165
  pairs.each do |pair|
189
- if pair.loc.operator && pair.loc.operator.is?(delim)
166
+ if pair.delimiter == delim
190
167
  add_offense(pair,
191
168
  pair.source_range.begin.join(pair.loc.operator),
192
169
  msg) do
@@ -212,20 +189,25 @@ module RuboCop
212
189
  key = node.children.first.source_range
213
190
  op = node.loc.operator
214
191
 
215
- corrector.insert_after(key, ' => ')
192
+ corrector.insert_after(key, node.inverse_delimiter(true))
216
193
  corrector.insert_before(key, ':')
217
194
  corrector.remove(range_with_surrounding_space(op))
218
195
  end
219
196
 
220
197
  def autocorrect_no_mixed_keys(corrector, node)
221
- op = node.loc.operator
222
-
223
- if op.is?(':')
198
+ if node.colon?
224
199
  autocorrect_hash_rockets(corrector, node)
225
200
  else
226
201
  autocorrect_ruby19(corrector, node)
227
202
  end
228
203
  end
204
+
205
+ def force_hash_rockets?(pairs)
206
+ @force_hash_rockets ||= begin
207
+ cop_config['UseHashRocketsWithSymbolValues'] &&
208
+ pairs.map(&:value).any?(&:sym_type?)
209
+ end
210
+ end
229
211
  end
230
212
  end
231
213
  end
@@ -3,8 +3,8 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Style
6
- # This cop checks for identical lines at the end of each branch of a
7
- # conditional statement.
6
+ # This cop checks for identical lines at the beginning or end of
7
+ # each branch of a conditional statement.
8
8
  #
9
9
  # @example
10
10
  # @bad
@@ -23,40 +23,58 @@ module RuboCop
23
23
  # do_y
24
24
  # end
25
25
  # do_z
26
+ #
27
+ # @bad
28
+ # if condition
29
+ # do_z
30
+ # do_x
31
+ # else
32
+ # do_z
33
+ # do_y
34
+ # end
35
+ #
36
+ # @good
37
+ # do_z
38
+ # if condition
39
+ # do_x
40
+ # else
41
+ # do_y
42
+ # end
26
43
  class IdenticalConditionalBranches < Cop
27
- include IfNode
28
-
29
44
  MSG = 'Move `%s` out of the conditional.'.freeze
30
45
 
31
46
  def on_if(node)
32
- return if elsif?(node)
33
- _condition, if_branch, else_branch = *node
34
- branches = expand_elses(else_branch).unshift(if_branch)
47
+ return if node.elsif?
48
+
49
+ branches = expand_elses(node.else_branch).unshift(node.if_branch)
35
50
 
36
51
  # return if any branch is empty. An empty branch can be an `if`
37
52
  # without an `else`, or a branch that contains only comments.
38
53
  return if branches.any?(&:nil?)
39
54
 
40
- check_node(branches)
55
+ check_branches(branches)
41
56
  end
42
57
 
43
58
  def on_case(node)
44
- return unless node.loc.else
45
- _condition, *when_branches, else_branch = *node
46
- return unless else_branch # empty else
47
- when_branches = expand_when_branches(when_branches)
59
+ return unless node.else? && node.else_branch
48
60
 
49
- check_node(when_branches.push(else_branch))
61
+ check_branches(node.when_branches.map(&:body).push(node.else_branch))
50
62
  end
51
63
 
52
64
  private
53
65
 
54
- def check_node(branches)
55
- branches = branches.map { |branch| tail(branch) }
66
+ def check_branches(branches)
67
+ tails = branches.compact.map { |branch| tail(branch) }
68
+ check_expressions(tails)
69
+ heads = branches.compact.map { |branch| head(branch) }
70
+ check_expressions(heads)
71
+ end
72
+
73
+ def check_expressions(expressions)
74
+ return unless expressions.size > 1 && expressions.uniq.one?
56
75
 
57
- return unless branches.all? { |branch| branch == branches[0] }
58
- branches.each do |branch|
59
- add_offense(branch, :expression, format(MSG, branch.source))
76
+ expressions.each do |expression|
77
+ add_offense(expression, :expression, format(MSG, expression.source))
60
78
  end
61
79
  end
62
80
 
@@ -73,18 +91,12 @@ module RuboCop
73
91
  end
74
92
  end
75
93
 
76
- # `when` nodes contain the entire branch including the condition.
77
- # We only need the contents of the branch, not the condition.
78
- def expand_when_branches(when_branches)
79
- when_branches.map { |branch| branch.children[1] }
94
+ def tail(node)
95
+ node.begin_type? ? node.children.last : node
80
96
  end
81
97
 
82
- def tail(node)
83
- if node && node.begin_type?
84
- node.children.last
85
- else
86
- node
87
- end
98
+ def head(node)
99
+ node.begin_type? ? node.children.first : node
88
100
  end
89
101
  end
90
102
  end
@@ -28,19 +28,16 @@ module RuboCop
28
28
  # end
29
29
  # end
30
30
  class IfInsideElse < Cop
31
- include IfNode
32
-
33
31
  MSG = 'Convert `if` nested inside `else` to `elsif`.'.freeze
34
32
 
35
33
  def on_if(node)
36
- _cond, _if_branch, else_branch = *node
37
- return unless else_branch
38
- return unless else_branch.if_type?
39
- return if ternary?(node) || ternary?(else_branch)
40
- return unless else_branch.loc.keyword.is?('if')
41
- return if node.loc.keyword.is?('unless')
34
+ return if node.ternary? || node.unless?
35
+
36
+ else_branch = node.else_branch
37
+
38
+ return unless else_branch && else_branch.if_type? && else_branch.if?
42
39
 
43
- add_offense(else_branch, :keyword, MSG)
40
+ add_offense(else_branch, :keyword)
44
41
  end
45
42
  end
46
43
  end
@@ -7,37 +7,36 @@ module RuboCop
7
7
  # if written as a modifier if/unless.
8
8
  # The maximum line length is configurable.
9
9
  class IfUnlessModifier < Cop
10
- include IfNode
11
10
  include StatementModifier
12
11
 
12
+ MSG = 'Favor modifier `%s` usage when having a single-line body. ' \
13
+ 'Another good alternative is the usage of control flow ' \
14
+ '`&&`/`||`.'.freeze
15
+
13
16
  ASSIGNMENT_TYPES = [:lvasgn, :casgn, :cvasgn,
14
17
  :gvasgn, :ivasgn, :masgn].freeze
15
18
 
16
19
  def on_if(node)
17
20
  return unless eligible_node?(node)
18
21
 
19
- add_offense(node, :keyword, message(node.loc.keyword.source))
22
+ add_offense(node, :keyword, format(MSG, node.keyword))
20
23
  end
21
24
 
22
25
  private
23
26
 
24
27
  def autocorrect(node)
25
- ->(corrector) { corrector.replace(node.source_range, oneline(node)) }
28
+ lambda do |corrector|
29
+ corrector.replace(node.source_range, to_modifier_form(node))
30
+ end
26
31
  end
27
32
 
28
33
  def eligible_node?(node)
29
34
  !non_eligible_if?(node) && !node.chained? &&
30
- !nested_conditional?(node) && single_line_as_modifier?(node)
35
+ !node.nested_conditional? && single_line_as_modifier?(node)
31
36
  end
32
37
 
33
38
  def non_eligible_if?(node)
34
- ternary?(node) || modifier_if?(node) ||
35
- elsif?(node) || if_else?(node)
36
- end
37
-
38
- def message(keyword)
39
- "Favor modifier `#{keyword}` usage when having a single-line body." \
40
- ' Another good alternative is the usage of control flow `&&`/`||`.'
39
+ node.ternary? || node.modifier_form? || node.elsif? || node.else?
41
40
  end
42
41
 
43
42
  def parenthesize?(node)
@@ -60,21 +59,13 @@ module RuboCop
60
59
  source =~ /\s*\(\s*$/
61
60
  end
62
61
 
63
- # returns false if the then or else children are conditionals
64
- def nested_conditional?(node)
65
- node.children[1, 2].compact.any?(&:if_type?)
66
- end
67
-
68
- def oneline(node)
69
- cond, body, _else = if_node_parts(node)
70
-
71
- expr = "#{body.source} #{node.loc.keyword.source} " + cond.source
72
- if (comment_after = first_line_comment(node))
73
- expr << ' ' << comment_after
74
- end
75
- expr = "(#{expr})" if parenthesize?(node)
62
+ def to_modifier_form(node)
63
+ expression = [node.body.source,
64
+ node.keyword,
65
+ node.condition.source,
66
+ first_line_comment(node)].compact.join(' ')
76
67
 
77
- expr
68
+ parenthesize?(node) ? "(#{expression})" : expression
78
69
  end
79
70
 
80
71
  def first_line_comment(node)
@@ -25,18 +25,12 @@ module RuboCop
25
25
  class IfUnlessModifierOfIfUnless < Cop
26
26
  include StatementModifier
27
27
 
28
- MESSAGE = 'Avoid modifier `%s` after another conditional.'.freeze
29
-
30
- def message(keyword)
31
- format(MESSAGE, keyword)
32
- end
28
+ MSG = 'Avoid modifier `%s` after another conditional.'.freeze
33
29
 
34
30
  def on_if(node)
35
- return unless modifier_if?(node)
36
- _cond, body, _else = if_node_parts(node)
37
- return unless body.if_type?
31
+ return unless node.modifier_form? && node.body.if_type?
38
32
 
39
- add_offense(node, :keyword, message(node.loc.keyword.source))
33
+ add_offense(node, :keyword, format(MSG, node.keyword))
40
34
  end
41
35
  end
42
36
  end
@@ -63,7 +63,7 @@ module RuboCop
63
63
  return if ignored_node?(array_node)
64
64
 
65
65
  left_bracket = array_node.loc.begin
66
- first_elem = array_node.children.first
66
+ first_elem = array_node.values.first
67
67
  if first_elem
68
68
  return if first_elem.source_range.line == left_bracket.line
69
69
  check_first(first_elem, left_bracket, left_parenthesis, 0)
@@ -12,12 +12,11 @@ module RuboCop
12
12
  # puts 'hello'
13
13
  # end
14
14
  # end
15
- class IndentationWidth < Cop # rubocop:disable Metrics/ClassLength
15
+ class IndentationWidth < Cop
16
16
  include EndKeywordAlignment
17
17
  include AutocorrectAlignment
18
18
  include OnMethodDef
19
19
  include CheckAssignment
20
- include IfNode
21
20
  include AccessModifierNode
22
21
 
23
22
  SPECIAL_MODIFIERS = %w(private protected).freeze
@@ -67,18 +66,6 @@ module RuboCop
67
66
  check_members(node.loc.keyword, members)
68
67
  end
69
68
 
70
- def check_members(base, members)
71
- check_indentation(base, members.first)
72
-
73
- return unless members.any? && members.first.begin_type?
74
- return unless indentation_consistency_style == 'rails'
75
-
76
- each_member(members) do |member, previous_modifier|
77
- check_indentation(previous_modifier, member,
78
- indentation_consistency_style)
79
- end
80
- end
81
-
82
69
  def on_send(node)
83
70
  super
84
71
  return unless modifier_and_def_on_same_line?(node)
@@ -87,7 +74,7 @@ module RuboCop
87
74
  *_, body = *args.first
88
75
 
89
76
  def_end_config = config.for_cop('Lint/DefEndAlignment')
90
- style = def_end_config['AlignWith'] || 'start_of_line'
77
+ style = def_end_config['EnforcedStyleAlignWith'] || 'start_of_line'
91
78
  base = style == 'def' ? args.first : node
92
79
 
93
80
  check_indentation(base.source_range, body)
@@ -99,67 +86,49 @@ module RuboCop
99
86
  end
100
87
 
101
88
  def on_for(node)
102
- _variable, _collection, body = *node
103
- check_indentation(node.loc.keyword, body)
89
+ check_indentation(node.loc.keyword, node.body)
104
90
  end
105
91
 
106
92
  def on_while(node, base = node)
107
93
  return if ignored_node?(node)
108
94
 
109
- _condition, body = *node
110
- return unless node.loc.keyword.begin_pos ==
111
- node.source_range.begin_pos
95
+ return unless node.single_line_condition?
112
96
 
113
- check_indentation(base.loc, body)
97
+ check_indentation(base.loc, node.body)
114
98
  end
115
99
 
116
100
  alias on_until on_while
117
101
 
118
- def on_case(node)
119
- _condition, *branches = *node
120
- latest_when = nil
121
- branches.compact.each do |b|
122
- if b.when_type?
123
- # TODO: Revert to the original expression once the fix in Rubinius
124
- # is released.
125
- #
126
- # Originally this expression was:
127
- #
128
- # *_conditions, body = *b
129
- #
130
- # However it fails on Rubinius 2.2.9 due to its bug:
131
- #
132
- # RuntimeError:
133
- # can't modify frozen instance of Array
134
- # # kernel/common/array.rb:988:in `pop'
135
- # # ./lib/rubocop/cop/style/indentation_width.rb:99:in `on_case'
136
- #
137
- # It seems to be fixed on the current master (0a92c3c).
138
- body = b.children.last
139
-
140
- # Check "when" body against "when" keyword indentation.
141
- check_indentation(b.loc.keyword, body)
142
- latest_when = b
143
- else
144
- # Since it's not easy to get the position of the "else" keyword,
145
- # we check "else" body against latest "when" keyword indentation.
146
- check_indentation(latest_when.loc.keyword, b)
147
- end
102
+ def on_case(case_node)
103
+ case_node.each_when do |when_node|
104
+ check_indentation(when_node.loc.keyword, when_node.body)
148
105
  end
106
+
107
+ check_indentation(case_node.when_branches.last.loc.keyword,
108
+ case_node.else_branch)
149
109
  end
150
110
 
151
111
  def on_if(node, base = node)
152
- return if ignored_node?(node)
153
- return if ternary?(node)
154
- return if modifier_if?(node)
155
-
156
- _condition, body, else_clause = if_node_parts(node)
112
+ return if ignored_node?(node) || !node.body
113
+ return if node.ternary? || node.modifier_form?
157
114
 
158
- check_if(node, body, else_clause, base.loc) if body
115
+ check_if(node, node.body, node.else_branch, base.loc)
159
116
  end
160
117
 
161
118
  private
162
119
 
120
+ def check_members(base, members)
121
+ check_indentation(base, members.first)
122
+
123
+ return unless members.any? && members.first.begin_type?
124
+ return unless indentation_consistency_style == 'rails'
125
+
126
+ each_member(members) do |member, previous_modifier|
127
+ check_indentation(previous_modifier, member,
128
+ indentation_consistency_style)
129
+ end
130
+ end
131
+
163
132
  def each_member(members)
164
133
  previous_modifier = nil
165
134
  members.first.children.each do |member|
@@ -188,7 +157,7 @@ module RuboCop
188
157
  return unless rhs
189
158
 
190
159
  end_config = config.for_cop('Lint/EndAlignment')
191
- style = end_config['AlignWith'] || 'keyword'
160
+ style = end_config['EnforcedStyleAlignWith'] || 'keyword'
192
161
  base = variable_alignment?(node.loc, rhs, style.to_sym) ? node : rhs
193
162
 
194
163
  case rhs.type
@@ -201,14 +170,14 @@ module RuboCop
201
170
  end
202
171
 
203
172
  def check_if(node, body, else_clause, base_loc)
204
- return if ternary?(node)
173
+ return if node.ternary?
205
174
 
206
175
  check_indentation(base_loc, body)
207
176
  return unless else_clause
208
177
 
209
178
  # If the else clause is an elsif, it will get its own on_if call so
210
179
  # we don't need to process it here.
211
- return if elsif?(else_clause)
180
+ return if else_clause.if_type? && else_clause.elsif?
212
181
 
213
182
  check_indentation(node.loc.else, else_clause)
214
183
  end