rubocop 0.25.0 → 0.26.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 (113) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +3 -0
  3. data/CHANGELOG.md +37 -0
  4. data/README.md +2 -2
  5. data/assets/output.html.erb +190 -0
  6. data/config/default.yml +14 -2
  7. data/config/disabled.yml +7 -0
  8. data/config/enabled.yml +132 -5
  9. data/lib/rubocop.rb +5 -0
  10. data/lib/rubocop/cop/commissioner.rb +4 -10
  11. data/lib/rubocop/cop/lint/assignment_in_condition.rb +1 -1
  12. data/lib/rubocop/cop/lint/end_in_method.rb +3 -8
  13. data/lib/rubocop/cop/lint/ensure_return.rb +2 -2
  14. data/lib/rubocop/cop/lint/space_before_first_arg.rb +8 -1
  15. data/lib/rubocop/cop/lint/useless_assignment.rb +35 -0
  16. data/lib/rubocop/cop/lint/useless_setter_call.rb +2 -3
  17. data/lib/rubocop/cop/metrics/block_nesting.rb +3 -3
  18. data/lib/rubocop/cop/metrics/class_length.rb +1 -2
  19. data/lib/rubocop/cop/mixin/access_modifier_node.rb +5 -1
  20. data/lib/rubocop/cop/mixin/autocorrect_alignment.rb +2 -2
  21. data/lib/rubocop/cop/mixin/configurable_naming.rb +2 -2
  22. data/lib/rubocop/cop/mixin/method_complexity.rb +2 -4
  23. data/lib/rubocop/cop/mixin/statement_modifier.rb +1 -3
  24. data/lib/rubocop/cop/rails/delegate.rb +1 -1
  25. data/lib/rubocop/cop/rails/validation.rb +25 -2
  26. data/lib/rubocop/cop/style/alias.rb +1 -1
  27. data/lib/rubocop/cop/style/and_or.rb +12 -2
  28. data/lib/rubocop/cop/style/braces_around_hash_parameters.rb +19 -12
  29. data/lib/rubocop/cop/style/documentation.rb +1 -1
  30. data/lib/rubocop/cop/style/dot_position.rb +20 -0
  31. data/lib/rubocop/cop/style/empty_lines_around_access_modifier.rb +5 -1
  32. data/lib/rubocop/cop/style/encoding.rb +4 -4
  33. data/lib/rubocop/cop/style/format_string.rb +12 -2
  34. data/lib/rubocop/cop/style/if_unless_modifier.rb +8 -11
  35. data/lib/rubocop/cop/style/infinite_loop.rb +57 -0
  36. data/lib/rubocop/cop/style/multiline_block_chain.rb +15 -16
  37. data/lib/rubocop/cop/style/multiline_if_then.rb +10 -0
  38. data/lib/rubocop/cop/style/nested_ternary_operator.rb +3 -3
  39. data/lib/rubocop/cop/style/percent_literal_delimiters.rb +3 -1
  40. data/lib/rubocop/cop/style/predicate_name.rb +23 -5
  41. data/lib/rubocop/cop/style/redundant_begin.rb +1 -1
  42. data/lib/rubocop/cop/style/single_line_block_params.rb +1 -1
  43. data/lib/rubocop/cop/style/space_around_equals_in_parameter_default.rb +4 -8
  44. data/lib/rubocop/cop/style/space_inside_hash_literal_braces.rb +9 -11
  45. data/lib/rubocop/cop/style/space_inside_range_literal.rb +58 -0
  46. data/lib/rubocop/cop/style/special_global_vars.rb +1 -1
  47. data/lib/rubocop/cop/style/symbol_proc.rb +71 -0
  48. data/lib/rubocop/cop/style/tab.rb +11 -3
  49. data/lib/rubocop/cop/style/unneeded_capital_w.rb +6 -2
  50. data/lib/rubocop/cop/style/variable_name.rb +4 -14
  51. data/lib/rubocop/cop/style/while_until_modifier.rb +12 -8
  52. data/lib/rubocop/cop/variable_force.rb +17 -30
  53. data/lib/rubocop/cop/variable_force/assignment.rb +15 -23
  54. data/lib/rubocop/cop/variable_force/locatable.rb +29 -8
  55. data/lib/rubocop/cop/variable_force/scope.rb +34 -23
  56. data/lib/rubocop/cop/variable_force/variable.rb +7 -10
  57. data/lib/rubocop/formatter/disabled_config_formatter.rb +3 -2
  58. data/lib/rubocop/formatter/formatter_set.rb +1 -0
  59. data/lib/rubocop/formatter/fuubar_style_formatter.rb +1 -1
  60. data/lib/rubocop/formatter/html_formatter.rb +90 -0
  61. data/lib/rubocop/formatter/progress_formatter.rb +1 -1
  62. data/lib/rubocop/options.rb +1 -0
  63. data/lib/rubocop/processed_source.rb +10 -1
  64. data/lib/rubocop/string_util.rb +153 -0
  65. data/lib/rubocop/target_finder.rb +1 -1
  66. data/lib/rubocop/version.rb +1 -1
  67. data/relnotes/v0.26.0.md +89 -0
  68. data/rubocop.gemspec +1 -0
  69. data/spec/rubocop/cli_spec.rb +60 -34
  70. data/spec/rubocop/config_loader_spec.rb +19 -15
  71. data/spec/rubocop/cop/commissioner_spec.rb +2 -2
  72. data/spec/rubocop/cop/lint/block_alignment_spec.rb +74 -58
  73. data/spec/rubocop/cop/lint/space_before_first_arg_spec.rb +7 -0
  74. data/spec/rubocop/cop/lint/useless_assignment_spec.rb +173 -0
  75. data/spec/rubocop/cop/rails/validation_spec.rb +9 -2
  76. data/spec/rubocop/cop/style/access_modifier_indentation_spec.rb +26 -0
  77. data/spec/rubocop/cop/style/and_or_spec.rb +52 -61
  78. data/spec/rubocop/cop/style/braces_around_hash_parameters_spec.rb +26 -8
  79. data/spec/rubocop/cop/style/case_indentation_spec.rb +8 -8
  80. data/spec/rubocop/cop/style/def_with_parentheses_spec.rb +6 -2
  81. data/spec/rubocop/cop/style/dot_position_spec.rb +39 -0
  82. data/spec/rubocop/cop/style/empty_lines_around_access_modifier_spec.rb +12 -2
  83. data/spec/rubocop/cop/style/encoding_spec.rb +16 -28
  84. data/spec/rubocop/cop/style/format_string_spec.rb +12 -0
  85. data/spec/rubocop/cop/style/infinite_loop_spec.rb +48 -0
  86. data/spec/rubocop/cop/style/method_def_parentheses_spec.rb +3 -1
  87. data/spec/rubocop/cop/style/multiline_if_then_spec.rb +9 -0
  88. data/spec/rubocop/cop/style/percent_literal_delimiters_spec.rb +21 -1
  89. data/spec/rubocop/cop/style/predicate_name_spec.rb +44 -13
  90. data/spec/rubocop/cop/style/redundant_begin_spec.rb +32 -0
  91. data/spec/rubocop/cop/style/space_inside_range_literal_spec.rb +52 -0
  92. data/spec/rubocop/cop/style/symbol_proc_spec.rb +76 -0
  93. data/spec/rubocop/cop/style/tab_spec.rb +30 -0
  94. data/spec/rubocop/cop/style/trailing_whitespace_spec.rb +2 -1
  95. data/spec/rubocop/cop/style/unneeded_capital_w_spec.rb +18 -5
  96. data/spec/rubocop/cop/style/variable_name_spec.rb +5 -5
  97. data/spec/rubocop/cop/style/when_then_spec.rb +3 -1
  98. data/spec/rubocop/cop/style/while_until_do_spec.rb +4 -2
  99. data/spec/rubocop/cop/util_spec.rb +1 -9
  100. data/spec/rubocop/cop/variable_force/assignment_spec.rb +2 -15
  101. data/spec/rubocop/cop/variable_force/locatable_spec.rb +2 -37
  102. data/spec/rubocop/cop/variable_force/scope_spec.rb +156 -49
  103. data/spec/rubocop/cop/variable_force/variable_spec.rb +2 -1
  104. data/spec/rubocop/cop/variable_force_spec.rb +2 -1
  105. data/spec/rubocop/formatter/emacs_style_formatter_spec.rb +2 -1
  106. data/spec/rubocop/formatter/html_formatter_spec.rb +145 -0
  107. data/spec/rubocop/formatter/simple_text_formatter_spec.rb +18 -6
  108. data/spec/rubocop/options_spec.rb +1 -0
  109. data/spec/rubocop/path_util_spec.rb +6 -4
  110. data/spec/rubocop/processed_source_spec.rb +17 -1
  111. data/spec/rubocop/string_util_spec.rb +46 -0
  112. metadata +33 -4
  113. data/spec/support/ast_helper.rb +0 -15
@@ -16,6 +16,7 @@ require 'powerpack/string/strip_indent'
16
16
  require 'rubocop/version'
17
17
 
18
18
  require 'rubocop/path_util'
19
+ require 'rubocop/string_util'
19
20
 
20
21
  require 'rubocop/cop/util'
21
22
  require 'rubocop/cop/offense'
@@ -166,6 +167,7 @@ require 'rubocop/cop/style/indent_array'
166
167
  require 'rubocop/cop/style/indent_hash'
167
168
  require 'rubocop/cop/style/indentation_consistency'
168
169
  require 'rubocop/cop/style/indentation_width'
170
+ require 'rubocop/cop/style/infinite_loop'
169
171
  require 'rubocop/cop/style/inline_comment'
170
172
  require 'rubocop/cop/style/lambda'
171
173
  require 'rubocop/cop/style/lambda_call'
@@ -226,9 +228,11 @@ require 'rubocop/cop/style/space_inside_block_braces'
226
228
  require 'rubocop/cop/style/space_inside_brackets'
227
229
  require 'rubocop/cop/style/space_inside_hash_literal_braces'
228
230
  require 'rubocop/cop/style/space_inside_parens'
231
+ require 'rubocop/cop/style/space_inside_range_literal'
229
232
  require 'rubocop/cop/style/special_global_vars'
230
233
  require 'rubocop/cop/style/string_literals'
231
234
  require 'rubocop/cop/style/symbol_array'
235
+ require 'rubocop/cop/style/symbol_proc'
232
236
  require 'rubocop/cop/style/tab'
233
237
  require 'rubocop/cop/style/trailing_blank_lines'
234
238
  require 'rubocop/cop/style/trailing_comma'
@@ -263,6 +267,7 @@ require 'rubocop/formatter/clang_style_formatter'
263
267
  require 'rubocop/formatter/progress_formatter'
264
268
  require 'rubocop/formatter/fuubar_style_formatter'
265
269
  require 'rubocop/formatter/json_formatter'
270
+ require 'rubocop/formatter/html_formatter'
266
271
  require 'rubocop/formatter/file_list_formatter'
267
272
  require 'rubocop/formatter/offense_count_formatter'
268
273
  require 'rubocop/formatter/formatter_set'
@@ -7,24 +7,18 @@ module RuboCop
7
7
  class Commissioner < Parser::AST::Processor
8
8
  attr_reader :errors
9
9
 
10
- METHODS_NOT_DEFINED_IN_PARSER_PROCESSOR = [
11
- :on_sym, :on_str, :on_int, :on_float
12
- ]
13
-
14
10
  def self.callback_methods
15
- Parser::AST::Processor.instance_methods.select do |method|
16
- method.to_s =~ /^on_/
17
- end + METHODS_NOT_DEFINED_IN_PARSER_PROCESSOR
11
+ Parser::Meta::NODE_TYPES.map { |type| "on_#{type}" }
18
12
  end
19
13
 
20
14
  # Methods that are not defined in Parser::AST::Processor
21
15
  # won't have a `super` to call. So we should not attempt
22
16
  # to invoke `super` when defining them.
23
17
  def self.call_super(callback)
24
- if METHODS_NOT_DEFINED_IN_PARSER_PROCESSOR.include?(callback)
25
- ''
26
- else
18
+ if Parser::AST::Processor.method_defined?(callback)
27
19
  'super'
20
+ else
21
+ ''
28
22
  end
29
23
  end
30
24
 
@@ -30,7 +30,7 @@ module RuboCop
30
30
  # assignments inside blocks are not what we're looking for
31
31
  return if condition.type == :block
32
32
 
33
- on_node([:begin, *EQUALS_ASGN_NODES], condition) do |asgn_node|
33
+ condition.each_node(:begin, *EQUALS_ASGN_NODES) do |asgn_node|
34
34
  # skip safe assignment nodes if safe assignment is allowed
35
35
  return if safe_assignment_allowed? && safe_assignment?(asgn_node)
36
36
 
@@ -5,16 +5,11 @@ module RuboCop
5
5
  module Lint
6
6
  # This cop checks for END blocks in method definitions.
7
7
  class EndInMethod < Cop
8
- include OnMethod
9
-
10
8
  MSG = '`END` found in method definition. Use `at_exit` instead.'
11
9
 
12
- private
13
-
14
- def on_method(node, _method_name, _args, _body)
15
- on_node(:postexe, node) do |end_node|
16
- add_offense(end_node, :keyword)
17
- end
10
+ def on_postexe(node)
11
+ inside_of_method = node.each_ancestor(:def, :defs).count.nonzero?
12
+ add_offense(node, :keyword) if inside_of_method
18
13
  end
19
14
  end
20
15
  end
@@ -12,8 +12,8 @@ module RuboCop
12
12
 
13
13
  return unless ensure_body
14
14
 
15
- on_node(:return, ensure_body) do |e|
16
- add_offense(e, :expression)
15
+ ensure_body.each_node(:return) do |return_node|
16
+ add_offense(return_node, :expression)
17
17
  end
18
18
  end
19
19
  end
@@ -28,8 +28,15 @@ module RuboCop
28
28
 
29
29
  arg1 = args.first.loc.expression
30
30
  arg1_with_space = range_with_surrounding_space(arg1, :left)
31
+ space = Parser::Source::Range.new(arg1.source_buffer,
32
+ arg1_with_space.begin_pos,
33
+ arg1.begin_pos)
31
34
 
32
- add_offense(nil, arg1) if arg1_with_space.source =~ /\A\S/
35
+ add_offense(space, arg1) if arg1_with_space.source =~ /\A\S/
36
+ end
37
+
38
+ def autocorrect(range)
39
+ @corrections << ->(corrector) { corrector.insert_before(range, ' ') }
33
40
  end
34
41
  end
35
42
  end
@@ -14,6 +14,7 @@ module RuboCop
14
14
  # rescue, ensure, etc.
15
15
  class UselessAssignment < Cop
16
16
  MSG = 'Useless assignment to variable - `%s`.'
17
+ MINIMUM_SIMILARITY_TO_SUGGEST = 0.9
17
18
 
18
19
  def join_force?(force_class)
19
20
  force_class == VariableForce
@@ -57,6 +58,9 @@ module RuboCop
57
58
  non_assignment_operator = assignment.operator.sub(/=$/, '')
58
59
  message << " Use just operator `#{non_assignment_operator}`."
59
60
  end
61
+ else
62
+ similar_name = find_similar_name(variable.name, variable.scope)
63
+ message << " Did you mean `#{similar_name}`?" if similar_name
60
64
  end
61
65
 
62
66
  message
@@ -72,6 +76,37 @@ module RuboCop
72
76
  body_node
73
77
  end
74
78
  end
79
+
80
+ def find_similar_name(target_name, scope)
81
+ names = collect_variable_like_names(scope)
82
+ names.delete(target_name)
83
+
84
+ scores = names.each_with_object({}) do |name, hash|
85
+ score = StringUtil.similarity(target_name, name)
86
+ hash[name] = score if score >= MINIMUM_SIMILARITY_TO_SUGGEST
87
+ end
88
+
89
+ most_similar_name, _max_score = scores.max_by { |_, score| score }
90
+ most_similar_name
91
+ end
92
+
93
+ def collect_variable_like_names(scope)
94
+ names = scope.each_node.with_object(Set.new) do |node, set|
95
+ if variable_like_method_invocation?(node)
96
+ _receiver, method_name, = *node
97
+ set << method_name
98
+ end
99
+ end
100
+
101
+ variable_names = scope.variables.each_value.map(&:name)
102
+ names.merge(variable_names)
103
+ end
104
+
105
+ def variable_like_method_invocation?(node)
106
+ return false unless node.send_type?
107
+ receiver, _method_name, *args = *node
108
+ receiver.nil? && args.empty?
109
+ end
75
110
  end
76
111
  end
77
112
  end
@@ -91,9 +91,8 @@ module RuboCop
91
91
  catch(:skip_children) do
92
92
  yield node
93
93
 
94
- node.children.each do |child|
95
- next unless child.is_a?(Parser::AST::Node)
96
- scan(child, &block)
94
+ node.each_child_node do |child_node|
95
+ scan(child_node, &block)
97
96
  end
98
97
  end
99
98
  end
@@ -39,9 +39,9 @@ module RuboCop
39
39
  end
40
40
  end
41
41
  end
42
- node.children.each do |child|
43
- next unless child.is_a?(Parser::AST::Node)
44
- check_nesting_level(child, max, current_level)
42
+
43
+ node.each_child_node do |child_node|
44
+ check_nesting_level(child_node, max, current_level)
45
45
  end
46
46
  end
47
47
 
@@ -35,8 +35,7 @@ module RuboCop
35
35
  def line_numbers_of_inner_classes(node)
36
36
  line_numbers = Set.new
37
37
 
38
- on_node([:class, :module], node) do |inner_node|
39
- next if inner_node.eql?(node)
38
+ node.each_descendant(:class, :module) do |inner_node|
40
39
  line_range = line_range(inner_node)
41
40
  line_numbers.merge(line_range)
42
41
  end
@@ -9,9 +9,13 @@ module RuboCop
9
9
  PRIVATE_NODE = s(:send, nil, :private)
10
10
  PROTECTED_NODE = s(:send, nil, :protected)
11
11
  PUBLIC_NODE = s(:send, nil, :public)
12
+ MODUDULE_FUNCTION_NODE = s(:send, nil, :module_function)
12
13
 
13
14
  def modifier_node?(node)
14
- [PRIVATE_NODE, PROTECTED_NODE, PUBLIC_NODE].include?(node)
15
+ [PRIVATE_NODE,
16
+ PROTECTED_NODE,
17
+ PUBLIC_NODE,
18
+ MODUDULE_FUNCTION_NODE].include?(node)
15
19
  end
16
20
  end
17
21
  end
@@ -57,7 +57,7 @@ module RuboCop
57
57
  return [] unless arg.is_a?(Parser::AST::Node)
58
58
 
59
59
  heredoc_ranges = []
60
- on_node(:dstr, arg) do |n|
60
+ arg.each_node(:dstr) do |n|
61
61
  if n.loc.respond_to?(:heredoc_body)
62
62
  heredoc_ranges << n.loc.heredoc_body.join(n.loc.heredoc_end)
63
63
  end
@@ -66,7 +66,7 @@ module RuboCop
66
66
  end
67
67
 
68
68
  def block_comment_within?(expr)
69
- processed_source.comments.select { |c| c.document? }.find do |c|
69
+ processed_source.comments.select(&:document?).find do |c|
70
70
  within?(c.loc.expression, expr)
71
71
  end
72
72
  end
@@ -7,8 +7,8 @@ module RuboCop
7
7
  module ConfigurableNaming
8
8
  include ConfigurableEnforcedStyle
9
9
 
10
- SNAKE_CASE = /^@?[\da-z_]+[!?=]?$/
11
- CAMEL_CASE = /^@?[a-z][\da-zA-Z]+[!?=]?$/
10
+ SNAKE_CASE = /^@{0,2}[\da-z_]+[!?=]?$/
11
+ CAMEL_CASE = /^@{0,2}[a-z][\da-zA-Z]+[!?=]?$/
12
12
 
13
13
  def check_name(node, name, name_range)
14
14
  return if operator?(name)
@@ -21,11 +21,9 @@ module RuboCop
21
21
  end
22
22
 
23
23
  def complexity(node)
24
- c = 1
25
- on_node(self.class::COUNTED_NODES, node) do |n|
26
- c += complexity_score_for(n)
24
+ node.each_node(self.class::COUNTED_NODES).reduce(1) do |score, n|
25
+ score + complexity_score_for(n)
27
26
  end
28
- c
29
27
  end
30
28
  end
31
29
  end
@@ -20,9 +20,7 @@ module RuboCop
20
20
 
21
21
  return false if body_length == 0
22
22
 
23
- on_node(:lvasgn, cond) do
24
- return false
25
- end
23
+ return false if cond.each_node.any?(&:lvasgn_type?)
26
24
 
27
25
  indentation = node.loc.keyword.column
28
26
  kw_length = node.loc.keyword.size
@@ -67,7 +67,7 @@ module RuboCop
67
67
  receiver, * = *body
68
68
  return false unless receiver.is_a? Parser::AST::Node
69
69
  return false unless receiver.type == :send
70
- receiver.children.none? { |n| n.is_a? Parser::AST::Node }
70
+ receiver.child_nodes.empty?
71
71
  end
72
72
 
73
73
  def arguments_match?(args, body)
@@ -5,7 +5,7 @@ module RuboCop
5
5
  module Rails
6
6
  # This cop checks for the use of old-style attribute validation macros.
7
7
  class Validation < Cop
8
- MSG = 'Use the new "sexy" validations (`validates` ...).'
8
+ MSG = 'Prefer the new style validations `%s` over `%s`.'
9
9
 
10
10
  BLACKLIST = [:validates_acceptance_of,
11
11
  :validates_confirmation_of,
@@ -18,11 +18,34 @@ module RuboCop
18
18
  :validates_size_of,
19
19
  :validates_uniqueness_of]
20
20
 
21
+ WHITELIST = [
22
+ 'validates :column, acceptance: value',
23
+ 'validates :column, confirmation: value',
24
+ 'validates :column, exclusion: value',
25
+ 'validates :column, format: value',
26
+ 'validates :column, inclusion: value',
27
+ 'validates :column, length: value',
28
+ 'validates :column, numericality: value',
29
+ 'validates :column, presence: value',
30
+ 'validates :column, size: value',
31
+ 'validates :column, uniqueness: value'
32
+ ]
33
+
21
34
  def on_send(node)
22
35
  receiver, method_name, *_args = *node
23
36
  return unless receiver.nil? && BLACKLIST.include?(method_name)
24
37
 
25
- add_offense(node, :selector)
38
+ add_offense(node,
39
+ :selector,
40
+ format(MSG,
41
+ preferred_method(method_name),
42
+ method_name))
43
+ end
44
+
45
+ private
46
+
47
+ def preferred_method(method)
48
+ WHITELIST[BLACKLIST.index(method.to_sym)]
26
49
  end
27
50
  end
28
51
  end
@@ -16,7 +16,7 @@ module RuboCop
16
16
  # in such scenarios we don't want to report an offense
17
17
  return unless method_name == :instance_exec
18
18
 
19
- on_node(:alias, body) { |n| ignore_node(n) }
19
+ body.each_node(:alias) { |n| ignore_node(n) }
20
20
  end
21
21
 
22
22
  def on_alias(node)
@@ -28,15 +28,25 @@ module RuboCop
28
28
  on_conditionals(node) if style == :conditionals
29
29
  end
30
30
 
31
+ def on_while_post(node)
32
+ on_conditionals(node) if style == :conditionals
33
+ end
34
+
31
35
  def on_until(node)
32
36
  on_conditionals(node) if style == :conditionals
33
37
  end
34
38
 
39
+ def on_until_post(node)
40
+ on_conditionals(node) if style == :conditionals
41
+ end
42
+
35
43
  private
36
44
 
37
45
  def on_conditionals(node)
38
- on_node([:and, :or], node) do |my_node|
39
- process_logical_op(my_node)
46
+ condition_node, = *node
47
+
48
+ condition_node.each_node(:and, :or) do |logical_node|
49
+ process_logical_op(logical_node)
40
50
  end
41
51
  end
42
52
 
@@ -48,7 +48,8 @@ module RuboCop
48
48
  if style == :no_braces
49
49
  corrector.remove(node.loc.begin)
50
50
  corrector.remove(node.loc.end)
51
- remove_trailing_comma(node, corrector)
51
+ remove_leading_whitespace(node, corrector)
52
+ remove_trailing_comma_and_whitespace(node, corrector)
52
53
  elsif style == :braces
53
54
  corrector.insert_before(node.loc.expression, '{')
54
55
  corrector.insert_after(node.loc.expression, '}')
@@ -56,18 +57,24 @@ module RuboCop
56
57
  end
57
58
  end
58
59
 
59
- def remove_trailing_comma(node, corrector)
60
- sb = node.loc.end.source_buffer
61
- pos_after_last_pair = node.children.last.loc.expression.end_pos
62
- range_after_last_pair =
63
- Parser::Source::Range.new(sb, pos_after_last_pair,
64
- node.loc.end.begin_pos)
65
- trailing_comma_offset = range_after_last_pair.source =~ /,/
66
- return unless trailing_comma_offset
60
+ def remove_leading_whitespace(node, corrector)
61
+ corrector.remove(
62
+ Parser::Source::Range.new(
63
+ node.loc.expression.source_buffer,
64
+ node.loc.begin.end_pos,
65
+ node.children.first.loc.expression.begin_pos
66
+ )
67
+ )
68
+ end
67
69
 
68
- comma_begin = pos_after_last_pair + trailing_comma_offset
69
- corrector.remove(Parser::Source::Range.new(sb, comma_begin,
70
- comma_begin + 1))
70
+ def remove_trailing_comma_and_whitespace(node, corrector)
71
+ corrector.remove(
72
+ Parser::Source::Range.new(
73
+ node.loc.expression.source_buffer,
74
+ node.children.last.loc.expression.end_pos,
75
+ node.loc.end.begin_pos
76
+ )
77
+ )
71
78
  end
72
79
 
73
80
  def non_empty_hash?(arg)
@@ -27,7 +27,7 @@ module RuboCop
27
27
  private
28
28
 
29
29
  def check(ast, ast_with_comments)
30
- on_node([:class, :module], ast) do |node|
30
+ ast.each_node(:class, :module) do |node|
31
31
  case node.type
32
32
  when :class
33
33
  _name, _superclass, body = *node
@@ -51,6 +51,26 @@ module RuboCop
51
51
  when :trailing then dot_line != selector_line
52
52
  end
53
53
  end
54
+
55
+ def autocorrect(node)
56
+ receiver, _method_name, *_args = *node
57
+ if node.loc.selector
58
+ selector = node.loc.selector
59
+ else
60
+ # l.(1) has no selector, so we use the opening parenthesis instead
61
+ selector = node.loc.begin
62
+ end
63
+
64
+ @corrections << lambda do |corrector|
65
+ corrector.remove(node.loc.dot)
66
+ case style
67
+ when :leading
68
+ corrector.insert_before(selector, '.')
69
+ when :trailing
70
+ corrector.insert_after(receiver.loc.expression, '.')
71
+ end
72
+ end
73
+ end
54
74
  end
55
75
  end
56
76
  end