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.

Files changed (79) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +35 -0
  3. data/CONTRIBUTING.md +2 -0
  4. data/README.md +102 -5
  5. data/config/default.yml +31 -3
  6. data/config/enabled.yml +21 -3
  7. data/lib/rubocop.rb +5 -0
  8. data/lib/rubocop/cli.rb +27 -7
  9. data/lib/rubocop/config.rb +21 -2
  10. data/lib/rubocop/config_store.rb +4 -1
  11. data/lib/rubocop/cop/commissioner.rb +2 -4
  12. data/lib/rubocop/cop/cop.rb +8 -8
  13. data/lib/rubocop/cop/lint/assignment_in_condition.rb +3 -0
  14. data/lib/rubocop/cop/lint/block_alignment.rb +10 -20
  15. data/lib/rubocop/cop/lint/useless_assignment.rb +63 -0
  16. data/lib/rubocop/cop/lint/useless_comparison.rb +30 -0
  17. data/lib/rubocop/cop/style/align_parameters.rb +23 -13
  18. data/lib/rubocop/cop/style/and_or.rb +13 -1
  19. data/lib/rubocop/cop/style/blocks.rb +35 -0
  20. data/lib/rubocop/cop/style/character_literal.rb +1 -1
  21. data/lib/rubocop/cop/style/comment_annotation.rb +20 -5
  22. data/lib/rubocop/cop/style/dot_position.rb +7 -1
  23. data/lib/rubocop/cop/style/empty_line_between_defs.rb +1 -1
  24. data/lib/rubocop/cop/style/favor_modifier.rb +4 -4
  25. data/lib/rubocop/cop/style/module_function.rb +34 -0
  26. data/lib/rubocop/cop/style/multiline_if_then.rb +7 -9
  27. data/lib/rubocop/cop/style/redundant_begin.rb +7 -7
  28. data/lib/rubocop/cop/style/redundant_return.rb +9 -11
  29. data/lib/rubocop/cop/style/redundant_self.rb +5 -1
  30. data/lib/rubocop/cop/style/regexp_literal.rb +2 -1
  31. data/lib/rubocop/cop/style/signal_exception.rb +40 -0
  32. data/lib/rubocop/cop/style/string_literals.rb +2 -2
  33. data/lib/rubocop/cop/style/symbol_name.rb +11 -0
  34. data/lib/rubocop/cop/style/trivial_accessors.rb +22 -10
  35. data/lib/rubocop/cop/variable_inspector.rb +92 -71
  36. data/lib/rubocop/formatter/clang_style_formatter.rb +8 -3
  37. data/lib/rubocop/formatter/disabled_config_formatter.rb +32 -0
  38. data/lib/rubocop/formatter/formatter_set.rb +7 -4
  39. data/lib/rubocop/target_finder.rb +3 -4
  40. data/lib/rubocop/version.rb +1 -1
  41. data/rubocop.gemspec +1 -1
  42. data/spec/rubocop/cli_spec.rb +90 -1
  43. data/spec/rubocop/cops/commissioner_spec.rb +1 -1
  44. data/spec/rubocop/cops/lint/assignment_in_condition_spec.rb +6 -0
  45. data/spec/rubocop/cops/lint/block_alignment_spec.rb +16 -4
  46. data/spec/rubocop/cops/lint/empty_ensure_spec.rb +1 -1
  47. data/spec/rubocop/cops/lint/ensure_return_spec.rb +1 -1
  48. data/spec/rubocop/cops/lint/shadowing_outer_local_variable_spec.rb +4 -4
  49. data/spec/rubocop/cops/lint/unused_local_variable_spec.rb +49 -13
  50. data/spec/rubocop/cops/lint/useless_assignment_spec.rb +62 -0
  51. data/spec/rubocop/cops/lint/useless_comparison_spec.rb +31 -0
  52. data/spec/rubocop/cops/style/align_parameters_spec.rb +9 -0
  53. data/spec/rubocop/cops/style/and_or_spec.rb +12 -0
  54. data/spec/rubocop/cops/style/avoid_global_vars_spec.rb +1 -1
  55. data/spec/rubocop/cops/style/blocks_spec.rb +57 -14
  56. data/spec/rubocop/cops/style/character_literal_spec.rb +2 -2
  57. data/spec/rubocop/cops/style/comment_annotation_spec.rb +32 -4
  58. data/spec/rubocop/cops/style/dot_position_spec.rb +10 -0
  59. data/spec/rubocop/cops/style/empty_line_between_defs_spec.rb +12 -0
  60. data/spec/rubocop/cops/style/end_of_line_spec.rb +1 -0
  61. data/spec/rubocop/cops/style/favor_modifier_spec.rb +18 -0
  62. data/spec/rubocop/cops/style/hash_syntax_spec.rb +7 -2
  63. data/spec/rubocop/cops/style/module_function_spec.rb +30 -0
  64. data/spec/rubocop/cops/style/redundant_begin_spec.rb +2 -2
  65. data/spec/rubocop/cops/style/redundant_return_spec.rb +4 -4
  66. data/spec/rubocop/cops/style/redundant_self_spec.rb +36 -2
  67. data/spec/rubocop/cops/style/regexp_literal_spec.rb +1 -0
  68. data/spec/rubocop/cops/style/signal_exception_spec.rb +74 -0
  69. data/spec/rubocop/cops/style/string_literals_spec.rb +10 -0
  70. data/spec/rubocop/cops/style/symbol_name_spec.rb +13 -0
  71. data/spec/rubocop/cops/style/trivial_accessors_spec.rb +28 -3
  72. data/spec/rubocop/cops/variable_inspector_spec.rb +217 -36
  73. data/spec/rubocop/formatter/base_formatter_spec.rb +3 -3
  74. data/spec/rubocop/formatter/clang_style_formatter_spec.rb +19 -0
  75. data/spec/rubocop/formatter/disabled_config_formatter_spec.rb +48 -0
  76. data/spec/rubocop/formatter/formatter_set_spec.rb +1 -1
  77. data/spec/rubocop/processed_source_spec.rb +1 -1
  78. data/spec/spec_helper.rb +18 -13
  79. 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
- # if cond then
12
- # end
10
+ # if cond then
11
+ # end
13
12
  #
14
- # While if statements can contain `then` on the same line:
15
- # @example
13
+ # @example If statements can contain `then` on the same line:
16
14
  #
17
- # if cond then a
18
- # elsif cond then b
19
- # end
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
- # def test
13
- # begin
14
- # ala
15
- # bala
16
- # rescue StandardError => e
17
- # something
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
- # def test
13
- # return something
14
- # end
10
+ # def test
11
+ # return something
12
+ # end
15
13
  #
16
- # def test
17
- # one
18
- # two
19
- # three
20
- # return something
21
- # end
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, :for].include?(method_name)
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[1...-1].scan(/\//).size
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 !~ /('|([^\\]|\A)\\([^\\]|\Z))/ &&
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
- return false unless args.children.size == 0
52
-
53
- return false unless body && body.type == :ivar
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
- exact_name_match? ? names_match?(method_name, body) : true
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
- return false unless args.children.size == 1 &&
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
- method_name != :initialize
72
+ body.children[1] && body.children[1].type == :lvar
73
+ end
65
74
 
66
- exact_name_match? ? names_match?(method_name, body) : true
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.scan_nodes_in_scope(origin_node, &block)
129
+ instance = new(block)
130
+ instance.scan_nodes_in_scope(origin_node)
127
131
  end
128
132
 
129
- def initialize
130
- @node_index = -1
133
+ def initialize(callback)
134
+ @callback = callback
131
135
  end
132
136
 
133
- def scan_nodes_in_scope(origin_node, &block)
134
- origin_node.children.each do |child|
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
- # Do not go into inner scope.
144
- unless SCOPE_TYPES.include?(node.type)
145
- scan_nodes_in_scope(node, &block)
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, index|
173
- if scope_node.type == :block && index == 0 && node.type == :send
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