rubocop 0.14.1 → 0.15.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 (109) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +5 -3
  3. data/CHANGELOG.md +245 -198
  4. data/README.md +7 -0
  5. data/Rakefile +5 -1
  6. data/config/default.yml +27 -4
  7. data/config/enabled.yml +18 -4
  8. data/lib/rubocop.rb +13 -1
  9. data/lib/rubocop/cli.rb +83 -23
  10. data/lib/rubocop/config.rb +1 -1
  11. data/lib/rubocop/cop/cop.rb +31 -6
  12. data/lib/rubocop/cop/lint/block_alignment.rb +11 -8
  13. data/lib/rubocop/cop/lint/parentheses_as_grouped_expression.rb +21 -14
  14. data/lib/rubocop/cop/lint/useless_setter_call.rb +1 -1
  15. data/lib/rubocop/cop/rails/output.rb +35 -0
  16. data/lib/rubocop/cop/style/{access_control.rb → access_modifier_indentation.rb} +18 -15
  17. data/lib/rubocop/cop/style/alias.rb +14 -2
  18. data/lib/rubocop/cop/style/align_hash.rb +174 -109
  19. data/lib/rubocop/cop/style/autocorrect_alignment.rb +38 -18
  20. data/lib/rubocop/cop/style/blocks.rb +4 -6
  21. data/lib/rubocop/cop/style/braces_around_hash_parameters.rb +3 -3
  22. data/lib/rubocop/cop/style/cyclomatic_complexity.rb +46 -0
  23. data/lib/rubocop/cop/style/empty_lines_around_access_modifier.rb +48 -0
  24. data/lib/rubocop/cop/style/empty_lines_around_body.rb +62 -0
  25. data/lib/rubocop/cop/style/end_of_line.rb +6 -2
  26. data/lib/rubocop/cop/style/favor_modifier.rb +11 -1
  27. data/lib/rubocop/cop/style/final_newline.rb +10 -4
  28. data/lib/rubocop/cop/style/hash_syntax.rb +32 -21
  29. data/lib/rubocop/cop/style/leading_comment_space.rb +9 -0
  30. data/lib/rubocop/cop/style/method_call_parentheses.rb +11 -1
  31. data/lib/rubocop/cop/style/numeric_literals.rb +11 -15
  32. data/lib/rubocop/cop/style/redundant_return.rb +7 -4
  33. data/lib/rubocop/cop/style/redundant_self.rb +3 -3
  34. data/lib/rubocop/cop/style/signal_exception.rb +4 -2
  35. data/lib/rubocop/cop/style/space_after_comma_etc.rb +7 -1
  36. data/lib/rubocop/cop/style/space_after_control_keyword.rb +6 -0
  37. data/lib/rubocop/cop/style/space_after_method_name.rb +7 -1
  38. data/lib/rubocop/cop/style/space_after_not.rb +6 -2
  39. data/lib/rubocop/cop/style/space_around_block_braces.rb +149 -0
  40. data/lib/rubocop/cop/style/space_around_equals_in_parameter_default.rb +33 -0
  41. data/lib/rubocop/cop/style/space_around_operators.rb +169 -0
  42. data/lib/rubocop/cop/style/space_before_modifier_keyword.rb +6 -0
  43. data/lib/rubocop/cop/style/space_inside.rb +35 -0
  44. data/lib/rubocop/cop/style/space_inside_brackets.rb +18 -0
  45. data/lib/rubocop/cop/style/space_inside_hash_literal_braces.rb +99 -0
  46. data/lib/rubocop/cop/style/space_inside_parens.rb +18 -0
  47. data/lib/rubocop/cop/style/special_global_vars.rb +52 -25
  48. data/lib/rubocop/cop/style/string_literals.rb +1 -1
  49. data/lib/rubocop/cop/style/surrounding_space.rb +1 -344
  50. data/lib/rubocop/cop/style/trailing_blank_lines.rb +17 -5
  51. data/lib/rubocop/cop/style/trailing_whitespace.rb +9 -5
  52. data/lib/rubocop/cop/style/trivial_accessors.rb +1 -2
  53. data/lib/rubocop/cop/style/word_array.rb +16 -1
  54. data/lib/rubocop/cop/team.rb +5 -5
  55. data/lib/rubocop/cop/util.rb +1 -0
  56. data/lib/rubocop/formatter/offence_count_formatter.rb +0 -1
  57. data/lib/rubocop/options.rb +76 -111
  58. data/lib/rubocop/rake_task.rb +4 -2
  59. data/lib/rubocop/target_finder.rb +3 -3
  60. data/lib/rubocop/version.rb +1 -1
  61. data/spec/rubocop/cli_spec.rb +123 -13
  62. data/spec/rubocop/config_spec.rb +2 -2
  63. data/spec/rubocop/cop/lint/rescue_exception_spec.rb +10 -0
  64. data/spec/rubocop/cop/lint/useless_setter_call_spec.rb +13 -0
  65. data/spec/rubocop/cop/offence_spec.rb +2 -0
  66. data/spec/rubocop/cop/rails/output_spec.rb +40 -0
  67. data/spec/rubocop/cop/style/access_modifier_indentation_spec.rb +243 -0
  68. data/spec/rubocop/cop/style/alias_spec.rb +8 -0
  69. data/spec/rubocop/cop/style/align_array_spec.rb +12 -0
  70. data/spec/rubocop/cop/style/align_hash_spec.rb +15 -0
  71. data/spec/rubocop/cop/style/braces_around_hash_parameters_spec.rb +7 -4
  72. data/spec/rubocop/cop/style/cyclomatic_complexity_spec.rb +203 -0
  73. data/spec/rubocop/cop/style/empty_lines_around_access_modifier_spec.rb +56 -0
  74. data/spec/rubocop/cop/style/empty_lines_around_body_spec.rb +87 -0
  75. data/spec/rubocop/cop/style/end_of_line_spec.rb +17 -8
  76. data/spec/rubocop/cop/style/favor_modifier_spec.rb +34 -0
  77. data/spec/rubocop/cop/style/final_newline_spec.rb +5 -0
  78. data/spec/rubocop/cop/style/hash_syntax_spec.rb +22 -2
  79. data/spec/rubocop/cop/style/leading_comment_space_spec.rb +5 -0
  80. data/spec/rubocop/cop/style/method_call_parentheses_spec.rb +39 -4
  81. data/spec/rubocop/cop/style/numeric_literals_spec.rb +5 -0
  82. data/spec/rubocop/cop/style/signal_exception_spec.rb +11 -0
  83. data/spec/rubocop/cop/style/space_after_colon_spec.rb +7 -0
  84. data/spec/rubocop/cop/style/space_after_comma_spec.rb +5 -0
  85. data/spec/rubocop/cop/style/space_after_control_keyword_spec.rb +29 -8
  86. data/spec/rubocop/cop/style/space_after_method_name_spec.rb +15 -0
  87. data/spec/rubocop/cop/style/space_after_semicolon_spec.rb +5 -0
  88. data/spec/rubocop/cop/style/space_around_block_braces_spec.rb +68 -0
  89. data/spec/rubocop/cop/style/space_around_equals_in_default_parameter_spec.rb +5 -0
  90. data/spec/rubocop/cop/style/space_around_operators_spec.rb +43 -0
  91. data/spec/rubocop/cop/style/space_before_modifier_keyword_spec.rb +23 -0
  92. data/spec/rubocop/cop/style/space_inside_brackets_spec.rb +7 -0
  93. data/spec/rubocop/cop/style/space_inside_hash_literal_braces_spec.rb +65 -23
  94. data/spec/rubocop/cop/style/space_inside_parens_spec.rb +7 -0
  95. data/spec/rubocop/cop/style/special_global_vars_spec.rb +12 -2
  96. data/spec/rubocop/cop/style/string_literals_spec.rb +6 -0
  97. data/spec/rubocop/cop/style/symbol_array_spec.rb +5 -7
  98. data/spec/rubocop/cop/style/trailing_blank_lines_spec.rb +26 -1
  99. data/spec/rubocop/cop/style/trailing_whitespace_spec.rb +7 -0
  100. data/spec/rubocop/cop/style/trivial_accessors_spec.rb +8 -0
  101. data/spec/rubocop/cop/style/word_array_spec.rb +33 -2
  102. data/spec/rubocop/cop/team_spec.rb +4 -4
  103. data/spec/rubocop/formatter/json_formatter_spec.rb +1 -1
  104. data/spec/rubocop/options_spec.rb +5 -96
  105. data/spec/rubocop/processed_source_spec.rb +3 -3
  106. data/spec/spec_helper.rb +28 -23
  107. data/spec/support/mri_syntax_checker.rb +20 -16
  108. metadata +24 -5
  109. data/spec/rubocop/cop/style/access_control_spec.rb +0 -164
@@ -9,14 +9,6 @@ module Rubocop
9
9
  MSG = 'Separate every 3 digits in the integer portion of a number' \
10
10
  'with underscores(_).'
11
11
 
12
- def min_digits
13
- cop_config['MinDigits']
14
- end
15
-
16
- def enough_digits?(number)
17
- number.to_s.size >= min_digits
18
- end
19
-
20
12
  def on_int(node)
21
13
  check(node)
22
14
  end
@@ -25,15 +17,15 @@ module Rubocop
25
17
  check(node)
26
18
  end
27
19
 
28
- def check(node)
29
- value, = *node
20
+ private
30
21
 
31
- if enough_digits?(value)
32
- int = integer_part(node)
22
+ def check(node)
23
+ int = integer_part(node)
33
24
 
34
- # TODO: handle non-decimal literals as well
35
- return if int.start_with?('0')
25
+ # TODO: handle non-decimal literals as well
26
+ return if int.start_with?('0')
36
27
 
28
+ if int.size >= min_digits
37
29
  if int =~ /\d{4}/ || int =~ /_\d{1,2}_/
38
30
  convention(node, :expression)
39
31
  end
@@ -41,7 +33,11 @@ module Rubocop
41
33
  end
42
34
 
43
35
  def integer_part(node)
44
- node.loc.expression.source.split('.').first
36
+ node.loc.expression.source.sub(/^[+-]/, '').split('.').first
37
+ end
38
+
39
+ def min_digits
40
+ cop_config['MinDigits']
45
41
  end
46
42
  end
47
43
  end
@@ -39,10 +39,13 @@ module Rubocop
39
39
 
40
40
  def autocorrect(node)
41
41
  @corrections << lambda do |corrector|
42
- expr = node.loc.expression
43
- replacement = expr.source.sub(/return\s*/, '')
44
- replacement = "[#{replacement}]" if node.children.size > 1
45
- corrector.replace(expr, replacement)
42
+ if node.children.size > 1
43
+ kids = node.children.map { |child| child.loc.expression }
44
+ corrector.insert_before(kids.first, '[')
45
+ corrector.insert_after(kids.last, ']')
46
+ end
47
+ return_kw = range_with_surrounding_space(node.loc.keyword, :right)
48
+ corrector.remove(return_kw)
46
49
  end
47
50
  end
48
51
 
@@ -102,9 +102,10 @@ module Rubocop
102
102
  end
103
103
 
104
104
  def autocorrect(node)
105
+ receiver, _method_name, *_args = *node
105
106
  @corrections << lambda do |corrector|
106
- corrector.replace(node.loc.expression,
107
- node.loc.expression.source.gsub(/self\./, ''))
107
+ corrector.remove(receiver.loc.expression)
108
+ corrector.remove(node.loc.dot)
108
109
  end
109
110
  end
110
111
 
@@ -133,7 +134,6 @@ module Rubocop
133
134
  @allowed_send_nodes << node if receiver && receiver.type == :self
134
135
  end
135
136
  end
136
-
137
137
  end
138
138
  end
139
139
  end
@@ -69,8 +69,10 @@ module Rubocop
69
69
 
70
70
  if style == :semantic
71
71
  each_command(method_name, node) do |send_node|
72
- convention(send_node, :selector, message(method_name))
73
- ignore_node(send_node)
72
+ unless ignored_node?(send_node)
73
+ convention(send_node, :selector, message(method_name))
74
+ ignore_node(send_node)
75
+ end
74
76
  end
75
77
  else
76
78
  _receiver, selector, _args = *node
@@ -14,7 +14,7 @@ module Rubocop
14
14
  processed_source.tokens.each_cons(2) do |t1, t2|
15
15
  if kind(t1) && t1.pos.line == t2.pos.line &&
16
16
  t2.pos.column == t1.pos.column + offset(t1)
17
- convention(nil, t1.pos, sprintf(MSG, kind(t1)))
17
+ convention(t1, t1.pos, sprintf(MSG, kind(t1)))
18
18
  end
19
19
  end
20
20
  end
@@ -24,6 +24,12 @@ module Rubocop
24
24
  def offset(token)
25
25
  1
26
26
  end
27
+
28
+ def autocorrect(token)
29
+ @corrections << lambda do |corrector|
30
+ corrector.insert_after(token.pos, ' ')
31
+ end
32
+ end
27
33
  end
28
34
 
29
35
  # Checks for comma (,) not follwed by some kind of space.
@@ -25,6 +25,12 @@ module Rubocop
25
25
  on_keyword(node)
26
26
  end
27
27
  end
28
+
29
+ def autocorrect(node)
30
+ @corrections << lambda do |corrector|
31
+ corrector.insert_after(node.loc.keyword, ' ')
32
+ end
33
+ end
28
34
  end
29
35
  end
30
36
  end
@@ -25,7 +25,13 @@ module Rubocop
25
25
  expr.begin_pos - 1,
26
26
  expr.begin_pos)
27
27
  if pos_before_left_paren.source =~ /\s/
28
- convention(nil, pos_before_left_paren)
28
+ convention(pos_before_left_paren, pos_before_left_paren)
29
+ end
30
+ end
31
+
32
+ def autocorrect(pos_before_left_paren)
33
+ @corrections << lambda do |corrector|
34
+ corrector.remove(pos_before_left_paren)
29
35
  end
30
36
  end
31
37
  end
@@ -27,8 +27,12 @@ module Rubocop
27
27
 
28
28
  def autocorrect(node)
29
29
  @corrections << lambda do |corrector|
30
- corrector.replace(node.loc.expression,
31
- node.loc.expression.source.gsub(/\A!\s+/, '!'))
30
+ receiver, _method_name, *_args = *node
31
+ space_range =
32
+ Parser::Source::Range.new(node.loc.selector.source_buffer,
33
+ node.loc.selector.end_pos,
34
+ receiver.loc.expression.begin_pos)
35
+ corrector.remove(space_range)
32
36
  end
33
37
  end
34
38
  end
@@ -0,0 +1,149 @@
1
+ # encoding: utf-8
2
+
3
+ # rubocop:disable SymbolName
4
+
5
+ module Rubocop
6
+ module Cop
7
+ module Style
8
+ # Checks that block braces have or don't have surrounding space depending
9
+ # on configuration. For blocks taking parameters, it checks that the left
10
+ # brace has or doesn't have trailing space depending on configuration.
11
+ class SpaceAroundBlockBraces < Cop
12
+ include SurroundingSpace
13
+
14
+ def investigate(processed_source)
15
+ return unless processed_source.ast
16
+ @processed_source = processed_source
17
+
18
+ processed_source.tokens.each_cons(2) do |t1, t2|
19
+ next if ([t1.pos, t2.pos] - positions_not_to_check).size < 2
20
+
21
+ type1, type2 = t1.type, t2.type
22
+ if [:tLCURLY, :tRCURLY].include?(type2)
23
+ check(t1, t2)
24
+ elsif type1 == :tLCURLY
25
+ if type2 == :tPIPE
26
+ check_pipe(t1, t2)
27
+ else
28
+ check(t1, t2)
29
+ end
30
+ end
31
+ end
32
+ end
33
+
34
+ def positions_not_to_check
35
+ @positions_not_to_check ||= begin
36
+ positions = []
37
+ ast = @processed_source.ast
38
+ tokens = @processed_source.tokens
39
+
40
+ on_node(:hash, ast) do |hash|
41
+ b_ix = index_of_first_token(hash)
42
+ e_ix = index_of_last_token(hash)
43
+ positions << tokens[b_ix].pos << tokens[e_ix].pos
44
+ end
45
+
46
+ # TODO: Check braces inside string/symbol/regexp/xstr
47
+ # interpolation.
48
+ on_node([:dstr, :dsym, :regexp, :xstr], ast) do |s|
49
+ b_ix = index_of_first_token(s)
50
+ e_ix = index_of_last_token(s)
51
+ tokens[b_ix..e_ix].each do |t|
52
+ positions << t.pos if t.type == :tRCURLY
53
+ end
54
+ end
55
+
56
+ positions
57
+ end
58
+ end
59
+
60
+ def check(t1, t2)
61
+ if t2.text == '{'
62
+ check_space_outside_left_brace(t1, t2)
63
+ elsif t1.text == '{' && t2.text == '}'
64
+ check_empty_braces(t1, t2)
65
+ elsif cop_config['EnforcedStyle'] == 'space_inside_braces'
66
+ check_space_inside_braces(t1, t2)
67
+ else
68
+ check_no_space_inside_braces(t1, t2)
69
+ end
70
+ end
71
+
72
+ def check_empty_braces(t1, t2)
73
+ if cop_config['EnforcedStyleForEmptyBraces'] == 'space'
74
+ check_space_inside_braces(t1, t2)
75
+ else
76
+ check_no_space_inside_braces(t1, t2)
77
+ end
78
+ end
79
+
80
+ def check_space_inside_braces(t1, t2)
81
+ unless space_between?(t1, t2)
82
+ token, what = problem_details(t1, t2)
83
+ convention(token.pos, token.pos, "Space missing inside #{what}.")
84
+ end
85
+ end
86
+
87
+ def check_no_space_inside_braces(t1, t2)
88
+ if space_between?(t1, t2)
89
+ token, what = problem_details(t1, t2)
90
+ s = space_range(token)
91
+ convention(s, s, "Space inside #{what} detected.")
92
+ end
93
+ end
94
+
95
+ def problem_details(t1, t2)
96
+ if t1.text == '{'
97
+ token = t1
98
+ what = t2.text == '}' ? 'empty braces' : '{'
99
+ else
100
+ token = t2
101
+ what = '}'
102
+ end
103
+ [token, what]
104
+ end
105
+
106
+ def check_space_outside_left_brace(t1, t2)
107
+ if t2.text == '{' && !space_between?(t1, t2)
108
+ convention(t1.pos, t2.pos, 'Space missing to the left of {.')
109
+ end
110
+ end
111
+
112
+ def check_pipe(t1, t2)
113
+ if cop_config['SpaceBeforeBlockParameters']
114
+ unless space_between?(t1, t2)
115
+ convention(t2.pos, t1.pos, 'Space between { and | missing.')
116
+ end
117
+ elsif space_between?(t1, t2)
118
+ s = space_range(t1)
119
+ convention(s, s, 'Space between { and | detected.')
120
+ end
121
+ end
122
+
123
+ def space_range(token)
124
+ src = @processed_source.buffer.source
125
+ if token.text == '{'
126
+ b = token.pos.begin_pos + 1
127
+ e = b + 1
128
+ e += 1 while src[e] =~ /\s/
129
+ else
130
+ e = token.pos.begin_pos
131
+ b = e - 1
132
+ b -= 1 while src[b - 1] =~ /\s/
133
+ end
134
+ Parser::Source::Range.new(@processed_source.buffer, b, e)
135
+ end
136
+
137
+ def autocorrect(range)
138
+ @corrections << lambda do |corrector|
139
+ case range.source
140
+ when '}', '|' then corrector.insert_before(range, ' ')
141
+ when ' ' then corrector.remove(range)
142
+ else corrector.insert_after(range, ' ')
143
+ end
144
+ end
145
+ end
146
+ end
147
+ end
148
+ end
149
+ end
@@ -0,0 +1,33 @@
1
+ # encoding: utf-8
2
+
3
+ module Rubocop
4
+ module Cop
5
+ module Style
6
+ # Checks that the equals signs in parameter default assignments
7
+ # have surrounding space.
8
+ class SpaceAroundEqualsInParameterDefault < Cop
9
+ include SurroundingSpace
10
+ MSG = 'Surrounding space missing in default value assignment.'
11
+
12
+ def investigate(processed_source)
13
+ return unless processed_source.ast
14
+ @processed_source = processed_source
15
+ on_node(:optarg, processed_source.ast) do |optarg|
16
+ index = index_of_first_token(optarg)
17
+ arg, equals, value = processed_source.tokens[index, 3]
18
+ unless space_between?(arg, equals) && space_between?(equals, value)
19
+ convention(equals.pos, equals.pos)
20
+ end
21
+ end
22
+ end
23
+
24
+ def autocorrect(range)
25
+ @corrections << lambda do |corrector|
26
+ corrector.insert_before(range, ' ')
27
+ corrector.insert_after(range, ' ')
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,169 @@
1
+ # encoding: utf-8
2
+
3
+ module Rubocop
4
+ module Cop
5
+ module Style
6
+ # Checks that operators have space around them, except for **
7
+ # which should not have surrounding space.
8
+ class SpaceAroundOperators < Cop
9
+ include SurroundingSpace
10
+ MSG_MISSING = "Surrounding space missing for operator '%s'."
11
+ MSG_DETECTED = 'Space around operator ** detected.'
12
+
13
+ # rubocop:disable SymbolName
14
+ BINARY_OPERATORS =
15
+ [:tEQL, :tAMPER2, :tPIPE, :tCARET, :tPLUS, :tMINUS, :tSTAR2,
16
+ :tDIVIDE, :tPERCENT, :tEH, :tCOLON, :tANDOP, :tOROP, :tMATCH,
17
+ :tNMATCH, :tEQ, :tNEQ, :tGT, :tRSHFT, :tGEQ, :tLT,
18
+ :tLSHFT, :tLEQ, :tASSOC, :tEQQ, :tCMP, :tOP_ASGN]
19
+
20
+ def investigate(processed_source)
21
+ return unless processed_source.ast
22
+ @processed_source = processed_source
23
+ tokens = processed_source.tokens
24
+ tokens.each_cons(3) do |token_before, token, token_after|
25
+ next if token_before.type == :kDEF # TODO: remove?
26
+ next if token_before.type == :tDOT # Called as method.
27
+ next if positions_not_to_check.include?(token.pos)
28
+
29
+ case token.type
30
+ when :tPOW, :tDSTAR
31
+ if space_on_any_side?(token_before, token, token_after)
32
+ convention(token_with_surrounding_space(token), token.pos,
33
+ MSG_DETECTED)
34
+ end
35
+ when *BINARY_OPERATORS
36
+ check_missing_space(token_before, token, token_after)
37
+ end
38
+ end
39
+ end
40
+
41
+ # Returns an array of positions marking the tokens that this cop
42
+ # should not check, either because the token is not an operator
43
+ # or because another cop does the check.
44
+ def positions_not_to_check
45
+ @positions_not_to_check ||= begin
46
+ positions = []
47
+ positions.concat(do_not_check_block_arg_pipes)
48
+ positions.concat(do_not_check_param_default)
49
+ positions.concat(do_not_check_class_lshift_self)
50
+ positions.concat(do_not_check_def_things)
51
+ positions.concat(do_not_check_singleton_operator_defs)
52
+ positions
53
+ end
54
+ end
55
+
56
+ def do_not_check_block_arg_pipes
57
+ # each { |a| }
58
+ # ^ ^
59
+ positions = []
60
+ on_node(:block, @processed_source.ast) do |b|
61
+ on_node(:args, b) do |a|
62
+ positions << a.loc.begin << a.loc.end if a.loc.begin
63
+ end
64
+ end
65
+ positions
66
+ end
67
+
68
+ def do_not_check_param_default
69
+ # func(a, b=nil)
70
+ # ^
71
+ positions = []
72
+ tokens = @processed_source.tokens
73
+ on_node(:optarg, @processed_source.ast) do |optarg|
74
+ _arg, equals, _value = tokens[index_of_first_token(optarg),
75
+ 3]
76
+ positions << equals.pos
77
+ end
78
+ positions
79
+ end
80
+
81
+ def do_not_check_class_lshift_self
82
+ # class <<self
83
+ # ^
84
+ positions = []
85
+ tokens = @processed_source.tokens
86
+ on_node(:sclass, @processed_source.ast) do |sclass|
87
+ ix = index_of_first_token(sclass)
88
+ if tokens[ix, 2].map(&:type) == [:kCLASS, :tLSHFT]
89
+ positions << tokens[ix + 1].pos
90
+ end
91
+ end
92
+ positions
93
+ end
94
+
95
+ def do_not_check_def_things
96
+ # def +(other)
97
+ # ^
98
+ positions = []
99
+ tokens = @processed_source.tokens
100
+ on_node(:def, @processed_source.ast) do |def_node|
101
+ # def each &block
102
+ # ^
103
+ # def each *args
104
+ # ^
105
+ on_node([:blockarg, :restarg], def_node) do |arg_node|
106
+ positions << tokens[index_of_first_token(arg_node)].pos
107
+ end
108
+ positions << tokens[index_of_first_token(def_node) + 1].pos
109
+ end
110
+ positions
111
+ end
112
+
113
+ def do_not_check_singleton_operator_defs
114
+ # def self.===(other)
115
+ # ^
116
+ positions = []
117
+ tokens = @processed_source.tokens
118
+ on_node(:defs, @processed_source.ast) do |defs_node|
119
+ _receiver, name, _args = *defs_node
120
+ ix = index_of_first_token(defs_node)
121
+ name_token = tokens[ix..-1].find { |t| t.text == name.to_s }
122
+ positions << name_token.pos
123
+ end
124
+ positions
125
+ end
126
+
127
+ def check_missing_space(token_before, token, token_after)
128
+ unless space_on_both_sides?(token_before, token, token_after)
129
+ text = token.text.to_s + (token.type == :tOP_ASGN ? '=' : '')
130
+ convention(token_with_surrounding_space(token), token.pos,
131
+ MSG_MISSING.format(text))
132
+ end
133
+ end
134
+
135
+ def token_with_surrounding_space(token)
136
+ src = @processed_source.buffer.source
137
+ begin_pos = token.pos.begin_pos
138
+ begin_pos -= 1 while src[begin_pos - 1] =~ /[ \t]/
139
+ end_pos = token.pos.end_pos
140
+ end_pos += 1 while src[end_pos] =~ /[ \t]/
141
+ Parser::Source::Range.new(@processed_source.buffer, begin_pos,
142
+ end_pos)
143
+ end
144
+
145
+ def space_on_both_sides?(token_before, token, token_after)
146
+ space_between?(token_before, token) && space_between?(token,
147
+ token_after)
148
+ end
149
+
150
+ def space_on_any_side?(token_before, token, token_after)
151
+ space_between?(token_before, token) || space_between?(token,
152
+ token_after)
153
+ end
154
+
155
+ def autocorrect(range)
156
+ @corrections << lambda do |corrector|
157
+ case range.source
158
+ when /\*\*/
159
+ corrector.replace(range, '**')
160
+ else
161
+ corrector.insert_before(range, ' ') unless range.source =~ /^\s/
162
+ corrector.insert_after(range, ' ') unless range.source =~ /\s$/
163
+ end
164
+ end
165
+ end
166
+ end
167
+ end
168
+ end
169
+ end