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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +32 -1
- data/README.md +28 -3
- data/config/default.yml +14 -12
- data/config/disabled.yml +1 -1
- data/config/enabled.yml +190 -118
- data/lib/rubocop.rb +9 -1
- data/lib/rubocop/cli.rb +49 -13
- data/lib/rubocop/config.rb +5 -5
- data/lib/rubocop/cop/cop.rb +34 -1
- data/lib/rubocop/cop/lint/parentheses_as_grouped_expression.rb +47 -0
- data/lib/rubocop/cop/lint/rescue_exception.rb +1 -4
- data/lib/rubocop/cop/lint/useless_assignment.rb +39 -11
- data/lib/rubocop/cop/lint/useless_comparison.rb +2 -4
- data/lib/rubocop/cop/rails/has_and_belongs_to_many.rb +20 -0
- data/lib/rubocop/cop/rails/read_attribute.rb +28 -0
- data/lib/rubocop/cop/style/access_control.rb +12 -1
- data/lib/rubocop/cop/style/attr.rb +7 -0
- data/lib/rubocop/cop/style/collection_methods.rb +13 -1
- data/lib/rubocop/cop/style/constant_name.rb +1 -1
- data/lib/rubocop/cop/style/def_parentheses.rb +18 -0
- data/lib/rubocop/cop/style/documentation.rb +1 -1
- data/lib/rubocop/cop/style/empty_literal.rb +14 -0
- data/lib/rubocop/cop/style/even_odd.rb +56 -0
- data/lib/rubocop/cop/style/favor_modifier.rb +2 -2
- data/lib/rubocop/cop/style/hash_methods.rb +40 -0
- data/lib/rubocop/cop/style/indentation_width.rb +148 -0
- data/lib/rubocop/cop/style/method_and_variable_snake_case.rb +40 -25
- data/lib/rubocop/cop/style/method_call_parentheses.rb +8 -0
- data/lib/rubocop/cop/style/multiline_if_then.rb +1 -1
- data/lib/rubocop/cop/style/nil_comparison.rb +38 -0
- data/lib/rubocop/cop/style/signal_exception.rb +11 -0
- data/lib/rubocop/cop/style/space_after_method_name.rb +34 -0
- data/lib/rubocop/cop/util.rb +17 -0
- data/lib/rubocop/formatter/emacs_style_formatter.rb +2 -2
- data/lib/rubocop/formatter/file_list_formatter.rb +3 -2
- data/lib/rubocop/formatter/formatter_set.rb +3 -11
- data/lib/rubocop/formatter/offence_count_formatter.rb +50 -0
- data/lib/rubocop/formatter/progress_formatter.rb +0 -2
- data/lib/rubocop/formatter/simple_text_formatter.rb +1 -6
- data/lib/rubocop/version.rb +1 -1
- data/spec/project_spec.rb +7 -0
- data/spec/rubocop/cli_spec.rb +119 -57
- data/spec/rubocop/config_spec.rb +23 -17
- data/spec/rubocop/cop/commissioner_spec.rb +8 -8
- data/spec/rubocop/cop/cop_spec.rb +80 -0
- data/spec/rubocop/cop/lint/parentheses_as_grouped_expression_spec.rb +63 -0
- data/spec/rubocop/cop/lint/useless_assignment_spec.rb +59 -0
- data/spec/rubocop/cop/rails/has_and_belongs_to_many_spec.rb +19 -0
- data/spec/rubocop/cop/rails/read_attribute_spec.rb +19 -0
- data/spec/rubocop/cop/rails/validation_spec.rb +5 -5
- data/spec/rubocop/cop/style/access_control_spec.rb +28 -0
- data/spec/rubocop/cop/style/attr_spec.rb +6 -1
- data/spec/rubocop/cop/style/collection_methods_spec.rb +5 -0
- data/spec/rubocop/cop/style/constant_name_spec.rb +9 -0
- data/spec/rubocop/cop/style/def_with_parentheses_spec.rb +14 -9
- data/spec/rubocop/cop/style/def_without_parentheses_spec.rb +12 -7
- data/spec/rubocop/cop/style/empty_literal_spec.rb +42 -27
- data/spec/rubocop/cop/style/even_odd_spec.rb +47 -0
- data/spec/rubocop/cop/style/favor_modifier_spec.rb +15 -14
- data/spec/rubocop/cop/style/hash_methods_spec.rb +51 -0
- data/spec/rubocop/cop/style/indentation_width_spec.rb +390 -0
- data/spec/rubocop/cop/style/method_and_variable_snake_case_spec.rb +58 -50
- data/spec/rubocop/cop/style/method_call_parentheses_spec.rb +6 -1
- data/spec/rubocop/cop/style/nil_comparison_spec.rb +31 -0
- data/spec/rubocop/cop/style/signal_exception_spec.rb +28 -0
- data/spec/rubocop/cop/style/space_after_method_name_spec.rb +61 -0
- data/spec/rubocop/formatter/emacs_style_formatter_spec.rb +9 -2
- data/spec/rubocop/formatter/file_list_formatter_spec.rb +3 -3
- data/spec/rubocop/formatter/offence_count_formatter_spec.rb +52 -0
- data/spec/rubocop/formatter/progress_formatter_spec.rb +70 -84
- data/spec/rubocop/source_parser_spec.rb +1 -1
- metadata +29 -5
- data/lib/rubocop/cop/style/line_continuation.rb +0 -27
- 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
|
-
|
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
|
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
|
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.
|
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.
|
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
|