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
@@ -3,17 +3,17 @@
3
3
  module Rubocop
4
4
  module Cop
5
5
  module FavorOtherKeywordOverNegation
6
- private
7
- def check(grammar_part, sexp)
8
- each(grammar_part, sexp) do |s|
9
- # Don't complain about negative if/else. We don't want unless/else.
10
- next if s[3] && [:else, :elsif].include?(s[3][0])
6
+ def check(node)
7
+ condition, _body, _rest = *node
11
8
 
12
- condition = s[1]
13
- condition = condition[1][0] while condition[0] == :paren
9
+ # Look at last expression of contents if there's a parenthesis
10
+ # around condition.
11
+ *_, condition = *condition while condition.type == :begin
14
12
 
15
- if condition[0] == :unary && [:!, :not].include?(condition[1])
16
- add_offence(:convention, all_positions(s).first.lineno,
13
+ if condition.type == :send
14
+ _object, method = *condition
15
+ if method == :! && !(node.loc.respond_to?(:else) && node.loc.else)
16
+ add_offence(:convention, node.loc.expression.line,
17
17
  error_message)
18
18
  end
19
19
  end
@@ -23,24 +23,26 @@ module Rubocop
23
23
  class FavorUnlessOverNegatedIf < Cop
24
24
  include FavorOtherKeywordOverNegation
25
25
 
26
- def error_message
27
- 'Favor unless (or control flow or) over if for negative conditions.'
26
+ def on_if(node)
27
+ check(node)
28
+ super
28
29
  end
29
30
 
30
- def inspect(file, source, tokens, sexp)
31
- [:if, :if_mod].each { |grammar_part| check(grammar_part, sexp) }
31
+ def error_message
32
+ 'Favor unless (or control flow or) over if for negative conditions.'
32
33
  end
33
34
  end
34
35
 
35
36
  class FavorUntilOverNegatedWhile < Cop
36
37
  include FavorOtherKeywordOverNegation
37
38
 
38
- def error_message
39
- 'Favor until over while for negative conditions.'
39
+ def on_while(node)
40
+ check(node)
41
+ super
40
42
  end
41
43
 
42
- def inspect(file, source, tokens, sexp)
43
- [:while, :while_mod].each { |grammar_part| check(grammar_part, sexp) }
44
+ def error_message
45
+ 'Favor until over while for negative conditions.'
44
46
  end
45
47
  end
46
48
  end
@@ -3,18 +3,14 @@
3
3
  module Rubocop
4
4
  module Cop
5
5
  class HandleExceptions < Cop
6
- ERROR_MESSAGE = 'Do not suppress exceptions.'
6
+ MSG = 'Do not suppress exceptions.'
7
7
 
8
- def inspect(file, source, tokens, sexp)
9
- each(:begin, sexp) do |s|
10
- each(:rescue, s) do |rs|
11
- if rs[3] == [[:void_stmt]]
12
- add_offence(:warning,
13
- all_positions(s)[-1].lineno + 1,
14
- ERROR_MESSAGE)
15
- end
16
- end
17
- end
8
+ def on_resbody(node)
9
+ _exc_list_node, _exc_var_node, body_node = *node
10
+
11
+ add_offence(:warning, node.loc.line, MSG) if body_node.type == :nil
12
+
13
+ super
18
14
  end
19
15
  end
20
16
  end
@@ -3,22 +3,37 @@
3
3
  module Rubocop
4
4
  module Cop
5
5
  class HashSyntax < Cop
6
- ERROR_MESSAGE = 'Ruby 1.8 hash syntax detected'
7
-
8
- def inspect(file, source, tokens, sexp)
9
- each(:assoclist_from_args, sexp) do |assoclist_from_args|
10
- keys = assoclist_from_args[1].map { |assoc_new| assoc_new[1][0] }
11
- # If at least one of the keys in the hash is neither a symbol (:a)
12
- # nor a label (a:), we can't require the new syntax.
13
- return if keys.any? do |key|
14
- ![:symbol_literal, :@label].include?(key)
6
+ MSG = 'Ruby 1.8 hash syntax detected'
7
+
8
+ def on_hash(node)
9
+ pairs = *node
10
+
11
+ sym_indices = pairs.all? { |p| word_symbol_pair?(p) }
12
+
13
+ if sym_indices
14
+ pairs.each do |pair|
15
+ if pair.loc.operator && pair.loc.operator.source == '=>'
16
+ add_offence(:convention,
17
+ pair.loc.line,
18
+ MSG)
19
+ end
15
20
  end
16
21
  end
17
- each(:assoc_new, sexp) do |assoc_new|
18
- if assoc_new[1][0] == :symbol_literal
19
- add_offence(:convention, assoc_new[1][1][1][-1].lineno,
20
- ERROR_MESSAGE)
21
- end
22
+
23
+ super
24
+ end
25
+
26
+ private
27
+
28
+ def word_symbol_pair?(pair)
29
+ key, _value = *pair
30
+
31
+ if key.type == :sym
32
+ sym_name = key.to_a[0]
33
+
34
+ sym_name =~ /\A\w+\z/
35
+ else
36
+ false
22
37
  end
23
38
  end
24
39
  end
@@ -3,43 +3,34 @@
3
3
  module Rubocop
4
4
  module Cop
5
5
  module IfThenElse
6
- def inspect(file, source, tokens, sexp)
7
- tokens.each_with_index do |t, ix|
8
- if t.type == :on_kw && %w(if unless).include?(t.text)
9
- if kind_of_if(tokens, ix + 1) == self.class
10
- add_offence(:convention, t.pos.lineno, error_message)
11
- end
12
- end
13
- end
6
+ def on_if(node)
7
+ check(node)
8
+ super
9
+ end
10
+
11
+ def on_unless(node)
12
+ check(node)
13
+ super
14
14
  end
15
15
 
16
- def kind_of_if(tokens, ix)
17
- then_found = false
18
- tokens[ix..-1].each do |t|
19
- case t.type
20
- when :on_kw
21
- case t.text
22
- when 'then' then then_found = true
23
- when 'end' then return OneLineConditional
24
- end
25
- when :on_ignored_nl, :on_nl
26
- break
27
- when :on_semicolon
28
- return IfWithSemicolon
29
- when :on_comment
30
- break if t.text =~ /\n/
31
- when :on_sp
32
- nil
33
- else
34
- then_found = false
35
- end
16
+ def check(node)
17
+ # We won't check modifier or ternary conditionals.
18
+ if node.loc.expression.source =~ /\A(if|unless)\b/
19
+ line = offending_line(node)
20
+ add_offence(:convention, line, error_message) if line
36
21
  end
37
- then_found ? MultilineIfThen : nil
38
22
  end
39
23
  end
40
24
 
41
25
  class IfWithSemicolon < Cop
42
26
  include IfThenElse
27
+
28
+ def offending_line(node)
29
+ if node.loc.begin && node.loc.begin.source == ';'
30
+ node.loc.begin.line
31
+ end
32
+ end
33
+
43
34
  def error_message
44
35
  'Never use if x; Use the ternary operator instead.'
45
36
  end
@@ -47,6 +38,13 @@ module Rubocop
47
38
 
48
39
  class MultilineIfThen < Cop
49
40
  include IfThenElse
41
+
42
+ def offending_line(node)
43
+ if node.loc.expression.source =~ /\bthen\s*(#.*)?\s*$/
44
+ node.loc.begin.line
45
+ end
46
+ end
47
+
50
48
  def error_message
51
49
  'Never use then for multi-line if/unless.'
52
50
  end
@@ -54,6 +52,11 @@ module Rubocop
54
52
 
55
53
  class OneLineConditional < Cop
56
54
  include IfThenElse
55
+
56
+ def offending_line(node)
57
+ node.loc.expression.line unless node.loc.expression.source =~ /\n/
58
+ end
59
+
57
60
  def error_message
58
61
  'Favor the ternary operator (?:) over if/then/else/end constructs.'
59
62
  end
@@ -3,15 +3,12 @@
3
3
  module Rubocop
4
4
  module Cop
5
5
  class LeadingCommentSpace < Cop
6
- ERROR_MESSAGE = 'Missing space after #.'
6
+ MSG = 'Missing space after #.'
7
7
 
8
- def inspect(file, source, tokens, sexp)
9
- tokens.each_index do |ix|
10
- t = tokens[ix]
11
- if t.type == :on_comment && t.text =~ /^#+[^#\s]/
12
- unless t.text.start_with?('#!') && t.pos.lineno == 1
13
- add_offence(:convention, t.pos.lineno, ERROR_MESSAGE)
14
- end
8
+ def on_comment(c)
9
+ if c.text =~ /^#+[^#\s]/
10
+ unless c.text.start_with?('#!') && c.loc.line == 1
11
+ add_offence(:convention, c.loc.line, MSG)
15
12
  end
16
13
  end
17
14
  end
@@ -3,14 +3,11 @@
3
3
  module Rubocop
4
4
  module Cop
5
5
  class LineContinuation < Cop
6
- ERROR_MESSAGE = 'Avoid the use of the line continuation character(/).'
6
+ MSG = 'Avoid the use of the line continuation character(\).'
7
7
 
8
- def inspect(file, source, tokens, sexp)
9
- tokens.each_index do |ix|
10
- t = tokens[ix]
11
- if t.type == :on_sp && t.text == "\\\n"
12
- add_offence(:convention, t.pos.lineno, ERROR_MESSAGE)
13
- end
8
+ def inspect(source, tokens, ast, comments)
9
+ source.each_with_index do |line, index|
10
+ add_offence(:convention, index, MSG) if line =~ /.*\\\z/
14
11
  end
15
12
  end
16
13
  end
@@ -3,13 +3,13 @@
3
3
  module Rubocop
4
4
  module Cop
5
5
  class LineLength < Cop
6
- ERROR_MESSAGE = 'Line is too long. [%d/%d]'
6
+ MSG = 'Line is too long. [%d/%d]'
7
7
 
8
- def inspect(file, source, tokens, sexp)
8
+ def inspect(source, tokens, ast, comments)
9
9
  source.each_with_index do |line, index|
10
10
  max = LineLength.max
11
11
  if line.length > max
12
- message = sprintf(ERROR_MESSAGE, line.length, max)
12
+ message = sprintf(MSG, line.length, max)
13
13
  add_offence(:convention, index + 1, message)
14
14
  end
15
15
  end
@@ -0,0 +1,33 @@
1
+ # encoding: utf-8
2
+
3
+ module Rubocop
4
+ module Cop
5
+ class Loop < Cop
6
+ MSG = 'Use Kernel#loop with break rather than begin/end/until(or while).'
7
+
8
+ def on_while(node)
9
+ check(node)
10
+
11
+ super
12
+ end
13
+
14
+ def on_until(node)
15
+ check(node)
16
+
17
+ super
18
+ end
19
+
20
+ private
21
+
22
+ def check(node)
23
+ _cond, body = *node
24
+ type = node.type.to_s
25
+
26
+ if body.type == :begin &&
27
+ !node.loc.expression.source.start_with?(type)
28
+ add_offence(:warning, node.loc.keyword.line, MSG)
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -3,29 +3,52 @@
3
3
  module Rubocop
4
4
  module Cop
5
5
  class MethodAndVariableSnakeCase < Cop
6
- ERROR_MESSAGE = 'Use snake_case for methods and variables.'
6
+ MSG = 'Use snake_case for methods and variables.'
7
7
  SNAKE_CASE = /^@?[\da-z_]+[!?=]?$/
8
- CONSTANT = /^[A-Z]/
9
-
10
- def inspect(file, source, tokens, sexp)
11
- each(:def, sexp) { |s| check(*s[1]) }
12
-
13
- each(:assign, sexp) do |s|
14
- case s[1][0]
15
- when :var_field
16
- check(*s[1][1]) unless s[1][1][1] =~ CONSTANT
17
- when :field
18
- if s[1][1][0] == :var_ref && s[1][1][1][0..1] == [:@kw, 'self']
19
- check(*s[1][3])
20
- end
21
- end
8
+
9
+ # http://phrogz.net/programmingruby/language.html#table_18.4
10
+ OPERATOR_METHODS = %w(
11
+ | ^ & <=> == === =~ > >= < <= << >>
12
+ + - * / % ** ~ +@ -@ [] []= ` ! != !~
13
+ ).map(&:to_sym)
14
+
15
+ def inspect(source, tokens, node, comments)
16
+ on_node([:def, :defs, :lvasgn, :ivasgn, :send], node) do |n|
17
+ name = case n.type
18
+ when :def
19
+ name_of_instance_method(n)
20
+ when :defs
21
+ name_of_singleton_method(n)
22
+ when :lvasgn, :ivasgn
23
+ name_of_variable(n)
24
+ when :send
25
+ name_of_setter(n)
26
+ end
27
+
28
+ next unless name
29
+ next if name =~ SNAKE_CASE || OPERATOR_METHODS.include?(name)
30
+
31
+ add_offence(:convention, n.location.line, MSG)
22
32
  end
23
33
  end
24
34
 
25
- def check(type, name, pos)
26
- if [:@ivar, :@ident, :@const].include?(type) && name !~ SNAKE_CASE
27
- add_offence(:convention, pos.lineno, ERROR_MESSAGE)
28
- end
35
+ def name_of_instance_method(def_node)
36
+ def_node.children.first
37
+ end
38
+
39
+ def name_of_singleton_method(defs_node)
40
+ defs_node.children[1]
41
+ end
42
+
43
+ def name_of_variable(vasgn_node)
44
+ vasgn_node.children.first
45
+ end
46
+
47
+ def name_of_setter(send_node)
48
+ receiver, method_name = *send_node
49
+ return nil unless receiver && receiver.type == :self
50
+ return nil unless method_name.to_s.end_with?('=')
51
+ method_name
29
52
  end
30
53
  end
31
54
  end
@@ -3,52 +3,49 @@
3
3
  module Rubocop
4
4
  module Cop
5
5
  class MethodLength < Cop
6
- ERROR_MESSAGE = 'Method has too many lines. [%d/%d]'
7
-
8
- def inspect(file, source, tokens, sexp)
9
- def_token_indices(tokens, source).each do |t_ix|
10
- def_lineno, end_lineno = def_and_end_lines(tokens, t_ix)
11
- length = calculate_length(def_lineno, end_lineno, source)
12
-
13
- max = MethodLength.config['Max']
14
- if length > max
15
- message = sprintf(ERROR_MESSAGE, length, max)
16
- add_offence(:convention, def_lineno, message)
17
- end
18
- end
6
+ MSG = 'Method has too many lines. [%d/%d]'
7
+
8
+ def on_def(node)
9
+ check(node)
10
+
11
+ super
19
12
  end
20
13
 
21
- private
14
+ def on_defs(node)
15
+ check(node)
22
16
 
23
- def calculate_length(def_lineno, end_lineno, source)
24
- lines = source[def_lineno..(end_lineno - 2)].reject(&:empty?)
25
- unless MethodLength.config['CountComments']
26
- lines = lines.reject { |line| line =~ /^\s*#/ }
27
- end
28
- lines.size
17
+ super
29
18
  end
30
19
 
31
- def def_token_indices(tokens, source)
32
- tokens.each_index.select do |ix|
33
- t = tokens[ix]
20
+ def max_length
21
+ MethodLength.config['Max']
22
+ end
34
23
 
35
- # Need to check:
36
- # 1. if the previous character is a ':' to prevent matching ':def'
37
- # 2. if the method is a one line, which we will ignore
38
- [t.type, t.text] == [:on_kw, 'def'] &&
39
- source[t.pos.lineno - 1][t.pos.column - 1] != ':' &&
40
- source[t.pos.lineno - 1] !~ /^\s*def.*(?:\(.*\)|;).*end\s*$/
41
- end
24
+ def count_comments?
25
+ MethodLength.config['CountComments']
42
26
  end
43
27
 
44
- # Find the matching 'end' based on the indentation of 'def'
45
- # Fall back to last token if indentation cannot be matched
46
- def def_and_end_lines(tokens, t_ix)
47
- t1 = tokens[t_ix]
48
- t2 = tokens[(t_ix + 1)..-1].find(-> { tokens[-1] }) do |t|
49
- [t1.pos.column, t.type, t.text] == [t.pos.column, :on_kw, 'end']
28
+ private
29
+
30
+ def check(node)
31
+ method_length = calculate_length(node.loc.expression.source)
32
+
33
+ if method_length > max_length
34
+ message = sprintf(MSG, method_length, max_length)
35
+ add_offence(:convention, node.loc.keyword.line, message)
50
36
  end
51
- [t1.pos.lineno, t2.pos.lineno]
37
+ end
38
+
39
+ def calculate_length(source)
40
+ lines = source.lines.to_a[1...-1]
41
+
42
+ return 0 unless lines
43
+
44
+ lines.map!(&:strip).reject!(&:empty?)
45
+
46
+ lines.reject! { |line| line =~ /^\s*#/ } unless count_comments?
47
+
48
+ lines.size
52
49
  end
53
50
  end
54
51
  end