rubocop 0.42.0 → 0.43.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 (221) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/assets/output.html.erb +21 -10
  4. data/config/default.yml +32 -2
  5. data/config/disabled.yml +8 -1
  6. data/config/enabled.yml +40 -12
  7. data/lib/rubocop.rb +14 -2
  8. data/lib/rubocop/ast_node.rb +2 -0
  9. data/lib/rubocop/cached_data.rb +13 -11
  10. data/lib/rubocop/cli.rb +5 -5
  11. data/lib/rubocop/config.rb +68 -24
  12. data/lib/rubocop/config_loader.rb +13 -11
  13. data/lib/rubocop/config_loader_resolver.rb +4 -2
  14. data/lib/rubocop/cop/cop.rb +16 -5
  15. data/lib/rubocop/cop/lint/assignment_in_condition.rb +21 -20
  16. data/lib/rubocop/cop/lint/block_alignment.rb +3 -4
  17. data/lib/rubocop/cop/lint/def_end_alignment.rb +2 -3
  18. data/lib/rubocop/cop/lint/duplicate_methods.rb +16 -6
  19. data/lib/rubocop/cop/lint/else_layout.rb +1 -1
  20. data/lib/rubocop/cop/lint/empty_interpolation.rb +1 -1
  21. data/lib/rubocop/cop/lint/end_alignment.rb +4 -6
  22. data/lib/rubocop/cop/lint/eval.rb +1 -1
  23. data/lib/rubocop/cop/lint/format_parameter_mismatch.rb +1 -1
  24. data/lib/rubocop/cop/lint/ineffective_access_modifier.rb +8 -8
  25. data/lib/rubocop/cop/lint/inherit_exception.rb +22 -7
  26. data/lib/rubocop/cop/lint/literal_in_condition.rb +5 -5
  27. data/lib/rubocop/cop/lint/literal_in_interpolation.rb +3 -5
  28. data/lib/rubocop/cop/lint/next_without_accumulator.rb +1 -1
  29. data/lib/rubocop/cop/lint/parentheses_as_grouped_expression.rb +9 -8
  30. data/lib/rubocop/cop/lint/percent_string_array.rb +17 -6
  31. data/lib/rubocop/cop/lint/percent_symbol_array.rb +4 -4
  32. data/lib/rubocop/cop/lint/rand_one.rb +3 -3
  33. data/lib/rubocop/cop/lint/require_parentheses.rb +1 -3
  34. data/lib/rubocop/cop/lint/shadowed_exception.rb +39 -44
  35. data/lib/rubocop/cop/lint/string_conversion_in_interpolation.rb +2 -2
  36. data/lib/rubocop/cop/lint/underscore_prefixed_variable_name.rb +1 -2
  37. data/lib/rubocop/cop/lint/unified_integer.rb +38 -0
  38. data/lib/rubocop/cop/lint/unneeded_disable.rb +51 -38
  39. data/lib/rubocop/cop/lint/unneeded_splat_expansion.rb +114 -0
  40. data/lib/rubocop/cop/lint/useless_assignment.rb +25 -12
  41. data/lib/rubocop/cop/lint/useless_setter_call.rb +27 -28
  42. data/lib/rubocop/cop/lint/void.rb +2 -4
  43. data/lib/rubocop/cop/mixin/access_modifier_node.rb +5 -5
  44. data/lib/rubocop/cop/mixin/array_hash_indentation.rb +19 -17
  45. data/lib/rubocop/cop/mixin/autocorrect_alignment.rb +3 -5
  46. data/lib/rubocop/cop/mixin/configurable_naming.rb +4 -5
  47. data/lib/rubocop/cop/mixin/configurable_numbering.rb +52 -0
  48. data/lib/rubocop/cop/mixin/def_node.rb +28 -0
  49. data/lib/rubocop/cop/mixin/documentation_comment.rb +41 -0
  50. data/lib/rubocop/cop/mixin/end_keyword_alignment.rb +18 -13
  51. data/lib/rubocop/cop/mixin/if_node.rb +6 -0
  52. data/lib/rubocop/cop/mixin/match_range.rb +2 -5
  53. data/lib/rubocop/cop/mixin/multiline_expression_indentation.rb +2 -2
  54. data/lib/rubocop/cop/mixin/multiline_literal_brace_layout.rb +40 -28
  55. data/lib/rubocop/cop/mixin/negative_conditional.rb +6 -6
  56. data/lib/rubocop/cop/mixin/percent_literal.rb +1 -5
  57. data/lib/rubocop/cop/mixin/preceding_following_alignment.rb +14 -4
  58. data/lib/rubocop/cop/mixin/safe_mode.rb +23 -0
  59. data/lib/rubocop/cop/mixin/space_before_punctuation.rb +2 -4
  60. data/lib/rubocop/cop/mixin/space_inside.rb +1 -3
  61. data/lib/rubocop/cop/mixin/statement_modifier.rb +30 -20
  62. data/lib/rubocop/cop/mixin/trailing_comma.rb +19 -17
  63. data/lib/rubocop/cop/performance/case_when_splat.rb +16 -41
  64. data/lib/rubocop/cop/performance/casecmp.rb +28 -16
  65. data/lib/rubocop/cop/performance/count.rb +58 -34
  66. data/lib/rubocop/cop/performance/detect.rb +3 -7
  67. data/lib/rubocop/cop/performance/double_start_end_with.rb +17 -13
  68. data/lib/rubocop/cop/performance/fixed_size.rb +19 -14
  69. data/lib/rubocop/cop/performance/flat_map.rb +16 -9
  70. data/lib/rubocop/cop/performance/hash_each.rb +2 -3
  71. data/lib/rubocop/cop/performance/lstrip_rstrip.rb +4 -6
  72. data/lib/rubocop/cop/performance/redundant_match.rb +4 -1
  73. data/lib/rubocop/cop/performance/redundant_merge.rb +63 -32
  74. data/lib/rubocop/cop/performance/redundant_sort_by.rb +8 -7
  75. data/lib/rubocop/cop/performance/reverse_each.rb +1 -4
  76. data/lib/rubocop/cop/performance/size.rb +21 -8
  77. data/lib/rubocop/cop/performance/sort_with_block.rb +54 -0
  78. data/lib/rubocop/cop/performance/string_replacement.rb +3 -7
  79. data/lib/rubocop/cop/rails/delegate.rb +2 -3
  80. data/lib/rubocop/cop/rails/find_by.rb +4 -8
  81. data/lib/rubocop/cop/rails/not_null_column.rb +45 -0
  82. data/lib/rubocop/cop/rails/request_referer.rb +3 -3
  83. data/lib/rubocop/cop/rails/safe_navigation.rb +89 -0
  84. data/lib/rubocop/cop/rails/save_bang.rb +78 -9
  85. data/lib/rubocop/cop/rails/scope_args.rb +3 -1
  86. data/lib/rubocop/cop/rails/uniq_before_pluck.rb +2 -3
  87. data/lib/rubocop/cop/rails/validation.rb +1 -1
  88. data/lib/rubocop/cop/security/json_load.rb +36 -0
  89. data/lib/rubocop/cop/style/alias.rb +1 -1
  90. data/lib/rubocop/cop/style/align_hash.rb +25 -14
  91. data/lib/rubocop/cop/style/and_or.rb +13 -3
  92. data/lib/rubocop/cop/style/array_join.rb +3 -3
  93. data/lib/rubocop/cop/style/ascii_comments.rb +1 -2
  94. data/lib/rubocop/cop/style/ascii_identifiers.rb +1 -2
  95. data/lib/rubocop/cop/style/attr.rb +1 -3
  96. data/lib/rubocop/cop/style/block_comments.rb +2 -6
  97. data/lib/rubocop/cop/style/block_delimiters.rb +35 -21
  98. data/lib/rubocop/cop/style/braces_around_hash_parameters.rb +4 -4
  99. data/lib/rubocop/cop/style/case_indentation.rb +1 -3
  100. data/lib/rubocop/cop/style/class_methods.rb +3 -4
  101. data/lib/rubocop/cop/style/collection_methods.rb +1 -1
  102. data/lib/rubocop/cop/style/command_literal.rb +15 -8
  103. data/lib/rubocop/cop/style/comment_annotation.rb +1 -2
  104. data/lib/rubocop/cop/style/conditional_assignment.rb +68 -36
  105. data/lib/rubocop/cop/style/copyright.rb +1 -5
  106. data/lib/rubocop/cop/style/def_with_parentheses.rb +3 -5
  107. data/lib/rubocop/cop/style/documentation.rb +28 -56
  108. data/lib/rubocop/cop/style/documentation_method.rb +80 -0
  109. data/lib/rubocop/cop/style/each_for_simple_loop.rb +6 -5
  110. data/lib/rubocop/cop/style/each_with_object.rb +2 -2
  111. data/lib/rubocop/cop/style/else_alignment.rb +10 -9
  112. data/lib/rubocop/cop/style/empty_case_condition.rb +2 -4
  113. data/lib/rubocop/cop/style/empty_else.rb +1 -4
  114. data/lib/rubocop/cop/style/empty_line_between_defs.rb +1 -3
  115. data/lib/rubocop/cop/style/empty_lines_around_access_modifier.rb +2 -5
  116. data/lib/rubocop/cop/style/encoding.rb +28 -14
  117. data/lib/rubocop/cop/style/even_odd.rb +28 -17
  118. data/lib/rubocop/cop/style/extra_spacing.rb +36 -25
  119. data/lib/rubocop/cop/style/file_name.rb +19 -10
  120. data/lib/rubocop/cop/style/first_parameter_indentation.rb +2 -3
  121. data/lib/rubocop/cop/style/for.rb +12 -8
  122. data/lib/rubocop/cop/style/format_string.rb +1 -1
  123. data/lib/rubocop/cop/style/guard_clause.rb +22 -56
  124. data/lib/rubocop/cop/style/hash_syntax.rb +72 -7
  125. data/lib/rubocop/cop/style/if_unless_modifier.rb +23 -19
  126. data/lib/rubocop/cop/style/if_unless_modifier_of_if_unless.rb +3 -3
  127. data/lib/rubocop/cop/style/indentation_width.rb +30 -16
  128. data/lib/rubocop/cop/style/infinite_loop.rb +16 -13
  129. data/lib/rubocop/cop/style/initial_indentation.rb +23 -18
  130. data/lib/rubocop/cop/style/inline_comment.rb +16 -3
  131. data/lib/rubocop/cop/style/lambda.rb +22 -10
  132. data/lib/rubocop/cop/style/leading_comment_space.rb +12 -1
  133. data/lib/rubocop/cop/style/line_end_concatenation.rb +24 -6
  134. data/lib/rubocop/cop/style/method_call_parentheses.rb +18 -9
  135. data/lib/rubocop/cop/style/method_called_on_do_end_block.rb +3 -4
  136. data/lib/rubocop/cop/style/method_def_parentheses.rb +3 -4
  137. data/lib/rubocop/cop/style/method_missing.rb +10 -2
  138. data/lib/rubocop/cop/style/module_function.rb +14 -6
  139. data/lib/rubocop/cop/style/multiline_assignment_layout.rb +2 -5
  140. data/lib/rubocop/cop/style/multiline_block_chain.rb +3 -5
  141. data/lib/rubocop/cop/style/multiline_block_layout.rb +22 -15
  142. data/lib/rubocop/cop/style/multiline_method_call_brace_layout.rb +9 -0
  143. data/lib/rubocop/cop/style/multiline_method_call_indentation.rb +41 -20
  144. data/lib/rubocop/cop/style/multiline_operation_indentation.rb +6 -6
  145. data/lib/rubocop/cop/style/multiline_ternary_operator.rb +3 -5
  146. data/lib/rubocop/cop/style/mutable_constant.rb +21 -13
  147. data/lib/rubocop/cop/style/negated_if.rb +1 -1
  148. data/lib/rubocop/cop/style/negated_while.rb +3 -3
  149. data/lib/rubocop/cop/style/nested_modifier.rb +2 -4
  150. data/lib/rubocop/cop/style/next.rb +4 -4
  151. data/lib/rubocop/cop/style/non_nil_check.rb +18 -10
  152. data/lib/rubocop/cop/style/numeric_literal_prefix.rb +8 -0
  153. data/lib/rubocop/cop/style/numeric_predicate.rb +9 -9
  154. data/lib/rubocop/cop/style/one_line_conditional.rb +11 -1
  155. data/lib/rubocop/cop/style/op_method.rb +1 -1
  156. data/lib/rubocop/cop/style/option_hash.rb +8 -8
  157. data/lib/rubocop/cop/style/optional_arguments.rb +21 -8
  158. data/lib/rubocop/cop/style/parallel_assignment.rb +51 -35
  159. data/lib/rubocop/cop/style/parentheses_around_condition.rb +2 -2
  160. data/lib/rubocop/cop/style/percent_literal_delimiters.rb +1 -1
  161. data/lib/rubocop/cop/style/raise_args.rb +2 -2
  162. data/lib/rubocop/cop/style/redundant_begin.rb +1 -1
  163. data/lib/rubocop/cop/style/redundant_parentheses.rb +26 -15
  164. data/lib/rubocop/cop/style/redundant_return.rb +5 -5
  165. data/lib/rubocop/cop/style/redundant_self.rb +20 -11
  166. data/lib/rubocop/cop/style/regexp_literal.rb +16 -10
  167. data/lib/rubocop/cop/style/rescue_ensure_alignment.rb +8 -6
  168. data/lib/rubocop/cop/style/safe_navigation.rb +125 -0
  169. data/lib/rubocop/cop/style/self_assignment.rb +2 -2
  170. data/lib/rubocop/cop/style/semicolon.rb +9 -10
  171. data/lib/rubocop/cop/style/signal_exception.rb +2 -4
  172. data/lib/rubocop/cop/style/single_line_block_params.rb +1 -1
  173. data/lib/rubocop/cop/style/single_line_methods.rb +18 -11
  174. data/lib/rubocop/cop/style/space_after_method_name.rb +2 -3
  175. data/lib/rubocop/cop/style/space_after_not.rb +4 -6
  176. data/lib/rubocop/cop/style/space_around_block_parameters.rb +1 -2
  177. data/lib/rubocop/cop/style/space_around_equals_in_parameter_default.rb +1 -3
  178. data/lib/rubocop/cop/style/space_around_operators.rb +21 -16
  179. data/lib/rubocop/cop/style/space_before_block_braces.rb +2 -12
  180. data/lib/rubocop/cop/style/space_before_first_arg.rb +1 -3
  181. data/lib/rubocop/cop/style/space_inside_array_percent_literal.rb +1 -1
  182. data/lib/rubocop/cop/style/space_inside_block_braces.rb +33 -40
  183. data/lib/rubocop/cop/style/space_inside_hash_literal_braces.rb +38 -23
  184. data/lib/rubocop/cop/style/space_inside_percent_literal_delimiters.rb +1 -1
  185. data/lib/rubocop/cop/style/space_inside_string_interpolation.rb +26 -12
  186. data/lib/rubocop/cop/style/stabby_lambda_parentheses.rb +2 -4
  187. data/lib/rubocop/cop/style/symbol_array.rb +10 -10
  188. data/lib/rubocop/cop/style/symbol_proc.rb +28 -13
  189. data/lib/rubocop/cop/style/ternary_parentheses.rb +35 -5
  190. data/lib/rubocop/cop/style/trailing_blank_lines.rb +2 -4
  191. data/lib/rubocop/cop/style/trailing_underscore_variable.rb +29 -17
  192. data/lib/rubocop/cop/style/trivial_accessors.rb +6 -6
  193. data/lib/rubocop/cop/style/unless_else.rb +2 -6
  194. data/lib/rubocop/cop/style/unneeded_capital_w.rb +8 -4
  195. data/lib/rubocop/cop/style/unneeded_interpolation.rb +4 -5
  196. data/lib/rubocop/cop/style/unneeded_percent_q.rb +13 -7
  197. data/lib/rubocop/cop/style/variable_number.rb +79 -0
  198. data/lib/rubocop/cop/style/while_until_modifier.rb +1 -1
  199. data/lib/rubocop/cop/style/word_array.rb +25 -15
  200. data/lib/rubocop/cop/style/zero_length_predicate.rb +2 -0
  201. data/lib/rubocop/cop/util.rb +23 -4
  202. data/lib/rubocop/cop/variable_force.rb +59 -25
  203. data/lib/rubocop/cop/variable_force/locatable.rb +8 -6
  204. data/lib/rubocop/cop/variable_force/variable.rb +2 -2
  205. data/lib/rubocop/cop/variable_force/variable_table.rb +3 -3
  206. data/lib/rubocop/formatter/disabled_config_formatter.rb +16 -11
  207. data/lib/rubocop/formatter/formatter_set.rb +12 -10
  208. data/lib/rubocop/formatter/worst_offenders_formatter.rb +4 -4
  209. data/lib/rubocop/node_pattern.rb +79 -35
  210. data/lib/rubocop/options.rb +4 -4
  211. data/lib/rubocop/processed_source.rb +9 -5
  212. data/lib/rubocop/remote_config.rb +14 -10
  213. data/lib/rubocop/result_cache.rb +14 -6
  214. data/lib/rubocop/runner.rb +55 -34
  215. data/lib/rubocop/string_util.rb +9 -5
  216. data/lib/rubocop/target_finder.rb +1 -1
  217. data/lib/rubocop/token.rb +1 -1
  218. data/lib/rubocop/version.rb +1 -1
  219. metadata +15 -4
  220. data/lib/rubocop/cop/lint/useless_array_splat.rb +0 -56
  221. data/lib/rubocop/cop/performance/push_splat.rb +0 -47
@@ -26,11 +26,7 @@ module RuboCop
26
26
  # A range containing only the contents of the percent literal (e.g. in
27
27
  # %i{1 2 3} this will be the range covering '1 2 3' only)
28
28
  def contents_range(node)
29
- Parser::Source::Range.new(
30
- node.loc.expression.source_buffer,
31
- node.loc.begin.end_pos,
32
- node.loc.end.begin_pos
33
- )
29
+ range_between(node.loc.begin.end_pos, node.loc.end.begin_pos)
34
30
  end
35
31
  end
36
32
  end
@@ -22,14 +22,24 @@ module RuboCop
22
22
  # minus 2 because node.loc.line is zero-based
23
23
  pre = (range.line - 2).downto(0)
24
24
  post = range.line.upto(processed_source.lines.size - 1)
25
- return true if aligned_with_line?(pre, range, &predicate) ||
26
- aligned_with_line?(post, range, &predicate)
25
+
26
+ aligned_with_any_line_range?([pre, post], range, &predicate)
27
+ end
28
+
29
+ def aligned_with_any_line_range?(line_ranges, range, &predicate)
30
+ return true if aligned_with_any_line?(line_ranges, range, &predicate)
27
31
 
28
32
  # If no aligned token was found, search for an aligned token on the
29
33
  # nearest line with the same indentation as the checked line.
30
34
  base_indentation = processed_source.lines[range.line - 1] =~ /\S/
31
- aligned_with_line?(pre, range, base_indentation, &predicate) ||
32
- aligned_with_line?(post, range, base_indentation, &predicate)
35
+
36
+ aligned_with_any_line?(line_ranges, range, base_indentation, &predicate)
37
+ end
38
+
39
+ def aligned_with_any_line?(line_ranges, range, indent = nil, &predicate)
40
+ line_ranges.any? do |line_nos|
41
+ aligned_with_line?(line_nos, range, indent, &predicate)
42
+ end
33
43
  end
34
44
 
35
45
  def aligned_with_line?(line_nos, range, indent = nil)
@@ -0,0 +1,23 @@
1
+ # encoding: utf-8
2
+ # frozen_string_literal: true
3
+
4
+ module RuboCop
5
+ module Cop
6
+ # Common functionality for Rails safe mode.
7
+ module SafeMode
8
+ private
9
+
10
+ def rails_safe_mode?
11
+ safe_mode? || rails?
12
+ end
13
+
14
+ def safe_mode?
15
+ cop_config['SafeMode']
16
+ end
17
+
18
+ def rails?
19
+ config['Rails'] && config['Rails']['Enabled']
20
+ end
21
+ end
22
+ end
23
+ end
@@ -20,10 +20,8 @@ module RuboCop
20
20
  next unless space_missing?(t1, t2)
21
21
  next if space_required_after?(t1)
22
22
 
23
- buffer = processed_source.buffer
24
- pos_before_punctuation = Parser::Source::Range.new(buffer,
25
- t1.pos.end_pos,
26
- t2.pos.begin_pos)
23
+ pos_before_punctuation = range_between(t1.pos.end_pos,
24
+ t2.pos.begin_pos)
27
25
 
28
26
  yield t2, pos_before_punctuation
29
27
  end
@@ -41,9 +41,7 @@ module RuboCop
41
41
  end
42
42
 
43
43
  def range_between_tokens(t1, t2)
44
- Parser::Source::Range.new(processed_source.buffer,
45
- t1.pos.end_pos,
46
- t2.pos.begin_pos)
44
+ range_between(t1.pos.end_pos, t2.pos.begin_pos)
47
45
  end
48
46
 
49
47
  # Wraps info about the brackets. Makes it easy to check whether a token
@@ -7,18 +7,32 @@ module RuboCop
7
7
  module StatementModifier
8
8
  include IfNode
9
9
 
10
- def fit_within_line_as_modifier_form?(node)
11
- cond, body, _else = if_node_parts(node)
10
+ def single_line_as_modifier?(node)
11
+ cond, body, = if_node_parts(node)
12
12
 
13
- return false if length(node) > 3
14
- return false if body && body.begin_type? # multiple statements
13
+ return false if non_eligible_node?(node) || non_eligible_body?(body) ||
14
+ non_eligible_condition?(cond)
15
15
 
16
- body_length = body_length(body)
16
+ modifier_fits_on_single_line?(node)
17
+ end
18
+
19
+ def non_eligible_node?(node)
20
+ line_count(node) > 3 || commented?(node.loc.end)
21
+ end
22
+
23
+ def non_eligible_body?(body)
24
+ return true unless body
25
+
26
+ body.begin_type? || empty_body?(body) || commented?(body.source_range)
27
+ end
28
+
29
+ def non_eligible_condition?(condition)
30
+ condition.each_node.any?(&:lvasgn_type?)
31
+ end
17
32
 
18
- return false if body_length.zero?
19
- return false if cond.each_node.any?(&:lvasgn_type?)
20
- return false if body_has_comment?(body)
21
- return false if end_keyword_has_comment?(node)
33
+ def modifier_fits_on_single_line?(node)
34
+ cond, body, = if_node_parts(node)
35
+ body_length = body_length(body)
22
36
 
23
37
  length_in_modifier_form(node, cond, body_length) <= max_line_length
24
38
  end
@@ -36,24 +50,20 @@ module RuboCop
36
50
  config.for_cop('Metrics/LineLength')['Max']
37
51
  end
38
52
 
39
- def length(node)
53
+ def line_count(node)
40
54
  node.source.lines.grep(/\S/).size
41
55
  end
42
56
 
43
- def body_length(body)
44
- if body && body.source_range
45
- body.source_range.size
46
- else
47
- 0
48
- end
57
+ def empty_body?(body)
58
+ body_length(body).zero?
49
59
  end
50
60
 
51
- def body_has_comment?(body)
52
- comment_lines.include?(body.source_range.line)
61
+ def body_length(body)
62
+ body.source_range ? body.source_range.size : 0
53
63
  end
54
64
 
55
- def end_keyword_has_comment?(node)
56
- comment_lines.include?(node.loc.end.line)
65
+ def commented?(source)
66
+ comment_lines.include?(source.line)
57
67
  end
58
68
 
59
69
  def comment_lines
@@ -15,8 +15,7 @@ module RuboCop
15
15
  end
16
16
 
17
17
  def check(node, items, kind, begin_pos, end_pos)
18
- sb = node.source_range.source_buffer
19
- after_last_item = Parser::Source::Range.new(sb, begin_pos, end_pos)
18
+ after_last_item = range_between(begin_pos, end_pos)
20
19
 
21
20
  return if heredoc?(after_last_item.source)
22
21
 
@@ -25,15 +24,14 @@ module RuboCop
25
24
  if comma_offset && !inside_comment?(after_last_item, comma_offset)
26
25
  check_comma(node, kind, after_last_item.begin_pos + comma_offset)
27
26
  elsif should_have_comma?(style, node)
28
- put_comma(node, items, kind, sb)
27
+ put_comma(node, items, kind)
29
28
  end
30
29
  end
31
30
 
32
31
  def check_comma(node, kind, comma_pos)
33
32
  return if should_have_comma?(style, node)
34
33
 
35
- avoid_comma(kind, comma_pos, node.source_range.source_buffer,
36
- extra_avoid_comma_info)
34
+ avoid_comma(kind, comma_pos, extra_avoid_comma_info)
37
35
  end
38
36
 
39
37
  def extra_avoid_comma_info
@@ -117,30 +115,34 @@ module RuboCop
117
115
  a.last_line == b.line
118
116
  end
119
117
 
120
- def avoid_comma(kind, comma_begin_pos, sb, extra_info)
121
- range = Parser::Source::Range.new(sb, comma_begin_pos,
122
- comma_begin_pos + 1)
118
+ def avoid_comma(kind, comma_begin_pos, extra_info)
119
+ range = range_between(comma_begin_pos, comma_begin_pos + 1)
123
120
  article = kind =~ /array/ ? 'an' : 'a'
124
121
  add_offense(range, range,
125
122
  format(MSG, 'Avoid', format(kind, article)) +
126
123
  "#{extra_info}.")
127
124
  end
128
125
 
129
- def put_comma(node, items, kind, sb)
126
+ def put_comma(node, items, kind)
127
+ return if avoid_autocorrect?(elements(node))
128
+
130
129
  last_item = items.last
131
- return if last_item.type == :block_pass
130
+ return if last_item.block_pass_type?
132
131
 
133
- last_expr = last_item.source_range
134
- ix = last_expr.source.rindex("\n") || 0
135
- ix += last_expr.source[ix..-1] =~ /\S/
136
- range = Parser::Source::Range.new(sb, last_expr.begin_pos + ix,
137
- last_expr.end_pos)
138
- autocorrect_range = avoid_autocorrect?(elements(node)) ? nil : range
132
+ range = autocorrect_range(last_item)
139
133
 
140
- add_offense(autocorrect_range, range,
134
+ add_offense(range, range,
141
135
  format(MSG, 'Put a', format(kind, 'a multiline') + '.'))
142
136
  end
143
137
 
138
+ def autocorrect_range(item)
139
+ expr = item.source_range
140
+ ix = expr.source.rindex("\n") || 0
141
+ ix += expr.source[ix..-1] =~ /\S/
142
+
143
+ range_between(expr.begin_pos + ix, expr.end_pos)
144
+ end
145
+
144
146
  # By default, there's no reason to avoid auto-correct.
145
147
  def avoid_autocorrect?(_)
146
148
  false
@@ -94,37 +94,20 @@ module RuboCop
94
94
  private
95
95
 
96
96
  def replacement(conditions)
97
- new_condition = conditions.map do |condition|
98
- variable, = *condition
99
- if variable.respond_to?(:array_type?) && variable.array_type?
100
- expand_percent_array(variable)
101
- else
102
- condition.source
103
- end
104
- end
105
-
97
+ new_condition = conditions.map(&:source)
106
98
  new_condition.join(', ')
107
99
  end
108
100
 
109
- def inline_fix_branch(corrector, node, conditions, new_condition)
110
- range =
111
- Parser::Source::Range.new(node.loc.expression.source_buffer,
112
- conditions[0].loc.expression.begin_pos,
113
- conditions[-1].loc.expression.end_pos)
101
+ def inline_fix_branch(corrector, _node, conditions, new_condition)
102
+ range = range_between(conditions[0].loc.expression.begin_pos,
103
+ conditions[-1].loc.expression.end_pos)
114
104
  corrector.replace(range, new_condition)
115
105
  end
116
106
 
117
107
  def reorder_condition(corrector, node, new_condition)
118
108
  *_conditions, body = *node
119
- parent = node.parent
120
- _case_branch, *when_branches, _else_branch = *parent
121
- current_index = when_branches.index { |branch| branch == node }
122
- next_branch = when_branches[current_index + 1]
123
- range = Parser::Source::Range.new(parent,
124
- node.source_range.begin_pos,
125
- next_branch.source_range.begin_pos)
126
-
127
- corrector.remove(range)
109
+ _case_branch, *when_branches, _else_branch = *node.parent
110
+ corrector.remove(when_branch_range(node, when_branches))
128
111
 
129
112
  correction = if same_line?(node, body)
130
113
  new_condition_with_then(node, new_condition)
@@ -135,6 +118,14 @@ module RuboCop
135
118
  corrector.insert_after(when_branches.last.source_range, correction)
136
119
  end
137
120
 
121
+ def when_branch_range(node, when_branches)
122
+ current_index = when_branches.index { |branch| branch == node }
123
+ next_branch = when_branches[current_index + 1]
124
+
125
+ range_between(node.source_range.begin_pos,
126
+ next_branch.source_range.begin_pos)
127
+ end
128
+
138
129
  def same_line?(node, other)
139
130
  node.loc.first_line == other.loc.first_line
140
131
  end
@@ -155,6 +146,8 @@ module RuboCop
155
146
  found_non_splat ||= error_condition?(condition)
156
147
 
157
148
  next unless condition.splat_type?
149
+ variable, = *condition
150
+ next if variable.array_type?
158
151
  result << condition if found_non_splat
159
152
  end
160
153
  end
@@ -172,24 +165,6 @@ module RuboCop
172
165
  condition.splat_type? && !(variable && variable.array_type?)
173
166
  end
174
167
  end
175
-
176
- def expand_percent_array(array)
177
- array_start = array.loc.begin.source
178
- elements = *array
179
- elements = elements.map(&:source)
180
-
181
- if array_start.start_with?(PERCENT_W)
182
- "'#{elements.join("', '")}'"
183
- elsif array_start.start_with?(PERCENT_CAPITAL_W)
184
- %("#{elements.join('", "')}")
185
- elsif array_start.start_with?(PERCENT_I)
186
- ":#{elements.join(', :')}"
187
- elsif array_start.start_with?(PERCENT_CAPITAL_I)
188
- %(:"#{elements.join('", :"')}")
189
- else
190
- elements.join(', ')
191
- end
192
- end
193
168
  end
194
169
  end
195
170
  end
@@ -39,22 +39,9 @@ module RuboCop
39
39
  def on_send(node)
40
40
  return if part_of_ignored_node?(node)
41
41
 
42
- downcase_eq(node) do |send_downcase, case_method, eq_method, other|
43
- *_, method = *other
44
- if CASE_METHODS.include?(method)
45
- range = node.loc.expression
46
- ignore_node(node)
47
- else
48
- range = node.loc.selector.join(send_downcase.loc.selector)
49
- end
50
-
51
- add_offense(node, range, format(MSG, case_method, eq_method))
52
- return
53
- end
54
-
55
- eq_downcase(node) do |eq_method, send_downcase, case_method|
56
- range = node.loc.selector.join(send_downcase.loc.selector)
57
- add_offense(node, range, format(MSG, eq_method, case_method))
42
+ inefficient_comparison(node) do |range, is_other_part, *methods|
43
+ ignore_node(node) if is_other_part
44
+ add_offense(node, range, format(MSG, *methods))
58
45
  end
59
46
  end
60
47
 
@@ -74,6 +61,31 @@ module RuboCop
74
61
 
75
62
  private
76
63
 
64
+ def inefficient_comparison(node)
65
+ loc = node.loc
66
+
67
+ downcase_eq(node) do |send_downcase, case_method, eq_method, other|
68
+ *_, method = *other
69
+ range, is_other_part = downcase_eq_range(method, loc, send_downcase)
70
+
71
+ yield range, is_other_part, case_method, eq_method
72
+ return
73
+ end
74
+
75
+ eq_downcase(node) do |eq_method, send_downcase, case_method|
76
+ range = loc.selector.join(send_downcase.loc.selector)
77
+ yield range, false, eq_method, case_method
78
+ end
79
+ end
80
+
81
+ def downcase_eq_range(method, loc, send_downcase)
82
+ if CASE_METHODS.include?(method)
83
+ [loc.expression, true]
84
+ else
85
+ [loc.selector.join(send_downcase.loc.selector), false]
86
+ end
87
+ end
88
+
77
89
  def correction(node, _receiver, method, arg, variable)
78
90
  lambda do |corrector|
79
91
  corrector.insert_before(node.loc.expression, '!') if method == :!=
@@ -39,24 +39,32 @@ module RuboCop
39
39
  #
40
40
  # Model.where(id: [1, 2, 3]).to_a.count { |m| m.method == true }
41
41
  class Count < Cop
42
+ include SafeMode
43
+
42
44
  MSG = 'Use `count` instead of `%s...%s`.'.freeze
43
45
 
44
46
  SELECTORS = [:reject, :select].freeze
45
47
  COUNTERS = [:count, :length, :size].freeze
46
48
 
47
49
  def on_send(node)
48
- return unless should_run?
49
- selector, selector_loc, params, counter = parse(node)
50
- return unless COUNTERS.include?(counter)
51
- return unless SELECTORS.include?(selector)
52
- return if params && !params.block_pass_type?
53
- return if node.parent && node.parent.block_type?
54
-
55
- range = Parser::Source::Range.new(node.source_range.source_buffer,
56
- selector_loc.begin_pos,
57
- node.source_range.end_pos)
58
-
59
- add_offense(node, range, format(MSG, selector, counter))
50
+ return if rails_safe_mode?
51
+
52
+ @selector, @selector_loc, @params, @counter = parse(node)
53
+
54
+ check(node)
55
+ end
56
+
57
+ private
58
+
59
+ attr_reader :selector, :selector_loc, :params, :counter
60
+
61
+ def check(node)
62
+ return unless eligible_node?(node) && eligible_params? &&
63
+ eligible_method_chain?
64
+
65
+ range = source_starting_at(node) { @selector_loc.begin_pos }
66
+
67
+ add_offense(node, range, format(MSG, @selector, @counter))
60
68
  end
61
69
 
62
70
  def autocorrect(node)
@@ -64,9 +72,7 @@ module RuboCop
64
72
 
65
73
  return if selector == :reject
66
74
 
67
- range = Parser::Source::Range.new(node.source_range.source_buffer,
68
- node.loc.dot.begin_pos,
69
- node.source_range.end_pos)
75
+ range = source_starting_at(node) { |n| n.loc.dot.begin_pos }
70
76
 
71
77
  lambda do |corrector|
72
78
  corrector.remove(range)
@@ -74,37 +80,55 @@ module RuboCop
74
80
  end
75
81
  end
76
82
 
77
- private
83
+ def eligible_node?(node)
84
+ !(node.parent && node.parent.block_type?)
85
+ end
78
86
 
79
- def should_run?
80
- !(cop_config['SafeMode'.freeze] ||
81
- config['Rails'.freeze] &&
82
- config['Rails'.freeze]['Enabled'.freeze])
87
+ def eligible_params?
88
+ !(params && !params.block_pass_type?)
83
89
  end
84
90
 
85
- def parse(node)
86
- left, counter = *node
87
- expression, selector, params = *left
88
-
89
- selector_loc =
90
- if selector.is_a?(Symbol)
91
- if expression && expression.parent.loc.respond_to?(:selector)
92
- expression.parent.loc.selector
93
- elsif left.loc.respond_to?(:selector)
94
- left.loc.selector
95
- end
96
- else
97
- _enumerable, selector, params = *expression
91
+ def eligible_method_chain?
92
+ COUNTERS.include?(counter) && SELECTORS.include?(selector)
93
+ end
98
94
 
99
- expression.loc.selector if contains_selector?(expression)
95
+ def parse(node)
96
+ head, counter = *node
97
+ expression, selector, params = *head
98
+ if selector.is_a?(Symbol)
99
+ selector_loc = selector_location(expression, head.loc)
100
+ else
101
+ _, selector, params = *expression
102
+ if contains_selector?(expression)
103
+ selector_loc = expression.loc.selector
100
104
  end
105
+ end
101
106
 
102
107
  [selector, selector_loc, params, counter]
103
108
  end
104
109
 
110
+ def selector_location(expression, head_loc)
111
+ if expression && expression.parent.loc.respond_to?(:selector)
112
+ expression.parent.loc.selector
113
+ elsif head_loc.respond_to?(:selector)
114
+ head_loc.selector
115
+ end
116
+ end
117
+
105
118
  def contains_selector?(node)
106
119
  node.respond_to?(:loc) && node.loc.respond_to?(:selector)
107
120
  end
121
+
122
+ def source_starting_at(node)
123
+ begin_pos =
124
+ if block_given?
125
+ yield node
126
+ else
127
+ node.source_range.begin_pos
128
+ end
129
+
130
+ range_between(begin_pos, node.source_range.end_pos)
131
+ end
108
132
  end
109
133
  end
110
134
  end