rubocop 0.11.1 → 0.12.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 (75) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +32 -1
  3. data/README.md +28 -3
  4. data/config/default.yml +14 -12
  5. data/config/disabled.yml +1 -1
  6. data/config/enabled.yml +190 -118
  7. data/lib/rubocop.rb +9 -1
  8. data/lib/rubocop/cli.rb +49 -13
  9. data/lib/rubocop/config.rb +5 -5
  10. data/lib/rubocop/cop/cop.rb +34 -1
  11. data/lib/rubocop/cop/lint/parentheses_as_grouped_expression.rb +47 -0
  12. data/lib/rubocop/cop/lint/rescue_exception.rb +1 -4
  13. data/lib/rubocop/cop/lint/useless_assignment.rb +39 -11
  14. data/lib/rubocop/cop/lint/useless_comparison.rb +2 -4
  15. data/lib/rubocop/cop/rails/has_and_belongs_to_many.rb +20 -0
  16. data/lib/rubocop/cop/rails/read_attribute.rb +28 -0
  17. data/lib/rubocop/cop/style/access_control.rb +12 -1
  18. data/lib/rubocop/cop/style/attr.rb +7 -0
  19. data/lib/rubocop/cop/style/collection_methods.rb +13 -1
  20. data/lib/rubocop/cop/style/constant_name.rb +1 -1
  21. data/lib/rubocop/cop/style/def_parentheses.rb +18 -0
  22. data/lib/rubocop/cop/style/documentation.rb +1 -1
  23. data/lib/rubocop/cop/style/empty_literal.rb +14 -0
  24. data/lib/rubocop/cop/style/even_odd.rb +56 -0
  25. data/lib/rubocop/cop/style/favor_modifier.rb +2 -2
  26. data/lib/rubocop/cop/style/hash_methods.rb +40 -0
  27. data/lib/rubocop/cop/style/indentation_width.rb +148 -0
  28. data/lib/rubocop/cop/style/method_and_variable_snake_case.rb +40 -25
  29. data/lib/rubocop/cop/style/method_call_parentheses.rb +8 -0
  30. data/lib/rubocop/cop/style/multiline_if_then.rb +1 -1
  31. data/lib/rubocop/cop/style/nil_comparison.rb +38 -0
  32. data/lib/rubocop/cop/style/signal_exception.rb +11 -0
  33. data/lib/rubocop/cop/style/space_after_method_name.rb +34 -0
  34. data/lib/rubocop/cop/util.rb +17 -0
  35. data/lib/rubocop/formatter/emacs_style_formatter.rb +2 -2
  36. data/lib/rubocop/formatter/file_list_formatter.rb +3 -2
  37. data/lib/rubocop/formatter/formatter_set.rb +3 -11
  38. data/lib/rubocop/formatter/offence_count_formatter.rb +50 -0
  39. data/lib/rubocop/formatter/progress_formatter.rb +0 -2
  40. data/lib/rubocop/formatter/simple_text_formatter.rb +1 -6
  41. data/lib/rubocop/version.rb +1 -1
  42. data/spec/project_spec.rb +7 -0
  43. data/spec/rubocop/cli_spec.rb +119 -57
  44. data/spec/rubocop/config_spec.rb +23 -17
  45. data/spec/rubocop/cop/commissioner_spec.rb +8 -8
  46. data/spec/rubocop/cop/cop_spec.rb +80 -0
  47. data/spec/rubocop/cop/lint/parentheses_as_grouped_expression_spec.rb +63 -0
  48. data/spec/rubocop/cop/lint/useless_assignment_spec.rb +59 -0
  49. data/spec/rubocop/cop/rails/has_and_belongs_to_many_spec.rb +19 -0
  50. data/spec/rubocop/cop/rails/read_attribute_spec.rb +19 -0
  51. data/spec/rubocop/cop/rails/validation_spec.rb +5 -5
  52. data/spec/rubocop/cop/style/access_control_spec.rb +28 -0
  53. data/spec/rubocop/cop/style/attr_spec.rb +6 -1
  54. data/spec/rubocop/cop/style/collection_methods_spec.rb +5 -0
  55. data/spec/rubocop/cop/style/constant_name_spec.rb +9 -0
  56. data/spec/rubocop/cop/style/def_with_parentheses_spec.rb +14 -9
  57. data/spec/rubocop/cop/style/def_without_parentheses_spec.rb +12 -7
  58. data/spec/rubocop/cop/style/empty_literal_spec.rb +42 -27
  59. data/spec/rubocop/cop/style/even_odd_spec.rb +47 -0
  60. data/spec/rubocop/cop/style/favor_modifier_spec.rb +15 -14
  61. data/spec/rubocop/cop/style/hash_methods_spec.rb +51 -0
  62. data/spec/rubocop/cop/style/indentation_width_spec.rb +390 -0
  63. data/spec/rubocop/cop/style/method_and_variable_snake_case_spec.rb +58 -50
  64. data/spec/rubocop/cop/style/method_call_parentheses_spec.rb +6 -1
  65. data/spec/rubocop/cop/style/nil_comparison_spec.rb +31 -0
  66. data/spec/rubocop/cop/style/signal_exception_spec.rb +28 -0
  67. data/spec/rubocop/cop/style/space_after_method_name_spec.rb +61 -0
  68. data/spec/rubocop/formatter/emacs_style_formatter_spec.rb +9 -2
  69. data/spec/rubocop/formatter/file_list_formatter_spec.rb +3 -3
  70. data/spec/rubocop/formatter/offence_count_formatter_spec.rb +52 -0
  71. data/spec/rubocop/formatter/progress_formatter_spec.rb +70 -84
  72. data/spec/rubocop/source_parser_spec.rb +1 -1
  73. metadata +29 -5
  74. data/lib/rubocop/cop/style/line_continuation.rb +0 -27
  75. data/spec/rubocop/cop/style/line_continuation_spec.rb +0 -26
@@ -0,0 +1,28 @@
1
+ # encoding: utf-8
2
+
3
+ module Rubocop
4
+ module Cop
5
+ module Rails
6
+ # This cop checks for the use of the read_attribute method.
7
+ #
8
+ # @example
9
+ #
10
+ # # bad
11
+ # read_attributed(:attr)
12
+ #
13
+ # # good
14
+ # self[:attr]
15
+ class ReadAttribute < Cop
16
+ MSG = 'Prefer self[:attribute] over read_attribute(:attribute).'
17
+
18
+ def on_send(node)
19
+ receiver, method_name, *_args = *node
20
+
21
+ if receiver.nil? && method_name == :read_attribute
22
+ add_offence(:convention, node.loc.selector, MSG)
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
@@ -17,7 +17,11 @@ module Rubocop
17
17
  def investigate(processed_source)
18
18
  ast = processed_source.ast
19
19
  return unless ast
20
- on_node([:class, :module, :sclass], ast) do |class_node|
20
+ on_node([:class, :module, :sclass, :block], ast) do |class_node|
21
+ if class_node.type == :block && !class_constructor?(class_node)
22
+ next
23
+ end
24
+
21
25
  class_start_col = class_node.loc.expression.column
22
26
 
23
27
  # we'll have to walk all class children nodes
@@ -50,6 +54,13 @@ module Rubocop
50
54
 
51
55
  private
52
56
 
57
+ def class_constructor?(block_node)
58
+ send_node = block_node.children.first
59
+ receiver_node, method_name, *_ = *send_node
60
+ return false unless method_name == :new
61
+ %w(Class Module).include?(Util.const_name(receiver_node))
62
+ end
63
+
53
64
  def modifier_node?(node)
54
65
  [PRIVATE_NODE, PROTECTED_NODE, PUBLIC_NODE].include?(node)
55
66
  end
@@ -10,6 +10,13 @@ module Rubocop
10
10
  def on_send(node)
11
11
  if command?(:attr, node)
12
12
  add_offence(:convention, node.loc.selector, MSG)
13
+ do_autocorrect(node)
14
+ end
15
+ end
16
+
17
+ def autocorrect_action(node)
18
+ @corrections << lambda do |corrector|
19
+ corrector.replace(node.loc.selector, 'attr_reader')
13
20
  end
14
21
  end
15
22
  end
@@ -32,6 +32,13 @@ module Rubocop
32
32
  end
33
33
  end
34
34
 
35
+ def autocorrect_action(node)
36
+ @corrections << lambda do |corrector|
37
+ corrector.replace(node.loc.selector,
38
+ preferred_method(node.loc.selector.source))
39
+ end
40
+ end
41
+
35
42
  private
36
43
 
37
44
  def check_method_node(node)
@@ -42,11 +49,16 @@ module Rubocop
42
49
  :convention,
43
50
  node.loc.selector,
44
51
  sprintf(MSG,
45
- self.class.preferred_methods[method_name],
52
+ preferred_method(method_name),
46
53
  method_name)
47
54
  )
55
+ do_autocorrect(node)
48
56
  end
49
57
  end
58
+
59
+ def preferred_method(method)
60
+ self.class.preferred_methods[method.to_sym]
61
+ end
50
62
  end
51
63
  end
52
64
  end
@@ -17,7 +17,7 @@ module Rubocop
17
17
 
18
18
  # We cannot know the result of method calls line
19
19
  # NewClass = something_that_returns_a_class
20
- unless value && value.type == :send
20
+ unless value && [:send, :block].include?(value.type)
21
21
  if const_name !~ SNAKE_CASE
22
22
  add_offence(:convention, node.loc.name, MSG)
23
23
  end
@@ -19,6 +19,7 @@ module Rubocop
19
19
  _, args = *node
20
20
  if args.children == [] && args.loc.begin
21
21
  add_offence(:convention, args.loc.begin, MSG)
22
+ do_autocorrect(args)
22
23
  end
23
24
  end
24
25
 
@@ -31,6 +32,14 @@ module Rubocop
31
32
  _, _, args = *node
32
33
  if args.children == [] && args.loc.begin
33
34
  add_offence(:convention, args.loc.begin, MSG)
35
+ do_autocorrect(args)
36
+ end
37
+ end
38
+
39
+ def autocorrect_action(node)
40
+ @corrections << lambda do |corrector|
41
+ corrector.remove(node.loc.begin)
42
+ corrector.remove(node.loc.end)
34
43
  end
35
44
  end
36
45
  end
@@ -46,6 +55,7 @@ module Rubocop
46
55
 
47
56
  if args.children.size > 0 && args.loc.begin.nil?
48
57
  add_offence(:convention, args.loc.expression, MSG)
58
+ do_autocorrect(args)
49
59
  end
50
60
  end
51
61
 
@@ -54,6 +64,14 @@ module Rubocop
54
64
 
55
65
  if args.children.size > 0 && args.loc.begin.nil?
56
66
  add_offence(:convention, args.loc.expression, MSG)
67
+ do_autocorrect(args)
68
+ end
69
+ end
70
+
71
+ def autocorrect_action(node)
72
+ @corrections << lambda do |corrector|
73
+ corrector.insert_before(node.loc.expression, '(')
74
+ corrector.insert_after(node.loc.expression, ')')
57
75
  end
58
76
  end
59
77
  end
@@ -29,7 +29,7 @@ module Rubocop
29
29
  on_node(:class, ast) do |node|
30
30
  _name, _superclass, body = *node
31
31
 
32
- if body != nil && ast_with_comments[node].empty?
32
+ if body && ast_with_comments[node].empty?
33
33
  add_offence(:convention, node.loc.keyword, format(MSG, 'class'))
34
34
  end
35
35
  end
@@ -36,19 +36,33 @@ module Rubocop
36
36
  add_offence(:convention,
37
37
  node.loc.expression,
38
38
  ARR_MSG)
39
+ do_autocorrect(node)
39
40
  when HASH_NODE
40
41
  add_offence(:convention,
41
42
  node.loc.expression,
42
43
  HASH_MSG)
44
+ do_autocorrect(node)
43
45
  when STR_NODE
44
46
  add_offence(:convention,
45
47
  node.loc.expression,
46
48
  STR_MSG)
49
+ do_autocorrect(node)
47
50
  end
48
51
  end
49
52
 
50
53
  # TODO: Check block contents as well.
51
54
  alias_method :on_block, :ignore_node
55
+
56
+ def autocorrect_action(node)
57
+ @corrections << lambda do |corrector|
58
+ name = case node
59
+ when ARRAY_NODE then '[]'
60
+ when HASH_NODE then '{}'
61
+ when STR_NODE then "''"
62
+ end
63
+ corrector.replace(node.loc.expression, name)
64
+ end
65
+ end
52
66
  end
53
67
  end
54
68
  end
@@ -0,0 +1,56 @@
1
+ # encoding: utf-8
2
+
3
+ module Rubocop
4
+ module Cop
5
+ module Style
6
+ # This cop checks for places where Fixnum#even? or Fixnum#odd?
7
+ # should have been used.
8
+ #
9
+ # @example
10
+ #
11
+ # # bad
12
+ # if x % 2 == 0
13
+ #
14
+ # # good
15
+ # if x.even?
16
+ class EvenOdd < Cop
17
+ MSG_EVEN = 'Use Fixnum.even?'
18
+ MSG_ODD = 'Use Fixnum.odd?'
19
+
20
+ ZERO = s(:int, 0)
21
+ ONE = s(:int, 1)
22
+ TWO = s(:int, 2)
23
+
24
+ def on_send(node)
25
+ receiver, method, args = *node
26
+
27
+ return unless method == :==
28
+ return unless div_by_2?(receiver)
29
+
30
+ if args == ZERO
31
+ add_offence(:convention, node.loc.expression, MSG_EVEN)
32
+ elsif args == ONE
33
+ add_offence(:convention, node.loc.expression, MSG_ODD)
34
+ end
35
+ end
36
+
37
+ private
38
+
39
+ def div_by_2?(node)
40
+ return unless node
41
+
42
+ # check for scenarios like (x % 2) == 0
43
+ if node.type == :begin && node.children.size == 1
44
+ node = node.children.first
45
+ end
46
+
47
+ return unless node.type == :send
48
+
49
+ _receiver, method, args = *node
50
+
51
+ method == :% && args == TWO
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
@@ -71,7 +71,7 @@ module Rubocop
71
71
  next if if_else?(node)
72
72
 
73
73
  if check(node, processed_source.comments)
74
- add_offence(:convention, node.loc.expression, error_message)
74
+ add_offence(:convention, node.loc.keyword, error_message)
75
75
  end
76
76
  end
77
77
  end
@@ -108,7 +108,7 @@ module Rubocop
108
108
  next unless node.loc.end
109
109
 
110
110
  if check(node, processed_source.comments)
111
- add_offence(:convention, node.loc.expression, MSG)
111
+ add_offence(:convention, node.loc.keyword, MSG)
112
112
  end
113
113
  end
114
114
  end
@@ -0,0 +1,40 @@
1
+ # encoding: utf-8
2
+
3
+ module Rubocop
4
+ module Cop
5
+ module Style
6
+ # This cop checks for uses of the deprecated methods Hash#has_key?
7
+ # and Hash#has_value?
8
+ class HashMethods < Cop
9
+ MSG = '%s is deprecated in favor of %s.'
10
+
11
+ DEPRECATED_METHODS = [:has_key?, :has_value?]
12
+
13
+ def on_send(node)
14
+ _receiver, method_name, *args = *node
15
+
16
+ if args.size == 1 && DEPRECATED_METHODS.include?(method_name)
17
+ add_offence(:convention,
18
+ node.loc.selector,
19
+ MSG.format(method_name,
20
+ proper_method_name(method_name)))
21
+ do_autocorrect(node)
22
+ end
23
+ end
24
+
25
+ def autocorrect_action(node)
26
+ @corrections << lambda do |corrector|
27
+ corrector.replace(node.loc.selector,
28
+ proper_method_name(node.loc.selector.source))
29
+ end
30
+ end
31
+
32
+ private
33
+
34
+ def proper_method_name(method_name)
35
+ method_name.to_s.sub(/has_/, '')
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,148 @@
1
+ # encoding: utf-8
2
+
3
+ module Rubocop
4
+ module Cop
5
+ module Style
6
+ # This cops checks for indentation that doesn't use two spaces.
7
+ #
8
+ # @example
9
+ #
10
+ # class A
11
+ # def test
12
+ # puts 'hello'
13
+ # end
14
+ # end
15
+ class IndentationWidth < Cop
16
+ CORRECT_INDENTATION = 2
17
+ MSG = "Use #{CORRECT_INDENTATION} (not %d) spaces for indentation."
18
+
19
+ def on_kwbegin(node)
20
+ node.children.each { |c| check_indentation(node.loc.end, c) }
21
+ end
22
+
23
+ def on_block(node)
24
+ _method, _args, body = *node
25
+ # Check body against end/} indentation. Checking against variable
26
+ # assignments, etc, would be more difficult.
27
+ check_indentation(node.loc.end, body)
28
+ end
29
+
30
+ def on_module(node)
31
+ _module_name, *members = *node
32
+ members.each { |m| check_indentation(node.loc.keyword, m) }
33
+ end
34
+
35
+ def on_class(node)
36
+ _class_name, _base_class, *members = *node
37
+ members.each { |m| check_indentation(node.loc.keyword, m) }
38
+ end
39
+
40
+ def on_def(node)
41
+ _method_name, _args, body = *node
42
+ check_indentation(node.loc.keyword, body)
43
+ end
44
+
45
+ def on_defs(node)
46
+ _scope, _method_name, _args, body = *node
47
+ check_indentation(node.loc.keyword, body)
48
+ end
49
+
50
+ def on_for(node)
51
+ _variable, _collection, body = *node
52
+ check_indentation(node.loc.keyword, body)
53
+ end
54
+
55
+ def on_while(node)
56
+ _condition, body = *node
57
+ check_indentation(node.loc.keyword, body)
58
+ end
59
+
60
+ alias_method :on_until, :on_while
61
+
62
+ def on_case(node)
63
+ _condition, *branches = *node
64
+ latest_when = nil
65
+ branches.compact.each do |b|
66
+ if b.type == :when
67
+ _condition, body = *b
68
+ # Check "when" body against "when" keyword indentation.
69
+ check_indentation(b.loc.keyword, body)
70
+ latest_when = b
71
+ else
72
+ # Since it's not easy to get the position of the "else" keyword,
73
+ # we check "else" body against latest "when" keyword indentation.
74
+ check_indentation(latest_when.loc.keyword, b)
75
+ end
76
+ end
77
+ end
78
+
79
+ def on_if(node)
80
+ return if ternary_op?(node)
81
+ return if modifier_if?(node)
82
+
83
+ case node.loc.keyword.source
84
+ when 'if' then _condition, body, else_clause = *node
85
+ when 'unless' then _condition, else_clause, body = *node
86
+ else _condition, body = *node
87
+ end
88
+
89
+ check_if(node, body, else_clause) if body
90
+ end
91
+
92
+ private
93
+
94
+ def check_if(node, body, else_clause)
95
+ return if ternary_op?(node)
96
+ # Don't check if expression is on same line as "then" keyword.
97
+ check_indentation(node.loc.keyword, body)
98
+ if else_clause
99
+ if elsif?(else_clause)
100
+ _condition, inner_body, inner_else_clause = *else_clause
101
+ check_if(else_clause, inner_body, inner_else_clause)
102
+ else
103
+ check_indentation(node.loc.keyword, else_clause)
104
+ end
105
+ end
106
+ end
107
+
108
+ def modifier_if?(node)
109
+ node.loc.end.nil?
110
+ end
111
+
112
+ def ternary_op?(node)
113
+ node.loc.respond_to?(:question)
114
+ end
115
+
116
+ def elsif?(node)
117
+ node.loc.respond_to?(:keyword) && node.loc.keyword &&
118
+ node.loc.keyword.is?('elsif')
119
+ end
120
+
121
+ def check_indentation(base_loc, body_node)
122
+ return unless body_node
123
+ return if body_node.loc.line == base_loc.line
124
+ # Don't check indentation if the line doesn't start with the body.
125
+ # For example lines like "else do_something".
126
+ first_char_pos_on_line = body_node.loc.expression.source_line =~ /\S/
127
+ return unless body_node.loc.column == first_char_pos_on_line
128
+
129
+ indentation = body_node.loc.column - base_loc.column
130
+ if indentation != CORRECT_INDENTATION
131
+ expr = body_node.loc.expression
132
+ begin_pos, end_pos = if indentation >= 0
133
+ [expr.begin_pos - indentation,
134
+ expr.begin_pos]
135
+ else
136
+ [expr.begin_pos,
137
+ expr.begin_pos - indentation]
138
+ end
139
+ add_offence(:convention,
140
+ Parser::Source::Range.new(expr.source_buffer,
141
+ begin_pos, end_pos),
142
+ sprintf(MSG, indentation))
143
+ end
144
+ end
145
+ end
146
+ end
147
+ end
148
+ end