rubocop 0.7.2 → 0.8.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 (184) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +7 -1
  3. data/CHANGELOG.md +19 -0
  4. data/README.md +4 -8
  5. data/bin/rubocop +2 -2
  6. data/config/default.yml +8 -0
  7. data/config/enabled.yml +21 -24
  8. data/lib/rubocop.rb +9 -7
  9. data/lib/rubocop/cli.rb +73 -52
  10. data/lib/rubocop/config.rb +8 -5
  11. data/lib/rubocop/cop/access_control.rb +41 -0
  12. data/lib/rubocop/cop/alias.rb +7 -5
  13. data/lib/rubocop/cop/align_parameters.rb +20 -96
  14. data/lib/rubocop/cop/and_or.rb +26 -0
  15. data/lib/rubocop/cop/ascii_comments.rb +3 -8
  16. data/lib/rubocop/cop/ascii_identifiers.rb +6 -5
  17. data/lib/rubocop/cop/avoid_class_vars.rb +5 -10
  18. data/lib/rubocop/cop/avoid_for.rb +7 -5
  19. data/lib/rubocop/cop/avoid_global_vars.rb +19 -7
  20. data/lib/rubocop/cop/avoid_perl_backrefs.rb +7 -10
  21. data/lib/rubocop/cop/avoid_perlisms.rb +11 -10
  22. data/lib/rubocop/cop/block_comments.rb +4 -6
  23. data/lib/rubocop/cop/blocks.rb +11 -47
  24. data/lib/rubocop/cop/case_indentation.rb +9 -31
  25. data/lib/rubocop/cop/class_and_module_camel_case.rb +20 -11
  26. data/lib/rubocop/cop/class_methods.rb +5 -10
  27. data/lib/rubocop/cop/collection_methods.rb +16 -16
  28. data/lib/rubocop/cop/colon_method_call.rb +8 -32
  29. data/lib/rubocop/cop/constant_name.rb +24 -0
  30. data/lib/rubocop/cop/cop.rb +20 -78
  31. data/lib/rubocop/cop/def_parentheses.rb +43 -35
  32. data/lib/rubocop/cop/empty_line_between_defs.rb +11 -15
  33. data/lib/rubocop/cop/empty_lines.rb +20 -9
  34. data/lib/rubocop/cop/empty_literal.rb +47 -0
  35. data/lib/rubocop/cop/encoding.rb +3 -3
  36. data/lib/rubocop/cop/end_of_line.rb +3 -3
  37. data/lib/rubocop/cop/ensure_return.rb +6 -23
  38. data/lib/rubocop/cop/eval.rb +7 -10
  39. data/lib/rubocop/cop/favor_join.rb +9 -24
  40. data/lib/rubocop/cop/favor_modifier.rb +38 -48
  41. data/lib/rubocop/cop/favor_percent_r.rb +7 -7
  42. data/lib/rubocop/cop/favor_sprintf.rb +8 -24
  43. data/lib/rubocop/cop/favor_unless_over_negated_if.rb +19 -17
  44. data/lib/rubocop/cop/handle_exceptions.rb +7 -11
  45. data/lib/rubocop/cop/hash_syntax.rb +29 -14
  46. data/lib/rubocop/cop/if_then_else.rb +32 -29
  47. data/lib/rubocop/cop/leading_comment_space.rb +5 -8
  48. data/lib/rubocop/cop/line_continuation.rb +4 -7
  49. data/lib/rubocop/cop/line_length.rb +3 -3
  50. data/lib/rubocop/cop/loop.rb +33 -0
  51. data/lib/rubocop/cop/method_and_variable_snake_case.rb +42 -19
  52. data/lib/rubocop/cop/method_length.rb +34 -37
  53. data/lib/rubocop/cop/new_lambda_literal.rb +8 -6
  54. data/lib/rubocop/cop/not.rb +10 -4
  55. data/lib/rubocop/cop/numeric_literals.rb +9 -7
  56. data/lib/rubocop/cop/offence.rb +1 -1
  57. data/lib/rubocop/cop/op_method.rb +12 -22
  58. data/lib/rubocop/cop/parameter_lists.rb +12 -6
  59. data/lib/rubocop/cop/parentheses_around_condition.rb +11 -11
  60. data/lib/rubocop/cop/percent_r.rb +7 -7
  61. data/lib/rubocop/cop/reduce_arguments.rb +13 -51
  62. data/lib/rubocop/cop/rescue_exception.rb +13 -29
  63. data/lib/rubocop/cop/rescue_modifier.rb +5 -8
  64. data/lib/rubocop/cop/semicolon.rb +15 -74
  65. data/lib/rubocop/cop/single_line_methods.rb +28 -44
  66. data/lib/rubocop/cop/space_after_comma_etc.rb +29 -9
  67. data/lib/rubocop/cop/space_after_control_keyword.rb +16 -15
  68. data/lib/rubocop/cop/string_literals.rb +9 -35
  69. data/lib/rubocop/cop/surrounding_space.rb +213 -112
  70. data/lib/rubocop/cop/symbol_array.rb +9 -7
  71. data/lib/rubocop/cop/symbol_name.rb +23 -0
  72. data/lib/rubocop/cop/syntax.rb +14 -7
  73. data/lib/rubocop/cop/tab.rb +3 -3
  74. data/lib/rubocop/cop/ternary_operator.rb +26 -24
  75. data/lib/rubocop/cop/trailing_whitespace.rb +3 -5
  76. data/lib/rubocop/cop/trivial_accessors.rb +18 -95
  77. data/lib/rubocop/cop/unless_else.rb +11 -7
  78. data/lib/rubocop/cop/util.rb +26 -0
  79. data/lib/rubocop/cop/variable_interpolation.rb +18 -10
  80. data/lib/rubocop/cop/when_then.rb +6 -17
  81. data/lib/rubocop/cop/word_array.rb +18 -19
  82. data/lib/rubocop/version.rb +1 -1
  83. data/rubocop.gemspec +1 -0
  84. data/spec/project_spec.rb +1 -1
  85. data/spec/rubocop/cli_spec.rb +16 -9
  86. data/spec/rubocop/config_spec.rb +13 -3
  87. data/spec/rubocop/cops/access_control_spec.rb +129 -0
  88. data/spec/rubocop/cops/alias_spec.rb +2 -6
  89. data/spec/rubocop/cops/align_parameters_spec.rb +58 -71
  90. data/spec/rubocop/cops/and_or_spec.rb +37 -0
  91. data/spec/rubocop/cops/ascii_comments_spec.rb +3 -4
  92. data/spec/rubocop/cops/ascii_identifiers_spec.rb +3 -4
  93. data/spec/rubocop/cops/avoid_class_vars_spec.rb +7 -2
  94. data/spec/rubocop/cops/avoid_for_spec.rb +1 -4
  95. data/spec/rubocop/cops/{avoid_global_vars.rb → avoid_global_vars_spec.rb} +4 -4
  96. data/spec/rubocop/cops/avoid_perl_backrefs_spec.rb +1 -1
  97. data/spec/rubocop/cops/avoid_perlisms_spec.rb +5 -5
  98. data/spec/rubocop/cops/block_comments_spec.rb +0 -4
  99. data/spec/rubocop/cops/blocks_spec.rb +33 -0
  100. data/spec/rubocop/cops/case_indentation_spec.rb +5 -5
  101. data/spec/rubocop/cops/class_and_module_camel_case_spec.rb +15 -5
  102. data/spec/rubocop/cops/class_methods_spec.rb +4 -4
  103. data/spec/rubocop/cops/collection_methods_spec.rb +9 -4
  104. data/spec/rubocop/cops/colon_method_call_spec.rb +11 -5
  105. data/spec/rubocop/cops/constant_name_spec.rb +42 -0
  106. data/spec/rubocop/cops/def_with_parentheses_spec.rb +13 -8
  107. data/spec/rubocop/cops/def_without_parentheses_spec.rb +11 -5
  108. data/spec/rubocop/cops/empty_line_between_defs_spec.rb +38 -38
  109. data/spec/rubocop/cops/empty_lines_spec.rb +15 -3
  110. data/spec/rubocop/cops/empty_literal_spec.rb +90 -0
  111. data/spec/rubocop/cops/encoding_spec.rb +9 -9
  112. data/spec/rubocop/cops/end_of_line_spec.rb +2 -2
  113. data/spec/rubocop/cops/ensure_return_spec.rb +1 -3
  114. data/spec/rubocop/cops/eval_spec.rb +8 -5
  115. data/spec/rubocop/cops/favor_join_spec.rb +1 -5
  116. data/spec/rubocop/cops/favor_modifier_spec.rb +16 -14
  117. data/spec/rubocop/cops/{favor_percent_r.rb → favor_percent_r_spec.rb} +6 -6
  118. data/spec/rubocop/cops/favor_sprintf_spec.rb +3 -9
  119. data/spec/rubocop/cops/favor_unless_over_negated_if_spec.rb +4 -4
  120. data/spec/rubocop/cops/favor_until_over_negated_while_spec.rb +3 -3
  121. data/spec/rubocop/cops/handle_exceptions_spec.rb +1 -3
  122. data/spec/rubocop/cops/hash_syntax_spec.rb +11 -6
  123. data/spec/rubocop/cops/if_with_semicolon_spec.rb +7 -1
  124. data/spec/rubocop/cops/leading_comment_space_spec.rb +0 -7
  125. data/spec/rubocop/cops/line_continuation_spec.rb +2 -2
  126. data/spec/rubocop/cops/line_length_spec.rb +2 -2
  127. data/spec/rubocop/cops/loop_spec.rb +31 -0
  128. data/spec/rubocop/cops/method_and_variable_snake_case_spec.rb +38 -12
  129. data/spec/rubocop/cops/method_length_spec.rb +85 -85
  130. data/spec/rubocop/cops/multiline_if_then_spec.rb +15 -15
  131. data/spec/rubocop/cops/new_lambda_literal_spec.rb +3 -3
  132. data/spec/rubocop/cops/not_spec.rb +1 -4
  133. data/spec/rubocop/cops/numeric_literals_spec.rb +13 -13
  134. data/spec/rubocop/cops/one_line_conditional_spec.rb +1 -1
  135. data/spec/rubocop/cops/op_method_spec.rb +2 -9
  136. data/spec/rubocop/cops/parameter_lists_spec.rb +7 -7
  137. data/spec/rubocop/cops/parentheses_around_condition_spec.rb +41 -44
  138. data/spec/rubocop/cops/percent_r_spec.rb +6 -6
  139. data/spec/rubocop/cops/reduce_arguments_spec.rb +4 -4
  140. data/spec/rubocop/cops/rescue_exception_spec.rb +48 -8
  141. data/spec/rubocop/cops/rescue_modifier_spec.rb +2 -5
  142. data/spec/rubocop/cops/semicolon_spec.rb +2 -30
  143. data/spec/rubocop/cops/single_line_methods_spec.rb +13 -13
  144. data/spec/rubocop/cops/space_after_colon_spec.rb +3 -3
  145. data/spec/rubocop/cops/space_after_comma_spec.rb +14 -2
  146. data/spec/rubocop/cops/space_after_control_keyword_spec.rb +42 -3
  147. data/spec/rubocop/cops/space_after_semicolon_spec.rb +2 -2
  148. data/spec/rubocop/cops/space_around_braces_spec.rb +18 -3
  149. data/spec/rubocop/cops/space_around_equals_in_default_parameter_spec.rb +4 -4
  150. data/spec/rubocop/cops/space_around_operators_spec.rb +82 -27
  151. data/spec/rubocop/cops/space_inside_brackets_spec.rb +13 -7
  152. data/spec/rubocop/cops/space_inside_hash_literal_braces_spec.rb +14 -9
  153. data/spec/rubocop/cops/space_inside_parens_spec.rb +7 -3
  154. data/spec/rubocop/cops/string_literals_spec.rb +17 -5
  155. data/spec/rubocop/cops/symbol_array_spec.rb +18 -2
  156. data/spec/rubocop/cops/symbol_name_spec.rb +119 -0
  157. data/spec/rubocop/cops/syntax_spec.rb +25 -18
  158. data/spec/rubocop/cops/tab_spec.rb +2 -2
  159. data/spec/rubocop/cops/ternary_operator_spec.rb +13 -17
  160. data/spec/rubocop/cops/trailing_whitespace_spec.rb +3 -3
  161. data/spec/rubocop/cops/trivial_accessors_spec.rb +17 -20
  162. data/spec/rubocop/cops/unless_else_spec.rb +8 -8
  163. data/spec/rubocop/cops/variable_interpolation_spec.rb +0 -5
  164. data/spec/rubocop/cops/when_then_spec.rb +14 -21
  165. data/spec/rubocop/cops/word_array_spec.rb +12 -4
  166. data/spec/spec_helper.rb +12 -4
  167. metadata +40 -31
  168. data/.document +0 -5
  169. data/lib/rubocop/cop/ampersands_pipes_vs_and_or.rb +0 -25
  170. data/lib/rubocop/cop/array_literal.rb +0 -61
  171. data/lib/rubocop/cop/brace_after_percent.rb +0 -32
  172. data/lib/rubocop/cop/grammar.rb +0 -138
  173. data/lib/rubocop/cop/hash_literal.rb +0 -61
  174. data/lib/rubocop/cop/percent_literals.rb +0 -25
  175. data/lib/rubocop/cop/symbol_snake_case.rb +0 -47
  176. data/spec/rubocop/cops/ampersands_pipes_vs_and_or_spec.rb +0 -57
  177. data/spec/rubocop/cops/array_literal_spec.rb +0 -46
  178. data/spec/rubocop/cops/brace_after_percent_spec.rb +0 -33
  179. data/spec/rubocop/cops/grammar_spec.rb +0 -81
  180. data/spec/rubocop/cops/hash_literal_spec.rb +0 -46
  181. data/spec/rubocop/cops/multiline_blocks_spec.rb +0 -24
  182. data/spec/rubocop/cops/percent_literals_spec.rb +0 -47
  183. data/spec/rubocop/cops/single_line_blocks_spec.rb +0 -22
  184. data/spec/rubocop/cops/symbol_snake_case_spec.rb +0 -93
@@ -2,57 +2,21 @@
2
2
 
3
3
  module Rubocop
4
4
  module Cop
5
- module Blocks
6
- def inspect(file, source, tokens, sexp)
7
- @file = file
5
+ class Blocks < Cop
6
+ MULTI_LINE_MSG = 'Avoid using {...} for multi-line blocks.'
7
+ SINGLE_LINE_MSG = 'Prefer {...} over do...end for single-line blocks.'
8
8
 
9
- # The @reverse_correlations maps grammar path object ids to
10
- # token indexes, so we can use it to find the corresponding }
11
- # for each {.
12
- @reverse_correlations = Hash.new([])
13
- @correlations.each do |ix, path|
14
- @reverse_correlations[path.object_id] += [ix]
15
- end
16
-
17
- tokens.each_index { |ix| check(tokens, ix) }
18
- end
19
- end
20
-
21
- class MultilineBlocks < Cop
22
- include Blocks
23
- ERROR_MESSAGE = 'Avoid using {...} for multi-line blocks.'
9
+ def on_block(node)
10
+ block_length = Util.block_length(node)
11
+ block_begin = node.loc.begin.source
24
12
 
25
- def check(tokens, ix)
26
- t = tokens[ix]
27
- if [t.type, t.text] == [:on_lbrace, '{']
28
- path = @correlations[ix] or return
29
- if path.last == :brace_block
30
- rbrace_ix = @reverse_correlations[path.object_id] - [ix]
31
- if rbrace_ix.empty?
32
- fail "\n#{@file}:#{t.pos.lineno}:#{t.pos.column}: " +
33
- 'Matching brace not found'
34
- end
35
- if tokens[*rbrace_ix].pos.lineno > t.pos.lineno
36
- add_offence(:convention, t.pos.lineno, ERROR_MESSAGE)
37
- end
38
- end
13
+ if block_length > 0 && block_begin == '{'
14
+ add_offence(:convention, node.loc.line, MULTI_LINE_MSG)
15
+ elsif block_length == 0 && block_begin != '{'
16
+ add_offence(:convention, node.loc.line, SINGLE_LINE_MSG)
39
17
  end
40
- end
41
- end
42
18
 
43
- class SingleLineBlocks < Cop
44
- include Blocks
45
- ERROR_MESSAGE = 'Prefer {...} over do...end for single-line blocks.'
46
-
47
- def check(tokens, ix)
48
- t = tokens[ix]
49
- if [t.type, t.text] == [:on_kw, 'do']
50
- end_offset = tokens[ix..-1].index { |t2| t2.text == 'end' } or return
51
- end_token_ix = ix + end_offset
52
- if tokens[end_token_ix].pos.lineno == t.pos.lineno
53
- add_offence(:convention, t.pos.lineno, ERROR_MESSAGE)
54
- end
55
- end
19
+ super
56
20
  end
57
21
  end
58
22
  end
@@ -3,41 +3,19 @@
3
3
  module Rubocop
4
4
  module Cop
5
5
  class CaseIndentation < Cop
6
- ERROR_MESSAGE = 'Indent when as deep as case.'
6
+ MSG = 'Indent when as deep as case.'
7
7
 
8
- def inspect(file, source, tokens, sexp)
9
- case_tokens = find_keywords(tokens, 'case')
10
- when_tokens = find_keywords(tokens, 'when')
11
- each_when(sexp) do |case_ix|
12
- when_pos = when_tokens.shift.pos
13
- if when_pos.column != case_tokens[case_ix].pos.column
14
- add_offence(:convention, when_pos.lineno, ERROR_MESSAGE)
15
- end
16
- end
17
- end
8
+ def on_case(case_node)
9
+ _condition, *whens, _else = *case_node
18
10
 
19
- def find_keywords(tokens, keyword)
20
- indexes = tokens.each_index.select do |ix|
21
- keyword?(tokens, ix, keyword)
22
- end
23
- tokens.values_at(*indexes)
24
- end
11
+ case_column = case_node.location.keyword.column
25
12
 
26
- def keyword?(tokens, ix, keyword)
27
- [tokens[ix].type, tokens[ix].text] == [:on_kw, keyword] &&
28
- tokens[ix - 1].type != :on_symbeg
29
- end
30
-
31
- # Does a depth first search for :when, yielding the index of the
32
- # corresponding :case for each one.
33
- def each_when(sexp, case_ix = -1, &block)
34
- if sexp[0] == :case
35
- @total_case_ix = (@total_case_ix || -1) + 1
36
- each_when(sexp[2], @total_case_ix, &block)
37
- else
38
- yield case_ix if sexp[0] == :when
39
- sexp.grep(Array).each { |s| each_when(s, case_ix, &block) }
13
+ whens.each do |when_node|
14
+ pos = when_node.loc.keyword
15
+ add_offence(:convention, pos.line, MSG) if pos.column != case_column
40
16
  end
17
+
18
+ super
41
19
  end
42
20
  end
43
21
  end
@@ -3,17 +3,26 @@
3
3
  module Rubocop
4
4
  module Cop
5
5
  class ClassAndModuleCamelCase < Cop
6
- ERROR_MESSAGE = 'Use CamelCase for classes and modules.'
7
-
8
- def inspect(file, source, tokens, sexp)
9
- [:class, :module].each do |keyword|
10
- each(keyword, sexp) do |s|
11
- if s[1][0] == :const_ref && s[1][1][0] == :@const &&
12
- s[1][1][1] =~ /_/
13
- add_offence(:convention, s[1][1][2].lineno, ERROR_MESSAGE)
14
- end
15
- end
16
- end
6
+ MSG = 'Use CamelCase for classes and modules.'
7
+
8
+ def on_class(node)
9
+ check_name(node)
10
+
11
+ super
12
+ end
13
+
14
+ def on_module(node)
15
+ check_name(node)
16
+
17
+ super
18
+ end
19
+
20
+ private
21
+
22
+ def check_name(node)
23
+ name = node.loc.name.source
24
+
25
+ add_offence(:convention, node.loc.line, MSG) if name =~ /_/
17
26
  end
18
27
  end
19
28
  end
@@ -3,17 +3,12 @@
3
3
  module Rubocop
4
4
  module Cop
5
5
  class ClassMethods < Cop
6
- ERROR_MESSAGE = 'Prefer self over class/module for class/module methods.'
6
+ MSG = 'Prefer self over class/module for class/module methods.'
7
7
 
8
- def inspect(file, source, tokens, sexp)
9
- # defs nodes correspond to class & module methods
10
- each(:defs, sexp) do |s|
11
- if s[1][0] == :var_ref && s[1][1][0] == :@const
12
- add_offence(:convention,
13
- s[1][1][2].lineno,
14
- ERROR_MESSAGE)
15
- end
16
- end
8
+ def on_defs(node)
9
+ definee, _name, _args, _body = *node
10
+
11
+ add_offence(:convention, node.loc.line, MSG) if definee.type == :const
17
12
  end
18
13
  end
19
14
  end
@@ -3,25 +3,25 @@
3
3
  module Rubocop
4
4
  module Cop
5
5
  class CollectionMethods < Cop
6
+ MSG = 'Prefer %s over %s.'
7
+
6
8
  PREFERRED_METHODS = {
7
- 'collect' => 'map',
8
- 'inject' => 'reduce',
9
- 'detect' => 'find',
10
- 'find_all' => 'select',
9
+ collect: 'map',
10
+ inject: 'reduce',
11
+ detect: 'find',
12
+ find_all: 'select'
11
13
  }
12
14
 
13
- def inspect(file, source, tokens, sexp)
14
- each(:call, sexp) do |s|
15
- s.drop(2).each_slice(2) do |m|
16
- method_name = m[1][1]
17
- if PREFERRED_METHODS[method_name]
18
- add_offence(
19
- :convention,
20
- m[1][2].lineno,
21
- "Prefer #{PREFERRED_METHODS[method_name]} over #{method_name}."
22
- )
23
- end
24
- end
15
+ def on_send(node)
16
+ receiver, method_name, *_args = *node
17
+
18
+ # a simple(but flawed way) to reduce false positives
19
+ if receiver && PREFERRED_METHODS[method_name]
20
+ add_offence(
21
+ :convention,
22
+ node.loc.line,
23
+ sprintf(MSG, PREFERRED_METHODS[method_name], method_name)
24
+ )
25
25
  end
26
26
  end
27
27
  end
@@ -3,41 +3,17 @@
3
3
  module Rubocop
4
4
  module Cop
5
5
  class ColonMethodCall < Cop
6
- ERROR_MESSAGE = 'Do not use :: for method invocation.'
6
+ MSG = 'Do not use :: for method invocation.'
7
7
 
8
- def inspect(file, source, tokens, sexp)
9
- state = :outside
10
- tokens.each do |t|
11
- state = case [state, t.type]
12
- when [:outside, :on_const]
13
- :const
8
+ def on_send(node)
9
+ receiver, _method_name, *_args = *node
14
10
 
15
- when [:outside, :on_ident]
16
- :ident
17
-
18
- when [:const, :on_op]
19
- t.text == '::' ? :const_colon : :outside
20
-
21
- when [:ident, :on_op]
22
- t.text == '::' ? :ident_colon : :outside
23
-
24
- when [:ident_colon, :on_ident]
25
- add_offence(:convention, t.pos.lineno, ERROR_MESSAGE)
26
- :ident
27
-
28
- when [:const_colon, :on_ident]
29
- add_offence(:convention, t.pos.lineno, ERROR_MESSAGE)
30
- :ident
31
-
32
- when [:ident_colon, :on_const]
33
- :const
34
-
35
- when [:const_colon, :on_const]
36
- :const
37
- else
38
- :outside
39
- end || state
11
+ # discard methods with nil receivers and op methods(like [])
12
+ if receiver && node.loc.dot && node.loc.dot.source == '::'
13
+ add_offence(:convention, node.loc.line, MSG)
40
14
  end
15
+
16
+ super
41
17
  end
42
18
  end
43
19
  end
@@ -0,0 +1,24 @@
1
+ # encoding: utf-8
2
+
3
+ module Rubocop
4
+ module Cop
5
+ class ConstantName < Cop
6
+ MSG = 'Use SCREAMING_SNAKE_CASE for constants.'
7
+ SNAKE_CASE = /^[\dA-Z_]+$/
8
+
9
+ def on_casgn(node)
10
+ _scope, const_name, value = *node
11
+
12
+ # we cannot know the result of method calls line
13
+ # NewClass = something_that_returns_a_class
14
+ if value.type != :send && const_name !~ SNAKE_CASE
15
+ add_offence(:convention,
16
+ node.loc.line,
17
+ MSG)
18
+ end
19
+
20
+ super
21
+ end
22
+ end
23
+ end
24
+ end
@@ -2,38 +2,24 @@
2
2
 
3
3
  module Rubocop
4
4
  module Cop
5
- class Position < Struct.new :lineno, :column
6
- # Does a recursive search and replaces each [lineno, column] array
7
- # in the sexp with a Position object.
8
- def self.make_position_objects(sexp)
9
- if sexp[0] =~ /^@/
10
- sexp[2] = Position.new(*sexp[2])
11
- else
12
- sexp.grep(Array).each { |s| make_position_objects(s) }
13
- end
14
- end
15
-
16
- # The point of this class is to provide named attribute access.
17
- # So we don't want backwards compatibility with array indexing.
18
- undef_method :[]
19
- end
20
-
21
5
  class Token
22
6
  attr_reader :pos, :type, :text
23
7
 
24
8
  def initialize(pos, type, text)
25
- @pos, @type, @text = Position.new(*pos), type, text
9
+ @pos, @type, @text = pos, type, text
26
10
  end
27
11
 
28
12
  def to_s
29
- "[[#{@pos.lineno}, #{@pos.column}], #{@type}, #{@text.inspect}]"
13
+ "[[#{@pos.line}, #{@pos.column}], #{@type}, #{@text.inspect}]"
30
14
  end
31
15
  end
32
16
 
33
- class Cop
17
+ class Cop < Parser::AST::Processor
18
+ extend AST::Sexp
19
+
34
20
  attr_accessor :offences
35
21
  attr_accessor :debug
36
- attr_writer :correlations, :disabled_lines
22
+ attr_writer :disabled_lines
37
23
 
38
24
  @all = []
39
25
  @config = {}
@@ -60,6 +46,14 @@ module Rubocop
60
46
  !@offences.empty?
61
47
  end
62
48
 
49
+ def inspect(source, tokens, ast, comments)
50
+ process(ast)
51
+ comments.each { |c| on_comment(c) }
52
+ end
53
+
54
+ def on_comment(comment)
55
+ end
56
+
63
57
  def add_offence(severity, line_number, message)
64
58
  unless @disabled_lines && @disabled_lines.include?(line_number)
65
59
  message = debug ? "#{name}: #{message}" : message
@@ -73,68 +67,16 @@ module Rubocop
73
67
 
74
68
  private
75
69
 
76
- def each_parent_of(sym, sexp)
77
- parents = []
78
- sexp.each do |elem|
79
- if Array === elem
80
- if elem[0] == sym
81
- parents << sexp unless parents.include?(sexp)
82
- elem = elem[1..-1]
83
- end
84
- each_parent_of(sym, elem) do |parent|
85
- parents << parent unless parents.include?(parent)
86
- end
87
- end
88
- end
89
- parents.each { |parent| yield parent }
90
- end
91
-
92
- def each(sym, sexp)
93
- yield sexp if sexp[0] == sym
94
- sexp.each do |elem|
95
- each(sym, elem) { |s| yield s } if Array === elem
96
- end
97
- end
70
+ def on_node(syms, sexp, excludes = [])
71
+ yield sexp if Array(syms).include?(sexp.type)
98
72
 
99
- def find_all(sym, sexp)
100
- result = []
101
- each(sym, sexp) { |s| result << s }
102
- result
103
- end
73
+ return if Array(excludes).include?(sexp.type)
104
74
 
105
- def find_first(sym, sexp)
106
- find_all(sym, sexp).first
107
- end
108
-
109
- def whitespace?(token)
110
- [:on_sp, :on_ignored_nl, :on_nl].include?(token.type)
111
- end
112
-
113
- def all_positions(sexp)
114
- return [sexp[2]] if sexp[0] =~ /^@/
115
- sexp.grep(Array).reduce([]) { |a, e| a + all_positions(e) }
116
- end
117
-
118
- def keywords(tokens)
119
- # We need to keep track of the previous token to avoid
120
- # interpreting :some_keyword as the keyword some_keyword.
121
- prev = Token.new(0, :init, '')
122
- # Same goes for defs so we need to track those as well.
123
- keywords = []
124
-
125
- tokens.reject { |t| whitespace?(t) }.each do |t|
126
- if prev.type != :on_symbeg && t.type == :on_kw &&
127
- [prev.type, prev.text] != [:on_kw, 'def']
128
- keywords << t
75
+ sexp.children.each do |elem|
76
+ if Parser::AST::Node === elem
77
+ on_node(syms, elem, excludes) { |s| yield s }
129
78
  end
130
- prev = t
131
79
  end
132
-
133
- keywords
134
- end
135
-
136
- def each_keyword(keyword, tokens)
137
- keywords(tokens).select { |t| t.text == keyword }.each { |t| yield t }
138
80
  end
139
81
  end
140
82
  end
@@ -2,52 +2,60 @@
2
2
 
3
3
  module Rubocop
4
4
  module Cop
5
- module DefParentheses
6
- EMPTY_PARAMS = [:params, nil, nil, nil,
7
- nil, nil, nil, nil] if RUBY_VERSION >= '2.0.0'
8
- EMPTY_PARAMS = [:params, nil, nil, nil,
9
- nil, nil] if RUBY_VERSION < '2.0.0'
10
-
11
- def inspect(file, source, tokens, sexp)
12
- each(:def, sexp) { |def_sexp| check(tokens, def_sexp) }
13
- end
14
- end
15
-
16
5
  class DefWithParentheses < Cop
17
- include DefParentheses
18
- def error_message
19
- "Omit the parentheses in defs when the method doesn't accept any " +
20
- 'arguments.'
6
+ MSG = "Omit the parentheses in defs when the method doesn't accept " +
7
+ 'any arguments.'
8
+
9
+ def on_def(node)
10
+ start_line = node.loc.keyword.line
11
+ end_line = node.loc.end.line
12
+
13
+ return if start_line == end_line
14
+
15
+ _, args = *node
16
+ if args.children == [] && args.loc.begin
17
+ add_offence(:convention, node.loc.line, MSG)
18
+ end
19
+
20
+ super
21
21
  end
22
22
 
23
- def check(tokens, def_sexp)
24
- if def_sexp[2][0] == :paren && def_sexp[2][1] == EMPTY_PARAMS
25
- pos = def_sexp[1][-1]
26
- method_name_ix = tokens.index { |t| t.pos == pos }
27
- start = method_name_ix + 1
28
- rparen_ix = start + tokens[start..-1].index { |t| t.text == ')' }
29
- first_body_token = tokens[(rparen_ix + 1)..-1].find do |t|
30
- !whitespace?(t)
31
- end
32
- if first_body_token.pos.lineno > pos.lineno
33
- # Only report offence if there's a line break after
34
- # the empty parens.
35
- add_offence(:convention, pos.lineno, error_message)
36
- end
23
+ def on_defs(node)
24
+ start_line = node.loc.keyword.line
25
+ end_line = node.loc.end.line
26
+
27
+ return if start_line == end_line
28
+
29
+ _, _, args = *node
30
+ if args.children == [] && args.loc.begin
31
+ add_offence(:convention, node.loc.line, MSG)
37
32
  end
33
+
34
+ super
38
35
  end
39
36
  end
40
37
 
41
38
  class DefWithoutParentheses < Cop
42
- include DefParentheses
43
- def error_message
44
- 'Use def with parentheses when there are arguments.'
39
+ MSG = 'Use def with parentheses when there are arguments.'
40
+
41
+ def on_def(node)
42
+ _, args = *node
43
+
44
+ if args.children.size > 0 && args.loc.begin.nil?
45
+ add_offence(:convention, node.loc.line, MSG)
46
+ end
47
+
48
+ super
45
49
  end
46
50
 
47
- def check(tokens, def_sexp)
48
- if def_sexp[2][0] == :params && def_sexp[2] != EMPTY_PARAMS
49
- add_offence(:convention, def_sexp[1][-1].lineno, error_message)
51
+ def on_defs(node)
52
+ _, _, args = *node
53
+
54
+ if args.children.size > 0 && args.loc.begin.nil?
55
+ add_offence(:convention, node.loc.line, MSG)
50
56
  end
57
+
58
+ super
51
59
  end
52
60
  end
53
61
  end