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
@@ -0,0 +1,34 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module Rubocop
|
4
|
+
module Cop
|
5
|
+
module Style
|
6
|
+
# This cops checks for use of `extend self` in a module.
|
7
|
+
#
|
8
|
+
# @example
|
9
|
+
#
|
10
|
+
# module Test
|
11
|
+
# extend self
|
12
|
+
#
|
13
|
+
# ...
|
14
|
+
# end
|
15
|
+
class ModuleFunction < Cop
|
16
|
+
MSG = 'Use `module_function` instead of `extend self`.'
|
17
|
+
|
18
|
+
TARGET_NODE = s(:send, nil, :extend, s(:self))
|
19
|
+
|
20
|
+
def on_module(node)
|
21
|
+
_name, body = *node
|
22
|
+
|
23
|
+
if body && body.type == :begin
|
24
|
+
body.children.each do |body_node|
|
25
|
+
if body_node == TARGET_NODE
|
26
|
+
add_offence(:convention, body_node.loc.expression, MSG)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -5,18 +5,16 @@ module Rubocop
|
|
5
5
|
module Style
|
6
6
|
# Checks for uses of the `then` keyword in multi-line if statements.
|
7
7
|
#
|
8
|
-
# This is considered bad practice:
|
9
|
-
# @example
|
8
|
+
# @example This is considered bad practice:
|
10
9
|
#
|
11
|
-
#
|
12
|
-
#
|
10
|
+
# if cond then
|
11
|
+
# end
|
13
12
|
#
|
14
|
-
#
|
15
|
-
# @example
|
13
|
+
# @example If statements can contain `then` on the same line:
|
16
14
|
#
|
17
|
-
#
|
18
|
-
#
|
19
|
-
#
|
15
|
+
# if cond then a
|
16
|
+
# elsif cond then b
|
17
|
+
# end
|
20
18
|
class MultilineIfThen < Cop
|
21
19
|
include IfThenElse
|
22
20
|
|
@@ -9,14 +9,14 @@ module Rubocop
|
|
9
9
|
#
|
10
10
|
# @example
|
11
11
|
#
|
12
|
-
#
|
13
|
-
#
|
14
|
-
#
|
15
|
-
#
|
16
|
-
#
|
17
|
-
#
|
12
|
+
# def test
|
13
|
+
# begin
|
14
|
+
# ala
|
15
|
+
# bala
|
16
|
+
# rescue StandardError => e
|
17
|
+
# something
|
18
|
+
# end
|
18
19
|
# end
|
19
|
-
# end
|
20
20
|
class RedundantBegin < Cop
|
21
21
|
MSG = 'Redundant `begin` block detected.'
|
22
22
|
|
@@ -5,20 +5,18 @@ module Rubocop
|
|
5
5
|
module Style
|
6
6
|
# This cop checks for redundant `return` expressions.
|
7
7
|
#
|
8
|
-
# Currently it checks for code like this:
|
9
|
-
#
|
10
8
|
# @example
|
11
9
|
#
|
12
|
-
#
|
13
|
-
#
|
14
|
-
#
|
10
|
+
# def test
|
11
|
+
# return something
|
12
|
+
# end
|
15
13
|
#
|
16
|
-
#
|
17
|
-
#
|
18
|
-
#
|
19
|
-
#
|
20
|
-
#
|
21
|
-
#
|
14
|
+
# def test
|
15
|
+
# one
|
16
|
+
# two
|
17
|
+
# three
|
18
|
+
# return something
|
19
|
+
# end
|
22
20
|
#
|
23
21
|
# It should be extended to handle methods whose body is if/else
|
24
22
|
# or a case expression with a default branch.
|
@@ -68,7 +68,11 @@ module Rubocop
|
|
68
68
|
end
|
69
69
|
|
70
70
|
def keyword?(method_name)
|
71
|
-
[:class, :
|
71
|
+
[:alias, :and, :begin, :break, :case, :class, :def, :defined, :do,
|
72
|
+
:else, :elsif, :end, :ensure, :false, :for, :if, :in, :module,
|
73
|
+
:next, :nil, :not, :or, :redo, :rescue, :retry, :return, :self,
|
74
|
+
:super, :then, :true, :undef, :unless, :until, :when, :while,
|
75
|
+
:yield].include?(method_name)
|
72
76
|
end
|
73
77
|
|
74
78
|
def allow_self(node)
|
@@ -8,9 +8,10 @@ module Rubocop
|
|
8
8
|
# value of the configuration parameter MaxSlashes.
|
9
9
|
class RegexpLiteral < Cop
|
10
10
|
def on_regexp(node)
|
11
|
-
slashes = node.loc.expression.source
|
11
|
+
slashes = node.loc.expression.source.count('/')
|
12
12
|
max = RegexpLiteral.max_slashes
|
13
13
|
msg = if node.loc.begin.is?('/')
|
14
|
+
slashes -= 2 # subtract delimiters
|
14
15
|
error_message('') if slashes > max
|
15
16
|
else
|
16
17
|
error_message('only ') if slashes <= max
|
@@ -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 `fail` and `raise`.
|
7
|
+
class SignalException < Cop
|
8
|
+
FAIL_MSG = 'Use `fail` instead of `raise` to signal exceptions.'
|
9
|
+
RAISE_MSG = 'Use `raise` instead of `fail` to rethrow exceptions.'
|
10
|
+
|
11
|
+
def on_rescue(node)
|
12
|
+
begin_node, rescue_node = *node
|
13
|
+
|
14
|
+
check_for_raise(begin_node)
|
15
|
+
check_for_fail(rescue_node)
|
16
|
+
end
|
17
|
+
|
18
|
+
def check_for_raise(node)
|
19
|
+
return unless node
|
20
|
+
|
21
|
+
on_node(:send, node, :rescue) do |send_node|
|
22
|
+
if command?(:raise, send_node)
|
23
|
+
add_offence(:convention, send_node.loc.selector, FAIL_MSG)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def check_for_fail(node)
|
29
|
+
return unless node
|
30
|
+
|
31
|
+
on_node(:send, node, :rescue) do |send_node|
|
32
|
+
if command?(:fail, send_node)
|
33
|
+
add_offence(:convention, send_node.loc.selector, RAISE_MSG)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -17,8 +17,8 @@ module Rubocop
|
|
17
17
|
# regex matches IF there is a ' or there is a \\ in the string that
|
18
18
|
# is not preceeded/followed by another \\ (e.g. "\\x34") but not
|
19
19
|
# "\\\\"
|
20
|
-
if node.loc.expression.source !~ /
|
21
|
-
node.loc.begin.is?('"')
|
20
|
+
if node.loc.expression.source !~ /' | (?<! \\) \\{2}* \\ (?! \\)/x &&
|
21
|
+
node.loc.begin && node.loc.begin.is?('"')
|
22
22
|
add_offence(:convention, node.loc.expression, MSG)
|
23
23
|
do_autocorrect(node)
|
24
24
|
end
|
@@ -14,7 +14,18 @@ module Rubocop
|
|
14
14
|
self.class.config['AllowCamelCase']
|
15
15
|
end
|
16
16
|
|
17
|
+
def on_send(node)
|
18
|
+
receiver, method_name, *args = *node
|
19
|
+
# Arguments to Module#private_constant are symbols referring to
|
20
|
+
# existing constants, so they will start with an upper case letter.
|
21
|
+
# We ignore these symbols.
|
22
|
+
if receiver.nil? && method_name == :private_constant
|
23
|
+
args.each { |a| ignore_node(a) }
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
17
27
|
def on_sym(node)
|
28
|
+
return if ignored_node?(node)
|
18
29
|
sym_name = node.to_a[0]
|
19
30
|
return unless sym_name =~ /^[a-zA-Z]/
|
20
31
|
return if sym_name =~ SNAKE_CASE
|
@@ -43,27 +43,39 @@ module Rubocop
|
|
43
43
|
TrivialAccessors.config['AllowPredicates']
|
44
44
|
end
|
45
45
|
|
46
|
+
def whitelist
|
47
|
+
whitelist = TrivialAccessors.config['Whitelist']
|
48
|
+
Array(whitelist).map(&:to_sym) + [:initialize]
|
49
|
+
end
|
50
|
+
|
46
51
|
def predicate?(method_name)
|
47
52
|
method_name[-1] == '?'
|
48
53
|
end
|
49
54
|
|
50
55
|
def trivial_reader?(method_name, args, body)
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
return false if allow_predicates? && predicate?(method_name)
|
56
|
+
looks_like_trivial_reader?(args, body) &&
|
57
|
+
!allowed_method?(method_name, body)
|
58
|
+
end
|
56
59
|
|
57
|
-
|
60
|
+
def looks_like_trivial_reader?(args, body)
|
61
|
+
args.children.size == 0 && body && body.type == :ivar
|
58
62
|
end
|
59
63
|
|
60
64
|
def trivial_writer?(method_name, args, body)
|
61
|
-
|
65
|
+
looks_like_trivial_writer?(args, body) &&
|
66
|
+
!allowed_method?(method_name, body)
|
67
|
+
end
|
68
|
+
|
69
|
+
def looks_like_trivial_writer?(args, body)
|
70
|
+
args.children.size == 1 &&
|
62
71
|
body && body.type == :ivasgn &&
|
63
|
-
body.children[1] && body.children[1].type == :lvar
|
64
|
-
|
72
|
+
body.children[1] && body.children[1].type == :lvar
|
73
|
+
end
|
65
74
|
|
66
|
-
|
75
|
+
def allowed_method?(method_name, body)
|
76
|
+
allow_predicates? && predicate?(method_name) ||
|
77
|
+
whitelist.include?(method_name) ||
|
78
|
+
exact_name_match? && !names_match?(method_name, body)
|
67
79
|
end
|
68
80
|
|
69
81
|
def names_match?(method_name, body)
|
@@ -122,29 +122,105 @@ module Rubocop
|
|
122
122
|
|
123
123
|
# This provides a way to scan all nodes only in current scope.
|
124
124
|
class NodeScanner
|
125
|
+
TWISTED_SCOPE_NODE_TYPES = [:block, :sclass, :defs].freeze
|
126
|
+
POST_CONDITION_LOOP_NODE_TYPES = [:while_post, :until_post].freeze
|
127
|
+
|
125
128
|
def self.scan_nodes_in_scope(origin_node, &block)
|
126
|
-
new
|
129
|
+
instance = new(block)
|
130
|
+
instance.scan_nodes_in_scope(origin_node)
|
127
131
|
end
|
128
132
|
|
129
|
-
def initialize
|
130
|
-
@
|
133
|
+
def initialize(callback)
|
134
|
+
@callback = callback
|
131
135
|
end
|
132
136
|
|
133
|
-
def scan_nodes_in_scope(origin_node,
|
134
|
-
origin_node
|
135
|
-
next unless child.is_a?(Parser::AST::Node)
|
137
|
+
def scan_nodes_in_scope(origin_node, yield_origin_node = false)
|
138
|
+
@callback.call(origin_node) if yield_origin_node
|
136
139
|
|
140
|
+
origin_node.children.each_with_index do |child, index|
|
141
|
+
next unless child.is_a?(Parser::AST::Node)
|
137
142
|
node = child
|
138
|
-
@node_index += 1
|
139
|
-
|
140
|
-
catch(:skip_children) do
|
141
|
-
yield node, @node_index
|
142
143
|
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
end
|
144
|
+
if index == 0 &&
|
145
|
+
TWISTED_SCOPE_NODE_TYPES.include?(origin_node.type)
|
146
|
+
next
|
147
147
|
end
|
148
|
+
|
149
|
+
@callback.call(node)
|
150
|
+
|
151
|
+
scan_children(node)
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
def scan_children(node)
|
156
|
+
case node.type
|
157
|
+
when *POST_CONDITION_LOOP_NODE_TYPES
|
158
|
+
# Loop body nodes need to be scanned first.
|
159
|
+
#
|
160
|
+
# Ruby:
|
161
|
+
# begin
|
162
|
+
# foo = 1
|
163
|
+
# end while foo > 10
|
164
|
+
# puts foo
|
165
|
+
#
|
166
|
+
# AST:
|
167
|
+
# (begin
|
168
|
+
# (while-post
|
169
|
+
# (send
|
170
|
+
# (lvar :foo) :>
|
171
|
+
# (int 10))
|
172
|
+
# (kwbegin
|
173
|
+
# (lvasgn :foo
|
174
|
+
# (int 1))))
|
175
|
+
# (send nil :puts
|
176
|
+
# (lvar :foo)))
|
177
|
+
scan_nodes_in_scope(node.children[1], true)
|
178
|
+
scan_nodes_in_scope(node.children[0], true)
|
179
|
+
when *TWISTED_SCOPE_NODE_TYPES
|
180
|
+
# The variable foo belongs to the top level scope,
|
181
|
+
# but in AST, it's under the block node.
|
182
|
+
#
|
183
|
+
# Ruby:
|
184
|
+
# some_method(foo = 1) do
|
185
|
+
# end
|
186
|
+
# puts foo
|
187
|
+
#
|
188
|
+
# AST:
|
189
|
+
# (begin
|
190
|
+
# (block
|
191
|
+
# (send nil :some_method
|
192
|
+
# (lvasgn :foo
|
193
|
+
# (int 1)))
|
194
|
+
# (args) nil)
|
195
|
+
# (send nil :puts
|
196
|
+
# (lvar :foo)))
|
197
|
+
#
|
198
|
+
# So the the method argument nodes need to be processed
|
199
|
+
# in current scope.
|
200
|
+
#
|
201
|
+
# Same thing.
|
202
|
+
#
|
203
|
+
# Ruby:
|
204
|
+
# instance = Object.new
|
205
|
+
# class << instance
|
206
|
+
# foo = 1
|
207
|
+
# end
|
208
|
+
#
|
209
|
+
# AST:
|
210
|
+
# (begin
|
211
|
+
# (lvasgn :instance
|
212
|
+
# (send
|
213
|
+
# (const nil :Object) :new))
|
214
|
+
# (sclass
|
215
|
+
# (lvar :instance)
|
216
|
+
# (begin
|
217
|
+
# (lvasgn :foo
|
218
|
+
# (int 1))
|
219
|
+
scan_nodes_in_scope(node.children.first, true)
|
220
|
+
when *SCOPE_TYPES
|
221
|
+
# Do not go into inner scope.
|
222
|
+
else
|
223
|
+
scan_nodes_in_scope(node)
|
148
224
|
end
|
149
225
|
end
|
150
226
|
end
|
@@ -169,16 +245,8 @@ module Rubocop
|
|
169
245
|
def inspect_variables_in_scope(scope_node)
|
170
246
|
variable_table.push_scope(scope_node)
|
171
247
|
|
172
|
-
NodeScanner.scan_nodes_in_scope(scope_node) do |node
|
173
|
-
|
174
|
-
# Avoid processing method argument nodes of outer scope
|
175
|
-
# in current block scope.
|
176
|
-
# See #process_node.
|
177
|
-
throw :skip_children
|
178
|
-
elsif [:sclass, :defs].include?(scope_node.type) && index == 0
|
179
|
-
throw :skip_children
|
180
|
-
end
|
181
|
-
|
248
|
+
NodeScanner.scan_nodes_in_scope(scope_node) do |node|
|
249
|
+
# puts "scope:#{variable_table.current_scope_level} node:#{node}"
|
182
250
|
process_node(node)
|
183
251
|
end
|
184
252
|
|
@@ -202,53 +270,6 @@ module Rubocop
|
|
202
270
|
"at #{node.loc.expression}, #{node.inspect}"
|
203
271
|
end
|
204
272
|
variable_entry.used = true
|
205
|
-
when :block
|
206
|
-
# The variable foo belongs to the top level scope,
|
207
|
-
# but in AST, it's under the block node.
|
208
|
-
#
|
209
|
-
# Ruby:
|
210
|
-
# some_method(foo = 1) do
|
211
|
-
# end
|
212
|
-
# puts foo
|
213
|
-
#
|
214
|
-
# AST:
|
215
|
-
# (begin
|
216
|
-
# (block
|
217
|
-
# (send nil :some_method
|
218
|
-
# (lvasgn :foo
|
219
|
-
# (int 1)))
|
220
|
-
# (args) nil)
|
221
|
-
# (send nil :puts
|
222
|
-
# (lvar :foo)))
|
223
|
-
#
|
224
|
-
# So the nodes of the method argument need to be processed
|
225
|
-
# in current scope before dive into the block scope.
|
226
|
-
NodeScanner.scan_nodes_in_scope(node.children.first) do |n|
|
227
|
-
process_node(n)
|
228
|
-
end
|
229
|
-
# Now go into the block scope.
|
230
|
-
inspect_variables_in_scope(node)
|
231
|
-
when :sclass, :defs
|
232
|
-
# Same thing.
|
233
|
-
#
|
234
|
-
# Ruby:
|
235
|
-
# instance = Object.new
|
236
|
-
# class << instance
|
237
|
-
# foo = 1
|
238
|
-
# end
|
239
|
-
#
|
240
|
-
# AST:
|
241
|
-
# (begin
|
242
|
-
# (lvasgn :instance
|
243
|
-
# (send
|
244
|
-
# (const nil :Object) :new))
|
245
|
-
# (sclass
|
246
|
-
# (lvar :instance)
|
247
|
-
# (begin
|
248
|
-
# (lvasgn :foo
|
249
|
-
# (int 1))
|
250
|
-
process_node(node.children.first)
|
251
|
-
inspect_variables_in_scope(node)
|
252
273
|
when *SCOPE_TYPES
|
253
274
|
inspect_variables_in_scope(node)
|
254
275
|
end
|