rubocop 0.30.1 → 0.31.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 (150) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +38 -0
  3. data/README.md +10 -0
  4. data/config/default.yml +8 -1
  5. data/config/enabled.yml +28 -0
  6. data/lib/rubocop.rb +7 -0
  7. data/lib/rubocop/cli.rb +3 -2
  8. data/lib/rubocop/config.rb +12 -18
  9. data/lib/rubocop/cop/autocorrect_logic.rb +1 -1
  10. data/lib/rubocop/cop/cop.rb +35 -23
  11. data/lib/rubocop/cop/lint/block_alignment.rb +1 -1
  12. data/lib/rubocop/cop/lint/def_end_alignment.rb +6 -0
  13. data/lib/rubocop/cop/lint/deprecated_class_methods.rb +1 -1
  14. data/lib/rubocop/cop/lint/each_with_object_argument.rb +29 -0
  15. data/lib/rubocop/cop/lint/end_alignment.rb +5 -0
  16. data/lib/rubocop/cop/lint/require_parentheses.rb +1 -1
  17. data/lib/rubocop/cop/lint/space_before_first_arg.rb +1 -1
  18. data/lib/rubocop/cop/lint/string_conversion_in_interpolation.rb +1 -1
  19. data/lib/rubocop/cop/metrics/class_length.rb +1 -25
  20. data/lib/rubocop/cop/metrics/module_length.rb +24 -0
  21. data/lib/rubocop/cop/metrics/parameter_lists.rb +1 -1
  22. data/lib/rubocop/cop/mixin/autocorrect_alignment.rb +2 -2
  23. data/lib/rubocop/cop/mixin/autocorrect_unless_changing_ast.rb +2 -2
  24. data/lib/rubocop/cop/mixin/classish_length.rb +37 -0
  25. data/lib/rubocop/cop/mixin/empty_lines_around_body.rb +1 -1
  26. data/lib/rubocop/cop/mixin/end_keyword_alignment.rb +14 -1
  27. data/lib/rubocop/cop/mixin/min_body_length.rb +19 -0
  28. data/lib/rubocop/cop/mixin/on_method_def.rb +1 -0
  29. data/lib/rubocop/cop/mixin/space_after_punctuation.rb +2 -4
  30. data/lib/rubocop/cop/mixin/space_before_punctuation.rb +1 -3
  31. data/lib/rubocop/cop/mixin/space_inside.rb +1 -1
  32. data/lib/rubocop/cop/mixin/statement_modifier.rb +14 -7
  33. data/lib/rubocop/cop/mixin/string_literals_help.rb +1 -1
  34. data/lib/rubocop/cop/mixin/unused_argument.rb +1 -3
  35. data/lib/rubocop/cop/performance/count.rb +84 -0
  36. data/lib/rubocop/cop/performance/detect.rb +1 -1
  37. data/lib/rubocop/cop/performance/flat_map.rb +2 -1
  38. data/lib/rubocop/cop/performance/parallel_assignment.rb +79 -0
  39. data/lib/rubocop/cop/performance/reverse_each.rb +1 -3
  40. data/lib/rubocop/cop/performance/sample.rb +25 -18
  41. data/lib/rubocop/cop/performance/size.rb +1 -3
  42. data/lib/rubocop/cop/rails/action_filter.rb +1 -1
  43. data/lib/rubocop/cop/rails/delegate.rb +2 -5
  44. data/lib/rubocop/cop/rails/find_by.rb +1 -1
  45. data/lib/rubocop/cop/rails/find_each.rb +1 -3
  46. data/lib/rubocop/cop/rails/read_write_attribute.rb +1 -3
  47. data/lib/rubocop/cop/rails/time_zone.rb +29 -7
  48. data/lib/rubocop/cop/style/alias.rb +1 -1
  49. data/lib/rubocop/cop/style/align_hash.rb +11 -14
  50. data/lib/rubocop/cop/style/array_join.rb +11 -0
  51. data/lib/rubocop/cop/style/attr.rb +1 -3
  52. data/lib/rubocop/cop/style/bare_percent_literals.rb +1 -1
  53. data/lib/rubocop/cop/style/block_comments.rb +1 -1
  54. data/lib/rubocop/cop/style/block_delimiters.rb +2 -9
  55. data/lib/rubocop/cop/style/block_end_newline.rb +1 -1
  56. data/lib/rubocop/cop/style/braces_around_hash_parameters.rb +1 -1
  57. data/lib/rubocop/cop/style/character_literal.rb +1 -1
  58. data/lib/rubocop/cop/style/class_check.rb +1 -1
  59. data/lib/rubocop/cop/style/class_methods.rb +1 -3
  60. data/lib/rubocop/cop/style/collection_methods.rb +1 -1
  61. data/lib/rubocop/cop/style/colon_method_call.rb +1 -3
  62. data/lib/rubocop/cop/style/command_literal.rb +2 -2
  63. data/lib/rubocop/cop/style/comment_annotation.rb +9 -2
  64. data/lib/rubocop/cop/style/copyright.rb +1 -1
  65. data/lib/rubocop/cop/style/def_with_parentheses.rb +1 -1
  66. data/lib/rubocop/cop/style/deprecated_hash_methods.rb +1 -1
  67. data/lib/rubocop/cop/style/dot_position.rb +1 -1
  68. data/lib/rubocop/cop/style/empty_line_between_defs.rb +1 -3
  69. data/lib/rubocop/cop/style/empty_lines.rb +1 -1
  70. data/lib/rubocop/cop/style/empty_lines_around_access_modifier.rb +1 -1
  71. data/lib/rubocop/cop/style/empty_literal.rb +2 -6
  72. data/lib/rubocop/cop/style/encoding.rb +1 -1
  73. data/lib/rubocop/cop/style/even_odd.rb +2 -4
  74. data/lib/rubocop/cop/style/extra_spacing.rb +1 -3
  75. data/lib/rubocop/cop/style/guard_clause.rb +1 -11
  76. data/lib/rubocop/cop/style/hash_syntax.rb +1 -1
  77. data/lib/rubocop/cop/style/if_unless_modifier.rb +11 -6
  78. data/lib/rubocop/cop/style/indentation_width.rb +11 -2
  79. data/lib/rubocop/cop/style/infinite_loop.rb +8 -8
  80. data/lib/rubocop/cop/style/lambda_call.rb +1 -1
  81. data/lib/rubocop/cop/style/leading_comment_space.rb +1 -3
  82. data/lib/rubocop/cop/style/line_end_concatenation.rb +5 -7
  83. data/lib/rubocop/cop/style/method_call_parentheses.rb +1 -8
  84. data/lib/rubocop/cop/style/method_def_parentheses.rb +1 -1
  85. data/lib/rubocop/cop/style/multiline_block_chain.rb +2 -1
  86. data/lib/rubocop/cop/style/multiline_block_layout.rb +11 -8
  87. data/lib/rubocop/cop/style/multiline_if_then.rb +1 -1
  88. data/lib/rubocop/cop/style/multiline_operation_indentation.rb +3 -2
  89. data/lib/rubocop/cop/style/multiline_ternary_operator.rb +2 -1
  90. data/lib/rubocop/cop/style/negated_if.rb +1 -1
  91. data/lib/rubocop/cop/style/negated_while.rb +2 -2
  92. data/lib/rubocop/cop/style/next.rb +1 -11
  93. data/lib/rubocop/cop/style/nil_comparison.rb +3 -5
  94. data/lib/rubocop/cop/style/non_nil_check.rb +2 -2
  95. data/lib/rubocop/cop/style/not.rb +3 -5
  96. data/lib/rubocop/cop/style/numeric_literals.rb +2 -5
  97. data/lib/rubocop/cop/style/parentheses_around_condition.rb +1 -1
  98. data/lib/rubocop/cop/style/percent_literal_delimiters.rb +1 -1
  99. data/lib/rubocop/cop/style/percent_q_literals.rb +1 -1
  100. data/lib/rubocop/cop/style/perl_backrefs.rb +1 -1
  101. data/lib/rubocop/cop/style/proc.rb +1 -3
  102. data/lib/rubocop/cop/style/redundant_begin.rb +1 -1
  103. data/lib/rubocop/cop/style/redundant_exception.rb +6 -8
  104. data/lib/rubocop/cop/style/redundant_return.rb +1 -1
  105. data/lib/rubocop/cop/style/redundant_self.rb +2 -2
  106. data/lib/rubocop/cop/style/regexp_literal.rb +2 -2
  107. data/lib/rubocop/cop/style/self_assignment.rb +1 -1
  108. data/lib/rubocop/cop/style/semicolon.rb +2 -2
  109. data/lib/rubocop/cop/style/signal_exception.rb +1 -1
  110. data/lib/rubocop/cop/style/single_line_methods.rb +1 -1
  111. data/lib/rubocop/cop/style/single_space_before_first_arg.rb +1 -1
  112. data/lib/rubocop/cop/style/space_after_colon.rb +1 -3
  113. data/lib/rubocop/cop/style/space_after_control_keyword.rb +1 -3
  114. data/lib/rubocop/cop/style/space_after_method_name.rb +1 -3
  115. data/lib/rubocop/cop/style/space_after_not.rb +1 -1
  116. data/lib/rubocop/cop/style/space_around_block_parameters.rb +34 -16
  117. data/lib/rubocop/cop/style/space_around_equals_in_parameter_default.rb +1 -3
  118. data/lib/rubocop/cop/style/space_around_operators.rb +3 -2
  119. data/lib/rubocop/cop/style/space_before_block_braces.rb +1 -1
  120. data/lib/rubocop/cop/style/space_before_comment.rb +1 -3
  121. data/lib/rubocop/cop/style/space_before_modifier_keyword.rb +1 -3
  122. data/lib/rubocop/cop/style/space_inside_block_braces.rb +5 -3
  123. data/lib/rubocop/cop/style/space_inside_hash_literal_braces.rb +1 -1
  124. data/lib/rubocop/cop/style/space_inside_range_literal.rb +1 -1
  125. data/lib/rubocop/cop/style/special_global_vars.rb +1 -1
  126. data/lib/rubocop/cop/style/symbol_literal.rb +1 -1
  127. data/lib/rubocop/cop/style/symbol_proc.rb +1 -1
  128. data/lib/rubocop/cop/style/tab.rb +1 -1
  129. data/lib/rubocop/cop/style/trailing_blank_lines.rb +2 -2
  130. data/lib/rubocop/cop/style/trailing_comma.rb +1 -1
  131. data/lib/rubocop/cop/style/trailing_underscore_variable.rb +72 -0
  132. data/lib/rubocop/cop/style/trailing_whitespace.rb +1 -1
  133. data/lib/rubocop/cop/style/trivial_accessors.rb +5 -10
  134. data/lib/rubocop/cop/style/unneeded_capital_w.rb +1 -1
  135. data/lib/rubocop/cop/style/unneeded_percent_q.rb +1 -1
  136. data/lib/rubocop/cop/style/variable_interpolation.rb +2 -4
  137. data/lib/rubocop/cop/style/when_then.rb +1 -3
  138. data/lib/rubocop/cop/style/while_until_do.rb +5 -7
  139. data/lib/rubocop/cop/style/while_until_modifier.rb +4 -6
  140. data/lib/rubocop/cop/style/word_array.rb +1 -1
  141. data/lib/rubocop/cop/util.rb +6 -3
  142. data/lib/rubocop/formatter/progress_formatter.rb +3 -2
  143. data/lib/rubocop/formatter/simple_text_formatter.rb +1 -1
  144. data/lib/rubocop/rake_task.rb +2 -2
  145. data/lib/rubocop/runner.rb +2 -11
  146. data/lib/rubocop/string_util.rb +4 -2
  147. data/lib/rubocop/token.rb +3 -1
  148. data/lib/rubocop/version.rb +1 -1
  149. data/relnotes/v0.31.0.md +120 -0
  150. metadata +10 -2
@@ -29,7 +29,7 @@ module RuboCop
29
29
  end
30
30
 
31
31
  def autocorrect(node)
32
- @corrections << lambda do |corrector|
32
+ lambda do |corrector|
33
33
  receiver, method_name, *_args = *node
34
34
 
35
35
  DEPRECATED_METHODS.each do |data|
@@ -0,0 +1,29 @@
1
+ # encoding: utf-8
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Lint
6
+ # This cop checks if each_with_object is called with an immutable
7
+ # argument. Since the argument is the object that the given block shall
8
+ # make calls on to build something based on the enumerable that
9
+ # each_with_object iterates over, an immutable argument makes no sense.
10
+ # It's definitely a bug.
11
+ #
12
+ # @example
13
+ #
14
+ # sum = numbers.each_with_object(0) { |e, a| a += e }
15
+ class EachWithObjectArgument < Cop
16
+ MSG = 'The argument to each_with_object can not be immutable.'
17
+
18
+ def on_send(node)
19
+ _receiver, method_name, *args = *node
20
+ return unless method_name == :each_with_object
21
+ return unless args.length == 1
22
+
23
+ arg = args.first
24
+ add_offense(node, :expression) if arg.int_type? || arg.float_type?
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
@@ -71,6 +71,11 @@ module RuboCop
71
71
  def line_break_before_keyword?(whole_expression, rhs)
72
72
  rhs.loc.keyword.line > whole_expression.line
73
73
  end
74
+
75
+ def autocorrect(node)
76
+ align(node,
77
+ style == :variable ? node.each_ancestor(:lvasgn).first : node)
78
+ end
74
79
  end
75
80
  end
76
81
  end
@@ -41,7 +41,7 @@ module RuboCop
41
41
  private
42
42
 
43
43
  def check_ternary(arg, node)
44
- condition, _, _ = *arg
44
+ condition, = *arg
45
45
  return unless offense?(condition)
46
46
 
47
47
  expr = node.loc.expression
@@ -36,7 +36,7 @@ module RuboCop
36
36
  end
37
37
 
38
38
  def autocorrect(range)
39
- @corrections << ->(corrector) { corrector.insert_before(range, ' ') }
39
+ ->(corrector) { corrector.insert_before(range, ' ') }
40
40
  end
41
41
  end
42
42
  end
@@ -32,7 +32,7 @@ module RuboCop
32
32
  private
33
33
 
34
34
  def autocorrect(node)
35
- @corrections << lambda do |corrector|
35
+ lambda do |corrector|
36
36
  receiver, _method_name, *_args = *node
37
37
  corrector.replace(
38
38
  node.loc.expression,
@@ -7,7 +7,7 @@ module RuboCop
7
7
  # Comment lines can optionally be ignored.
8
8
  # The maximum allowed length is configurable.
9
9
  class ClassLength < Cop
10
- include CodeLength
10
+ include ClassishLength
11
11
 
12
12
  def on_class(node)
13
13
  check_code_length(node)
@@ -18,30 +18,6 @@ module RuboCop
18
18
  def message(length, max_length)
19
19
  format('Class definition is too long. [%d/%d]', length, max_length)
20
20
  end
21
-
22
- def code_length(node)
23
- class_body_line_numbers = line_range(node).to_a[1...-1]
24
-
25
- target_line_numbers = class_body_line_numbers -
26
- line_numbers_of_inner_classes(node)
27
-
28
- target_line_numbers.reduce(0) do |length, line_number|
29
- source_line = processed_source[line_number]
30
- next length if irrelevant_line(source_line)
31
- length + 1
32
- end
33
- end
34
-
35
- def line_numbers_of_inner_classes(node)
36
- line_numbers = Set.new
37
-
38
- node.each_descendant(:class, :module) do |inner_node|
39
- line_range = line_range(inner_node)
40
- line_numbers.merge(line_range)
41
- end
42
-
43
- line_numbers.to_a
44
- end
45
21
  end
46
22
  end
47
23
  end
@@ -0,0 +1,24 @@
1
+ # encoding: utf-8
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Metrics
6
+ # This cop checks if the length a module exceeds some maximum value.
7
+ # Comment lines can optionally be ignored.
8
+ # The maximum allowed length is configurable.
9
+ class ModuleLength < Cop
10
+ include ClassishLength
11
+
12
+ def on_module(node)
13
+ check_code_length(node)
14
+ end
15
+
16
+ private
17
+
18
+ def message(length, max_length)
19
+ format('Module definition is too long. [%d/%d]', length, max_length)
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -27,7 +27,7 @@ module RuboCop
27
27
  if count_keyword_args?
28
28
  node.children.size
29
29
  else
30
- node.children.reject { |a| a.type == :kwoptarg }.size
30
+ node.children.count { |a| a.type != :kwoptarg }
31
31
  end
32
32
  end
33
33
 
@@ -35,9 +35,9 @@ module RuboCop
35
35
  # value of @column_delta. A local variable fixes the problem.
36
36
  column_delta = @column_delta
37
37
 
38
- fail CorrectionNotPossible if block_comment_within?(expr)
38
+ return if block_comment_within?(expr)
39
39
 
40
- @corrections << lambda do |corrector|
40
+ lambda do |corrector|
41
41
  each_line(expr) do |line_begin_pos|
42
42
  autocorrect_line(corrector, line_begin_pos, expr, column_delta,
43
43
  heredoc_ranges)
@@ -15,10 +15,10 @@ module RuboCop
15
15
 
16
16
  # Make the correction only if it doesn't change the AST for the buffer.
17
17
  if processed_source.ast != ProcessedSource.new(new_buffer_src).ast
18
- fail CorrectionNotPossible
18
+ return
19
19
  end
20
20
 
21
- @corrections << correction(node)
21
+ correction(node)
22
22
  end
23
23
 
24
24
  private
@@ -0,0 +1,37 @@
1
+ # encoding: utf-8
2
+
3
+ module RuboCop
4
+ module Cop
5
+ # Common functionality for checking length of classes and modules.
6
+ module ClassishLength
7
+ include CodeLength
8
+
9
+ private
10
+
11
+ def code_length(node)
12
+ body_line_numbers = line_range(node).to_a[1...-1]
13
+
14
+ target_line_numbers = body_line_numbers -
15
+ line_numbers_of_inner_thing(node, :module) -
16
+ line_numbers_of_inner_thing(node, :class)
17
+
18
+ target_line_numbers.reduce(0) do |length, line_number|
19
+ source_line = processed_source[line_number]
20
+ next length if irrelevant_line(source_line)
21
+ length + 1
22
+ end
23
+ end
24
+
25
+ def line_numbers_of_inner_thing(node, type)
26
+ line_numbers = Set.new
27
+
28
+ node.each_descendant(:module, type) do |inner_node|
29
+ line_range = line_range(inner_node)
30
+ line_numbers.merge(line_range)
31
+ end
32
+
33
+ line_numbers.to_a
34
+ end
35
+ end
36
+ end
37
+ end
@@ -12,7 +12,7 @@ module RuboCop
12
12
  MSG_MISSING = 'Empty line missing at %s body %s.'
13
13
 
14
14
  def autocorrect(range)
15
- @corrections << lambda do |corrector|
15
+ lambda do |corrector|
16
16
  case style
17
17
  when :no_empty_lines then corrector.remove(range)
18
18
  when :empty_lines then corrector.insert_before(range, "\n")
@@ -24,7 +24,7 @@ module RuboCop
24
24
 
25
25
  if kw_loc.line != end_loc.line &&
26
26
  kw_loc.column != end_loc.column + offset
27
- add_offense(nil, end_loc,
27
+ add_offense(node, end_loc,
28
28
  format(MSG, end_loc.line, end_loc.column,
29
29
  alignment_base, kw_loc.line, kw_loc.column)) do
30
30
  opposite_style_detected
@@ -37,6 +37,19 @@ module RuboCop
37
37
  def parameter_name
38
38
  'AlignWith'
39
39
  end
40
+
41
+ def align(node, alignment_node)
42
+ source_buffer = node.loc.expression.source_buffer
43
+ begin_pos = node.loc.end.begin_pos
44
+ whitespace = Parser::Source::Range.new(source_buffer,
45
+ begin_pos - node.loc.end.column,
46
+ begin_pos)
47
+ return false unless whitespace.source.strip.empty?
48
+
49
+ column = alignment_node ? alignment_node.loc.expression.column : 0
50
+
51
+ ->(corrector) { corrector.replace(whitespace, ' ' * column) }
52
+ end
40
53
  end
41
54
  end
42
55
  end
@@ -0,0 +1,19 @@
1
+ # encoding: utf-8
2
+
3
+ module RuboCop
4
+ module Cop
5
+ # Common functionality for checking minimum body length.
6
+ module MinBodyLength
7
+ def min_body_length?(node)
8
+ (node.loc.end.line - node.loc.keyword.line) > min_body_length
9
+ end
10
+
11
+ def min_body_length
12
+ length = cop_config['MinBodyLength'] || 1
13
+ return length if length.is_a?(Integer) && length > 0
14
+
15
+ fail 'MinBodyLength needs to be a positive integer!'
16
+ end
17
+ end
18
+ end
19
+ end
@@ -22,6 +22,7 @@ module RuboCop
22
22
  def visibility_and_def_on_same_line?(receiver, method_name, args)
23
23
  !receiver &&
24
24
  [:public, :protected, :private,
25
+ :private_class_method, :public_class_method,
25
26
  :module_function].include?(method_name) &&
26
27
  args.size == 1 && [:def, :defs].include?(args.first.type)
27
28
  end
@@ -11,7 +11,7 @@ module RuboCop
11
11
  processed_source.tokens.each_cons(2) do |t1, t2|
12
12
  next unless kind(t1) && t1.pos.line == t2.pos.line &&
13
13
  t2.pos.column == t1.pos.column + offset &&
14
- ![:tRPAREN, :tRBRACK].include?(t2.type)
14
+ ![:tRPAREN, :tRBRACK, :tPIPE].include?(t2.type)
15
15
 
16
16
  add_offense(t1, t1.pos, format(MSG, kind(t1)))
17
17
  end
@@ -24,9 +24,7 @@ module RuboCop
24
24
  end
25
25
 
26
26
  def autocorrect(token)
27
- @corrections << lambda do |corrector|
28
- corrector.replace(token.pos, token.pos.source + ' ')
29
- end
27
+ ->(corrector) { corrector.replace(token.pos, token.pos.source + ' ') }
30
28
  end
31
29
  end
32
30
  end
@@ -23,9 +23,7 @@ module RuboCop
23
23
  end
24
24
 
25
25
  def autocorrect(pos_before_punctuation)
26
- @corrections << lambda do |corrector|
27
- corrector.remove(pos_before_punctuation)
28
- end
26
+ ->(corrector) { corrector.remove(pos_before_punctuation) }
29
27
  end
30
28
  end
31
29
  end
@@ -27,7 +27,7 @@ module RuboCop
27
27
  end
28
28
 
29
29
  def autocorrect(range)
30
- @corrections << ->(corrector) { corrector.remove(range) }
30
+ ->(corrector) { corrector.remove(range) }
31
31
  end
32
32
 
33
33
  # Wraps info about the brackets. Makes it easy to check whether a token
@@ -6,7 +6,6 @@ module RuboCop
6
6
  module StatementModifier
7
7
  include IfNode
8
8
 
9
- # TODO: Extremely ugly solution that needs lots of polish.
10
9
  def fit_within_line_as_modifier_form?(node)
11
10
  case node.loc.keyword.source
12
11
  when 'if' then cond, body, _else = *node
@@ -19,8 +18,9 @@ module RuboCop
19
18
  body_length = body_length(body)
20
19
 
21
20
  return false if body_length == 0
22
-
23
21
  return false if cond.each_node.any?(&:lvasgn_type?)
22
+ return false if body_has_comment?(body)
23
+ return false if end_keyword_has_comment?(node)
24
24
 
25
25
  indentation = node.loc.keyword.column
26
26
  kw_length = node.loc.keyword.size
@@ -28,7 +28,8 @@ module RuboCop
28
28
  space = 1
29
29
  total = indentation + body_length + space + kw_length + space +
30
30
  cond_length
31
- total <= max_line_length && !body_has_comment?(body)
31
+
32
+ total <= max_line_length
32
33
  end
33
34
 
34
35
  def max_line_length
@@ -37,7 +38,7 @@ module RuboCop
37
38
  end
38
39
 
39
40
  def length(node)
40
- node.loc.expression.source.lines.to_a.size
41
+ node.loc.expression.source.lines.grep(/\S/).size
41
42
  end
42
43
 
43
44
  def body_length(body)
@@ -49,9 +50,15 @@ module RuboCop
49
50
  end
50
51
 
51
52
  def body_has_comment?(body)
52
- comment_lines = processed_source.comments.map(&:location).map(&:line)
53
- body_line = body.loc.expression.line
54
- comment_lines.include?(body_line)
53
+ comment_lines.include?(body.loc.expression.line)
54
+ end
55
+
56
+ def end_keyword_has_comment?(node)
57
+ comment_lines.include?(node.loc.end.line)
58
+ end
59
+
60
+ def comment_lines
61
+ @comment_lines ||= processed_source.comments.map(&:location).map(&:line)
55
62
  end
56
63
  end
57
64
  end
@@ -17,7 +17,7 @@ module RuboCop
17
17
  end
18
18
 
19
19
  def autocorrect(node)
20
- @corrections << lambda do |corrector|
20
+ lambda do |corrector|
21
21
  replacement = node.loc.begin.is?('"') ? "'" : '"'
22
22
  corrector.replace(node.loc.begin, replacement)
23
23
  corrector.replace(node.loc.end, replacement)
@@ -26,9 +26,7 @@ module RuboCop
26
26
  def autocorrect(node)
27
27
  return if [:kwarg, :kwoptarg].include?(node.type)
28
28
 
29
- @corrections << lambda do |corrector|
30
- corrector.insert_before(node.loc.name, '_')
31
- end
29
+ ->(corrector) { corrector.insert_before(node.loc.name, '_') }
32
30
  end
33
31
  end
34
32
  end
@@ -0,0 +1,84 @@
1
+ # encoding: utf-8
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Performance
6
+ # This cop is used to identify usages of `count` on an
7
+ # `Enumerable` and change them to `size`.
8
+ #
9
+ # @example
10
+ # # bad
11
+ # [1, 2, 3].select { |e| e > 2 }.size
12
+ # [1, 2, 3].reject { |e| e > 2 }.size
13
+ # [1, 2, 3].select { |e| e > 2 }.length
14
+ # [1, 2, 3].reject { |e| e > 2 }.length
15
+ # [1, 2, 3].select { |e| e > 2 }.count { |e| e.odd? }
16
+ # [1, 2, 3].reject { |e| e > 2 }.count { |e| e.even? }
17
+ #
18
+ # # good
19
+ # [1, 2, 3].count { |e| e > 2 }
20
+ # [1, 2, 3].count { |e| e < 2 }
21
+ # [1, 2, 3].count { |e| e > 2 && e.odd? }
22
+ # [1, 2, 3].count { |e| e < 2 && e.even? }
23
+ class Count < Cop
24
+ MSG = 'Use `count` instead of `%s...%s`.'
25
+
26
+ SELECTORS = [:reject, :select]
27
+ COUNTERS = [:count, :length, :size]
28
+
29
+ def on_send(node)
30
+ expression, first_method, second_method, third_method = parse(node)
31
+
32
+ return unless COUNTERS.include?(third_method)
33
+
34
+ begin_pos = if SELECTORS.include?(first_method)
35
+ return if second_method.is_a?(Symbol)
36
+ expression.loc.selector.begin_pos
37
+ else
38
+ return unless SELECTORS.include?(second_method)
39
+ expression.parent.loc.selector.begin_pos
40
+ end
41
+
42
+ return if node.parent && node.parent.block_type?
43
+
44
+ range = Parser::Source::Range.new(node.loc.expression.source_buffer,
45
+ begin_pos,
46
+ node.loc.expression.end_pos)
47
+
48
+ add_offense(node, range,
49
+ format(MSG, first_method || second_method, third_method))
50
+ end
51
+
52
+ def autocorrect(node)
53
+ expression, first_method, second_method, = parse(node)
54
+
55
+ return if first_method == :reject || second_method == :reject
56
+
57
+ selector = if SELECTORS.include?(first_method)
58
+ expression.loc.selector
59
+ else
60
+ expression.parent.loc.selector
61
+ end
62
+
63
+ lambda do |corrector|
64
+ range = Parser::Source::Range.new(node.loc.expression.source_buffer,
65
+ node.loc.dot.begin_pos,
66
+ node.loc.expression.end_pos)
67
+ corrector.remove(range)
68
+ corrector.replace(selector, 'count')
69
+ end
70
+ end
71
+
72
+ private
73
+
74
+ def parse(node)
75
+ left, third_method = *node
76
+ expression, second_method = *left
77
+ _enumerable, first_method = *expression
78
+
79
+ [expression, first_method, second_method, third_method]
80
+ end
81
+ end
82
+ end
83
+ end
84
+ end