rubocop 0.10.0 → 0.11.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 +7 -0
- data/CHANGELOG.md +35 -0
- data/CONTRIBUTING.md +2 -0
- data/README.md +102 -5
- data/config/default.yml +31 -3
- data/config/enabled.yml +21 -3
- data/lib/rubocop.rb +5 -0
- data/lib/rubocop/cli.rb +27 -7
- data/lib/rubocop/config.rb +21 -2
- data/lib/rubocop/config_store.rb +4 -1
- data/lib/rubocop/cop/commissioner.rb +2 -4
- data/lib/rubocop/cop/cop.rb +8 -8
- data/lib/rubocop/cop/lint/assignment_in_condition.rb +3 -0
- data/lib/rubocop/cop/lint/block_alignment.rb +10 -20
- data/lib/rubocop/cop/lint/useless_assignment.rb +63 -0
- data/lib/rubocop/cop/lint/useless_comparison.rb +30 -0
- data/lib/rubocop/cop/style/align_parameters.rb +23 -13
- data/lib/rubocop/cop/style/and_or.rb +13 -1
- data/lib/rubocop/cop/style/blocks.rb +35 -0
- data/lib/rubocop/cop/style/character_literal.rb +1 -1
- data/lib/rubocop/cop/style/comment_annotation.rb +20 -5
- data/lib/rubocop/cop/style/dot_position.rb +7 -1
- data/lib/rubocop/cop/style/empty_line_between_defs.rb +1 -1
- data/lib/rubocop/cop/style/favor_modifier.rb +4 -4
- data/lib/rubocop/cop/style/module_function.rb +34 -0
- data/lib/rubocop/cop/style/multiline_if_then.rb +7 -9
- data/lib/rubocop/cop/style/redundant_begin.rb +7 -7
- data/lib/rubocop/cop/style/redundant_return.rb +9 -11
- data/lib/rubocop/cop/style/redundant_self.rb +5 -1
- data/lib/rubocop/cop/style/regexp_literal.rb +2 -1
- data/lib/rubocop/cop/style/signal_exception.rb +40 -0
- data/lib/rubocop/cop/style/string_literals.rb +2 -2
- data/lib/rubocop/cop/style/symbol_name.rb +11 -0
- data/lib/rubocop/cop/style/trivial_accessors.rb +22 -10
- data/lib/rubocop/cop/variable_inspector.rb +92 -71
- data/lib/rubocop/formatter/clang_style_formatter.rb +8 -3
- data/lib/rubocop/formatter/disabled_config_formatter.rb +32 -0
- data/lib/rubocop/formatter/formatter_set.rb +7 -4
- data/lib/rubocop/target_finder.rb +3 -4
- data/lib/rubocop/version.rb +1 -1
- data/rubocop.gemspec +1 -1
- data/spec/rubocop/cli_spec.rb +90 -1
- data/spec/rubocop/cops/commissioner_spec.rb +1 -1
- data/spec/rubocop/cops/lint/assignment_in_condition_spec.rb +6 -0
- data/spec/rubocop/cops/lint/block_alignment_spec.rb +16 -4
- data/spec/rubocop/cops/lint/empty_ensure_spec.rb +1 -1
- data/spec/rubocop/cops/lint/ensure_return_spec.rb +1 -1
- data/spec/rubocop/cops/lint/shadowing_outer_local_variable_spec.rb +4 -4
- data/spec/rubocop/cops/lint/unused_local_variable_spec.rb +49 -13
- data/spec/rubocop/cops/lint/useless_assignment_spec.rb +62 -0
- data/spec/rubocop/cops/lint/useless_comparison_spec.rb +31 -0
- data/spec/rubocop/cops/style/align_parameters_spec.rb +9 -0
- data/spec/rubocop/cops/style/and_or_spec.rb +12 -0
- data/spec/rubocop/cops/style/avoid_global_vars_spec.rb +1 -1
- data/spec/rubocop/cops/style/blocks_spec.rb +57 -14
- data/spec/rubocop/cops/style/character_literal_spec.rb +2 -2
- data/spec/rubocop/cops/style/comment_annotation_spec.rb +32 -4
- data/spec/rubocop/cops/style/dot_position_spec.rb +10 -0
- data/spec/rubocop/cops/style/empty_line_between_defs_spec.rb +12 -0
- data/spec/rubocop/cops/style/end_of_line_spec.rb +1 -0
- data/spec/rubocop/cops/style/favor_modifier_spec.rb +18 -0
- data/spec/rubocop/cops/style/hash_syntax_spec.rb +7 -2
- data/spec/rubocop/cops/style/module_function_spec.rb +30 -0
- data/spec/rubocop/cops/style/redundant_begin_spec.rb +2 -2
- data/spec/rubocop/cops/style/redundant_return_spec.rb +4 -4
- data/spec/rubocop/cops/style/redundant_self_spec.rb +36 -2
- data/spec/rubocop/cops/style/regexp_literal_spec.rb +1 -0
- data/spec/rubocop/cops/style/signal_exception_spec.rb +74 -0
- data/spec/rubocop/cops/style/string_literals_spec.rb +10 -0
- data/spec/rubocop/cops/style/symbol_name_spec.rb +13 -0
- data/spec/rubocop/cops/style/trivial_accessors_spec.rb +28 -3
- data/spec/rubocop/cops/variable_inspector_spec.rb +217 -36
- data/spec/rubocop/formatter/base_formatter_spec.rb +3 -3
- data/spec/rubocop/formatter/clang_style_formatter_spec.rb +19 -0
- data/spec/rubocop/formatter/disabled_config_formatter_spec.rb +48 -0
- data/spec/rubocop/formatter/formatter_set_spec.rb +1 -1
- data/spec/rubocop/processed_source_spec.rb +1 -1
- data/spec/spec_helper.rb +18 -13
- metadata +31 -38
data/lib/rubocop/config_store.rb
CHANGED
@@ -31,7 +31,10 @@ module Rubocop
|
|
31
31
|
dir = File.dirname(file)
|
32
32
|
@path_cache[dir] ||= Config.configuration_file_for(dir)
|
33
33
|
path = @path_cache[dir]
|
34
|
-
@object_cache[path] ||=
|
34
|
+
@object_cache[path] ||= begin
|
35
|
+
print "For #{dir}: " if Config.debug?
|
36
|
+
Config.configuration_from_file(path)
|
37
|
+
end
|
35
38
|
end
|
36
39
|
end
|
37
40
|
end
|
@@ -70,9 +70,7 @@ module Rubocop
|
|
70
70
|
# its own processing.
|
71
71
|
def invoke_cops_callback(processed_source)
|
72
72
|
@cops.each do |cop|
|
73
|
-
if cop.respond_to?(:investigate)
|
74
|
-
cop.investigate(processed_source)
|
75
|
-
end
|
73
|
+
cop.investigate(processed_source) if cop.respond_to?(:investigate)
|
76
74
|
end
|
77
75
|
end
|
78
76
|
|
@@ -80,7 +78,7 @@ module Rubocop
|
|
80
78
|
cop.send callback, node
|
81
79
|
rescue => e
|
82
80
|
if @options[:raise_error]
|
83
|
-
|
81
|
+
raise e
|
84
82
|
else
|
85
83
|
@errors[cop] << e
|
86
84
|
end
|
data/lib/rubocop/cop/cop.rb
CHANGED
@@ -11,16 +11,16 @@ module Rubocop
|
|
11
11
|
# A commissioner object is responsible for traversing the AST and invoking
|
12
12
|
# the specific callbacks on each cop.
|
13
13
|
# If a cop needs to do its own processing of the AST or depends on
|
14
|
-
# something else it should define the
|
14
|
+
# something else it should define the `#investigate` method and do
|
15
15
|
# the processing there.
|
16
16
|
#
|
17
17
|
# @example
|
18
18
|
#
|
19
|
-
#
|
20
|
-
#
|
21
|
-
#
|
19
|
+
# class CustomCop < Cop
|
20
|
+
# def investigate(processed_source)
|
21
|
+
# # Do custom processing
|
22
|
+
# end
|
22
23
|
# end
|
23
|
-
# end
|
24
24
|
class Cop
|
25
25
|
extend AST::Sexp
|
26
26
|
|
@@ -73,11 +73,11 @@ module Rubocop
|
|
73
73
|
@corrections = []
|
74
74
|
end
|
75
75
|
|
76
|
-
def do_autocorrect(node)
|
77
|
-
autocorrect_action(node) if autocorrect
|
76
|
+
def do_autocorrect(node, *args)
|
77
|
+
autocorrect_action(node, *args) if autocorrect
|
78
78
|
end
|
79
79
|
|
80
|
-
def autocorrect_action(node)
|
80
|
+
def autocorrect_action(node, *args)
|
81
81
|
end
|
82
82
|
|
83
83
|
def add_offence(severity, location, message)
|
@@ -26,6 +26,9 @@ module Rubocop
|
|
26
26
|
def check(node)
|
27
27
|
condition, = *node
|
28
28
|
|
29
|
+
# assignments inside blocks are not what we're looking for
|
30
|
+
return if condition.type == :block
|
31
|
+
|
29
32
|
on_node([:begin, *ASGN_NODES], condition) do |asgn_node|
|
30
33
|
# skip safe assignment nodes if safe assignment is allowed
|
31
34
|
return if safe_assignment_allowed? && safe_assignment?(asgn_node)
|
@@ -21,9 +21,7 @@ module Rubocop
|
|
21
21
|
|
22
22
|
def on_block(node)
|
23
23
|
return if already_processed_node?(node)
|
24
|
-
|
25
|
-
start_node = method.loc.expression.source =~ /\n/ ? method : node
|
26
|
-
check_block_alignment(start_node.loc.expression, node.loc)
|
24
|
+
check_block_alignment(node, node)
|
27
25
|
end
|
28
26
|
|
29
27
|
def on_and(node)
|
@@ -31,7 +29,7 @@ module Rubocop
|
|
31
29
|
|
32
30
|
_left, right = *node
|
33
31
|
if right.type == :block
|
34
|
-
check_block_alignment(node
|
32
|
+
check_block_alignment(node, right)
|
35
33
|
@inspected_blocks << right
|
36
34
|
end
|
37
35
|
end
|
@@ -93,7 +91,7 @@ module Rubocop
|
|
93
91
|
return if already_processed_node?(block_node)
|
94
92
|
|
95
93
|
@inspected_blocks << block_node
|
96
|
-
check_block_alignment(begin_node
|
94
|
+
check_block_alignment(begin_node, block_node)
|
97
95
|
end
|
98
96
|
|
99
97
|
def find_block_node(node)
|
@@ -117,24 +115,16 @@ module Rubocop
|
|
117
115
|
end
|
118
116
|
end
|
119
117
|
|
120
|
-
def check_block_alignment(
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
start_source = match.captures[1]
|
126
|
-
else
|
127
|
-
start_line = start_loc.line
|
128
|
-
start_column = start_loc.column
|
129
|
-
start_source = start_loc.source.lines.to_a.first.chomp
|
130
|
-
end
|
131
|
-
end_loc = block_loc.end
|
132
|
-
if block_loc.begin.line != end_loc.line &&
|
133
|
-
start_column != end_loc.column
|
118
|
+
def check_block_alignment(start_node, block_node)
|
119
|
+
start_loc = start_node.loc.expression
|
120
|
+
end_loc = block_node.loc.end
|
121
|
+
if block_node.loc.begin.line != end_loc.line &&
|
122
|
+
start_loc.column != end_loc.column
|
134
123
|
add_offence(:warning,
|
135
124
|
end_loc,
|
136
125
|
sprintf(MSG, end_loc.line, end_loc.column,
|
137
|
-
|
126
|
+
start_loc.source.lines.to_a.first.chomp,
|
127
|
+
start_loc.line, start_loc.column))
|
138
128
|
end
|
139
129
|
end
|
140
130
|
|
@@ -0,0 +1,63 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module Rubocop
|
4
|
+
module Cop
|
5
|
+
module Lint
|
6
|
+
# This cop checks for useless assignment as the final expression
|
7
|
+
# of a function definition.
|
8
|
+
#
|
9
|
+
# @example
|
10
|
+
#
|
11
|
+
# def something
|
12
|
+
# x = 5
|
13
|
+
# end
|
14
|
+
#
|
15
|
+
# def something
|
16
|
+
# x = Something.new
|
17
|
+
# x.attr = 5
|
18
|
+
# end
|
19
|
+
class UselessAssignment < Cop
|
20
|
+
MSG = 'Useless assignment to local variable %s.'
|
21
|
+
|
22
|
+
def on_def(node)
|
23
|
+
_name, _args, body = *node
|
24
|
+
|
25
|
+
check_for_useless_assignment(body)
|
26
|
+
end
|
27
|
+
|
28
|
+
def on_defs(node)
|
29
|
+
_target, _name, _args, body = *node
|
30
|
+
|
31
|
+
check_for_useless_assignment(body)
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
def check_for_useless_assignment(body)
|
37
|
+
return unless body
|
38
|
+
|
39
|
+
if body.type == :begin
|
40
|
+
expression = body.children
|
41
|
+
else
|
42
|
+
expression = body
|
43
|
+
end
|
44
|
+
|
45
|
+
last_expr = expression.is_a?(Array) ? expression.last : expression
|
46
|
+
|
47
|
+
if last_expr && last_expr.type == :lvasgn
|
48
|
+
var_name, = *last_expr
|
49
|
+
add_offence(:warning, last_expr.loc.name, MSG.format(var_name))
|
50
|
+
elsif last_expr && last_expr.type == :send
|
51
|
+
receiver, method, _args = *last_expr
|
52
|
+
|
53
|
+
if receiver && receiver.type == :lvar && method =~ /\w=$/
|
54
|
+
add_offence(:warning,
|
55
|
+
receiver.loc.name,
|
56
|
+
MSG.format(receiver.loc.name.source))
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module Rubocop
|
4
|
+
module Cop
|
5
|
+
module Lint
|
6
|
+
# This cop checks for comparison of something with itself.
|
7
|
+
#
|
8
|
+
# @example
|
9
|
+
#
|
10
|
+
# x.top >= x.top
|
11
|
+
class UselessComparison < Cop
|
12
|
+
MSG = 'Comparison of something with itself detected.'
|
13
|
+
|
14
|
+
OPS = %w(== === != < > <= >= <=>)
|
15
|
+
|
16
|
+
def on_send(node)
|
17
|
+
op = node.loc.selector.source
|
18
|
+
|
19
|
+
if OPS.include?(op)
|
20
|
+
receiver, _method, selector = *node
|
21
|
+
|
22
|
+
if receiver == selector
|
23
|
+
add_offence(:warning, node.loc.selector, MSG)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -12,22 +12,32 @@ module Rubocop
|
|
12
12
|
def on_send(node)
|
13
13
|
_receiver, method, *args = *node
|
14
14
|
|
15
|
-
if method
|
16
|
-
|
17
|
-
prev_arg_line = args.first.loc.expression.line
|
18
|
-
prev_arg_col = first_arg_col
|
15
|
+
return if method == :[]=
|
16
|
+
return if args.size <= 1
|
19
17
|
|
20
|
-
|
21
|
-
cur_arg_line = arg.loc.expression.line
|
22
|
-
cur_arg_col = arg.loc.expression.column
|
18
|
+
first_arg_column = args.first.loc.expression.column
|
23
19
|
|
24
|
-
|
25
|
-
|
26
|
-
add_offence(:convention, arg.loc.expression, MSG)
|
27
|
-
end
|
20
|
+
args.each_cons(2) do |prev, current|
|
21
|
+
current_pos = current.loc.expression
|
28
22
|
|
29
|
-
|
30
|
-
|
23
|
+
if current_pos.line > prev.loc.expression.line &&
|
24
|
+
current_pos.column != first_arg_column
|
25
|
+
add_offence(:convention, current_pos, MSG)
|
26
|
+
do_autocorrect(current, first_arg_column - current_pos.column)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def autocorrect_action(node, column_delta)
|
32
|
+
@corrections << lambda do |corrector|
|
33
|
+
expr = node.loc.expression
|
34
|
+
if column_delta > 0
|
35
|
+
corrector.replace(expr, ' ' * column_delta + expr.source)
|
36
|
+
else
|
37
|
+
range = Parser::Source::Range.new(expr.source_buffer,
|
38
|
+
expr.begin_pos + column_delta,
|
39
|
+
expr.end_pos)
|
40
|
+
corrector.replace(range, expr.source)
|
31
41
|
end
|
32
42
|
end
|
33
43
|
end
|
@@ -32,10 +32,22 @@ module Rubocop
|
|
32
32
|
end
|
33
33
|
|
34
34
|
def autocorrect_action(node)
|
35
|
-
|
35
|
+
correction = lambda do |corrector|
|
36
36
|
replacement = (node.type == :and ? '&&' : '||')
|
37
37
|
corrector.replace(node.loc.operator, replacement)
|
38
38
|
end
|
39
|
+
|
40
|
+
new_source = rewrite_node(node, correction)
|
41
|
+
|
42
|
+
# Make the correction only if it doesn't change the AST.
|
43
|
+
if node == SourceParser.parse(new_source).ast
|
44
|
+
@corrections << correction
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def rewrite_node(node, correction)
|
49
|
+
processed_source = SourceParser.parse(node.loc.expression.source)
|
50
|
+
Corrector.new(processed_source.buffer, [correction]).rewrite
|
39
51
|
end
|
40
52
|
end
|
41
53
|
end
|
@@ -9,7 +9,22 @@ module Rubocop
|
|
9
9
|
MULTI_LINE_MSG = 'Avoid using {...} for multi-line blocks.'
|
10
10
|
SINGLE_LINE_MSG = 'Prefer {...} over do...end for single-line blocks.'
|
11
11
|
|
12
|
+
def on_send(node)
|
13
|
+
_receiver, method_name, *args = *node
|
14
|
+
if args.any?
|
15
|
+
block = get_block(args.last)
|
16
|
+
if block && !has_parentheses?(node) && !operator?(method_name)
|
17
|
+
# If there are no parentheses around the arguments, then braces
|
18
|
+
# and do-end have different meaning due to how they bind, so we
|
19
|
+
# allow either.
|
20
|
+
ignore_node(block)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
12
25
|
def on_block(node)
|
26
|
+
return if ignored_node?(node)
|
27
|
+
|
13
28
|
block_length = Util.block_length(node)
|
14
29
|
block_begin = node.loc.begin.source
|
15
30
|
|
@@ -19,6 +34,26 @@ module Rubocop
|
|
19
34
|
add_offence(:convention, node.loc.begin, SINGLE_LINE_MSG)
|
20
35
|
end
|
21
36
|
end
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
def get_block(node)
|
41
|
+
case node.type
|
42
|
+
when :block
|
43
|
+
node
|
44
|
+
when :send
|
45
|
+
receiver, _method_name, *_args = *node
|
46
|
+
get_block(receiver) if receiver
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def has_parentheses?(send_node)
|
51
|
+
send_node.loc.begin
|
52
|
+
end
|
53
|
+
|
54
|
+
def operator?(method_name)
|
55
|
+
method_name =~ /^\W/
|
56
|
+
end
|
22
57
|
end
|
23
58
|
end
|
24
59
|
end
|
@@ -10,7 +10,7 @@ module Rubocop
|
|
10
10
|
def on_str(node)
|
11
11
|
# Constants like __FILE__ are handled as strings,
|
12
12
|
# but don't respond to begin.
|
13
|
-
return unless node.loc.respond_to?(:begin)
|
13
|
+
return unless node.loc.respond_to?(:begin) && node.loc.begin
|
14
14
|
return if part_of_ignored_node?(node)
|
15
15
|
|
16
16
|
# we don't register an offence for things like ?\C-\M-d
|
@@ -8,7 +8,6 @@ module Rubocop
|
|
8
8
|
class CommentAnnotation < Cop
|
9
9
|
MSG = 'Annotation keywords shall be all upper case, followed by a ' +
|
10
10
|
'colon and a space, then a note describing the problem.'
|
11
|
-
KEYWORDS = %w(TODO FIXME OPTIMIZE HACK REVIEW)
|
12
11
|
|
13
12
|
def investigate(processed_source)
|
14
13
|
processed_source.comments.each do |comment|
|
@@ -17,7 +16,7 @@ module Rubocop
|
|
17
16
|
margin, first_word, colon, space, note = *match.captures
|
18
17
|
if annotation?(first_word, colon, space, note) &&
|
19
18
|
!correct_annotation?(first_word, colon, space, note)
|
20
|
-
start = comment.loc.begin_pos + margin.length
|
19
|
+
start = comment.loc.expression.begin_pos + margin.length
|
21
20
|
length = first_word.length + (colon || '').length
|
22
21
|
range = Parser::Source::Range.new(processed_source.buffer,
|
23
22
|
start,
|
@@ -28,15 +27,31 @@ module Rubocop
|
|
28
27
|
end
|
29
28
|
end
|
30
29
|
|
30
|
+
def self.keywords
|
31
|
+
CommentAnnotation.config['Keywords']
|
32
|
+
end
|
33
|
+
|
31
34
|
private
|
32
35
|
|
33
36
|
def annotation?(first_word, colon, space, note)
|
34
|
-
|
37
|
+
keyword_appearance?(first_word, colon, space) &&
|
38
|
+
!just_first_word_of_sentence?(first_word, colon, space, note)
|
39
|
+
end
|
40
|
+
|
41
|
+
def keyword_appearance?(first_word, colon, space)
|
42
|
+
keyword?(first_word.upcase) && (colon || space)
|
43
|
+
end
|
44
|
+
|
45
|
+
def just_first_word_of_sentence?(first_word, colon, space, note)
|
46
|
+
first_word == first_word.capitalize && !colon && space && note
|
35
47
|
end
|
36
48
|
|
37
49
|
def correct_annotation?(first_word, colon, space, note)
|
38
|
-
|
39
|
-
|
50
|
+
keyword?(first_word) && (colon && space && note || !colon && !note)
|
51
|
+
end
|
52
|
+
|
53
|
+
def keyword?(word)
|
54
|
+
CommentAnnotation.keywords.include?(word)
|
40
55
|
end
|
41
56
|
end
|
42
57
|
end
|
@@ -19,7 +19,13 @@ module Rubocop
|
|
19
19
|
|
20
20
|
def proper_dot_position?(node)
|
21
21
|
dot_line = node.loc.dot.line
|
22
|
-
|
22
|
+
|
23
|
+
if node.loc.selector
|
24
|
+
selector_line = node.loc.selector.line
|
25
|
+
else
|
26
|
+
# l.(1) has no selector, so we use the opening parenthesis instead
|
27
|
+
selector_line = node.loc.begin.line
|
28
|
+
end
|
23
29
|
|
24
30
|
case DotPosition.config['Style'].downcase
|
25
31
|
when 'leading' then dot_line == selector_line
|
@@ -65,10 +65,10 @@ module Rubocop
|
|
65
65
|
return unless processed_source.ast
|
66
66
|
on_node(:if, processed_source.ast) do |node|
|
67
67
|
# discard ternary ops, if/else and modifier if/unless nodes
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
68
|
+
next if ternary_op?(node)
|
69
|
+
next if modifier_if?(node)
|
70
|
+
next if elsif?(node)
|
71
|
+
next if if_else?(node)
|
72
72
|
|
73
73
|
if check(node, processed_source.comments)
|
74
74
|
add_offence(:convention, node.loc.expression, error_message)
|