rubocop 0.18.0 → 0.18.1

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 449eac86969013808cd868da4a3f30a19ed9fee4
4
- data.tar.gz: e90bbbb51afe783b1e6cbaaee26776b215c37b0a
3
+ metadata.gz: 9ea14f3e307dd68df2a7359211b40d0b7bcf4993
4
+ data.tar.gz: a7c9a1f47f05baf47d33ccc0a814d759f2da54c0
5
5
  SHA512:
6
- metadata.gz: 0cbce187b2372414f314b7c79a1046a3951aa32d6056bd0324ee48b85bb3a7f85b48745cb3937d5f52a43b032def66e1b8d8c5c31847ec078b88b8b65ad8bae3
7
- data.tar.gz: 94d82a1c2921ba2dbb630cb0a1a2d69b2df8ad32b9410580c6a61d86868e48b05bd83cba89e3ab8a47c773a4255e22397d985c380c9980708ddbb1883c0eeff5
6
+ metadata.gz: 18b74d226546c2306d3450acc0c3a09e8cef00900b4699b578de51512e7a6f85cb73544dec43882646eb3e8ca8e5ba312f1cea8b9d5e2543238084c556c1b1f9
7
+ data.tar.gz: e4b061fc7821f68ac1ee1f6556c4fb871dea79ad6f32a551d6fad683271b3c44549c6fd7d845e897e9b2015d46ec247bc7348dd8bd62013d46d4d2fabfbc69e3
@@ -2,6 +2,18 @@
2
2
 
3
3
  ## master (unreleased)
4
4
 
5
+ ## 0.18.1 (02/02/2014)
6
+
7
+ ### Bugs fixed
8
+
9
+ * Remove double reporting in `EmptyLinesAroundBody` of empty line inside otherwise empty class/module/method that caused crash in autocorrect. ([@jonas054][])
10
+ * [#779](https://github.com/bbatsov/rubocop/issues/779): Fix a false positive in `LineEndConcatenation`. ([@bbatsov][])
11
+ * [#751](https://github.com/bbatsov/rubocop/issues/751): Fix `Documentation` cop so that a comment followed by an empty line and then a class definition is not considered to be class documentation. ([@jonas054][])
12
+ * [#783](https://github.com/bbatsov/rubocop/issues/783): Fix a false positive in `ParethesesAroundCondition` when the parentheses are actually required. ([@bbatsov][])
13
+ * [#781](https://github.com/bbatsov/rubocop/issues/781): Fix problem with back-and-forth auto-correction in `AccessModifierIndentation`. ([@jonas054][])
14
+ * [#785](https://github.com/bbatsov/rubocop/issues/785): Fix false positive on `%w` arrays in `TrailingComma`. ([@jonas054][])
15
+ * [#782](https://github.com/bbatsov/rubocop/issues/782): Fix false positive in `AlignHash` for single line hashes. ([@jonas054][])
16
+
5
17
  ## 0.18.0 (30/01/2014)
6
18
 
7
19
  ### New features
@@ -30,6 +30,7 @@ require 'rubocop/cop/variable_inspector/reference'
30
30
  require 'rubocop/cop/variable_inspector/scope'
31
31
  require 'rubocop/cop/variable_inspector/variable_table'
32
32
 
33
+ require 'rubocop/cop/mixin/annotation_comment'
33
34
  require 'rubocop/cop/mixin/array_syntax'
34
35
  require 'rubocop/cop/mixin/autocorrect_alignment'
35
36
  require 'rubocop/cop/mixin/check_assignment'
@@ -0,0 +1,37 @@
1
+ # encoding: utf-8
2
+
3
+ module Rubocop
4
+ module Cop
5
+ module Style
6
+ # Common functionality related to annotation comments.
7
+ module AnnotationComment
8
+ private
9
+
10
+ def annotation?(comment)
11
+ _margin, first_word, colon, space, note = split_comment(comment)
12
+ keyword_appearance?(first_word, colon, space) &&
13
+ !just_first_word_of_sentence?(first_word, colon, space, note)
14
+ end
15
+
16
+ def split_comment(comment)
17
+ match = comment.text.match(/^(# ?)([A-Za-z]+)(\s*:)?(\s+)?(\S+)?/)
18
+ return false unless match
19
+ margin, first_word, colon, space, note = *match.captures
20
+ [margin, first_word, colon, space, note]
21
+ end
22
+
23
+ def keyword_appearance?(first_word, colon, space)
24
+ first_word && keyword?(first_word.upcase) && (colon || space)
25
+ end
26
+
27
+ def just_first_word_of_sentence?(first_word, colon, space, note)
28
+ first_word == first_word.capitalize && !colon && space && note
29
+ end
30
+
31
+ def keyword?(word)
32
+ config.for_cop('CommentAnnotation')['Keywords'].include?(word)
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
@@ -6,7 +6,7 @@ module Rubocop
6
6
  # syntax.
7
7
  module ArraySyntax
8
8
  def array_of?(element_type, node)
9
- return false unless node.loc.begin && node.loc.begin.is?('[')
9
+ return false unless square_brackets?(node)
10
10
 
11
11
  array_elems = node.children
12
12
 
@@ -15,6 +15,10 @@ module Rubocop
15
15
 
16
16
  array_elems.all? { |e| e.type == element_type }
17
17
  end
18
+
19
+ def square_brackets?(node)
20
+ node.loc.begin && node.loc.begin.is?('[')
21
+ end
18
22
  end
19
23
  end
20
24
  end
@@ -3,9 +3,8 @@
3
3
  module Rubocop
4
4
  module Cop
5
5
  module Style
6
- # A couple of checks related to the use method visibility modifiers.
7
- # Modifiers should be indented as deeps are method definitions and
8
- # surrounded by blank lines.
6
+ # Modifiers should be indented as deep as method definitions, or as deep
7
+ # as the class/module keyword, depending on configuration.
9
8
  class AccessModifierIndentation < Cop
10
9
  include AutocorrectAlignment
11
10
  include ConfigurableEnforcedStyle
@@ -16,26 +15,24 @@ module Rubocop
16
15
  PROTECTED_NODE = s(:send, nil, :protected)
17
16
  PUBLIC_NODE = s(:send, nil, :public)
18
17
 
19
- def investigate(processed_source)
20
- ast = processed_source.ast
21
- return unless ast
22
- on_node([:class, :module, :sclass, :block], ast) do |class_node|
23
- if class_node.type == :block && !class_constructor?(class_node)
24
- next
25
- end
18
+ def on_class(node)
19
+ _name, _base_class, body = *node
20
+ check_body(body, node)
21
+ end
26
22
 
27
- class_start_col = class_node.loc.expression.column
23
+ def on_sclass(node)
24
+ _name, body = *node
25
+ check_body(body, node)
26
+ end
28
27
 
29
- # we'll have to walk all class children nodes
30
- # except other class/module nodes
31
- class_node.children.compact.each do |node|
32
- on_node(:send, node, [:class, :module, :sclass]) do |send_node|
33
- if self.class.modifier_node?(send_node)
34
- check(send_node, class_start_col)
35
- end
36
- end
37
- end
38
- end
28
+ def on_module(node)
29
+ _name, body = *node
30
+ check_body(body, node)
31
+ end
32
+
33
+ def on_block(node)
34
+ _method, _args, body = *node
35
+ check_body(body, node) if class_constructor?(node)
39
36
  end
40
37
 
41
38
  def self.modifier_node?(node)
@@ -44,7 +41,16 @@ module Rubocop
44
41
 
45
42
  private
46
43
 
47
- def check(send_node, class_start_col)
44
+ def check_body(body, node)
45
+ return if body.nil? # Empty class etc.
46
+
47
+ modifiers = body.children.select { |c| self.class.modifier_node?(c) }
48
+ class_column = node.loc.expression.column
49
+
50
+ modifiers.each { |modifier| check_modifier(modifier, class_column) }
51
+ end
52
+
53
+ def check_modifier(send_node, class_start_col)
48
54
  access_modifier_start_col = send_node.loc.expression.column
49
55
  offset = access_modifier_start_col - class_start_col
50
56
 
@@ -142,10 +142,11 @@ module Rubocop
142
142
  end
143
143
 
144
144
  MSG = 'Align the elements of a hash literal if they span more than ' \
145
- 'one line.'
145
+ 'one line.'
146
146
 
147
147
  def on_hash(node)
148
148
  return if node.children.empty?
149
+ return unless multiline?(node)
149
150
 
150
151
  @alignment_for_hash_rockets ||=
151
152
  new_alignment('EnforcedHashRocketStyle')
@@ -171,6 +172,10 @@ module Rubocop
171
172
 
172
173
  private
173
174
 
175
+ def multiline?(node)
176
+ node.loc.expression.source.include?("\n")
177
+ end
178
+
174
179
  def alignment_for(pair)
175
180
  if pair.loc.operator.is?('=>')
176
181
  @alignment_for_hash_rockets
@@ -6,53 +6,31 @@ module Rubocop
6
6
  # This cop checks that comment annotation keywords are written according
7
7
  # to guidelines.
8
8
  class CommentAnnotation < Cop
9
+ include AnnotationComment
10
+
9
11
  MSG = 'Annotation keywords should be all upper case, followed by a ' \
10
12
  'colon and a space, then a note describing the problem.'
11
13
 
12
14
  def investigate(processed_source)
13
15
  processed_source.comments.each do |comment|
14
- match = comment.text.match(/^(# ?)([A-Za-z]+)(\s*:)?(\s+)?(\S+)?/)
15
- if match
16
- margin, first_word, colon, space, note = *match.captures
17
- if annotation?(first_word, colon, space, note) &&
18
- !correct_annotation?(first_word, colon, space, note)
19
- start = comment.loc.expression.begin_pos + margin.length
20
- length = first_word.length + (colon || '').length
21
- range = Parser::Source::Range.new(processed_source.buffer,
22
- start,
23
- start + length)
24
- add_offence(nil, range)
25
- end
16
+ margin, first_word, colon, space, note = split_comment(comment)
17
+ if annotation?(comment) && !correct_annotation?(first_word, colon,
18
+ space, note)
19
+ start = comment.loc.expression.begin_pos + margin.length
20
+ length = first_word.length + (colon || '').length
21
+ range = Parser::Source::Range.new(processed_source.buffer,
22
+ start,
23
+ start + length)
24
+ add_offence(nil, range)
26
25
  end
27
26
  end
28
27
  end
29
28
 
30
- def keywords
31
- cop_config['Keywords']
32
- end
33
-
34
29
  private
35
30
 
36
- def annotation?(first_word, colon, space, note)
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
47
- end
48
-
49
31
  def correct_annotation?(first_word, colon, space, note)
50
32
  keyword?(first_word) && (colon && space && note || !colon && !note)
51
33
  end
52
-
53
- def keyword?(word)
54
- keywords.include?(word)
55
- end
56
34
  end
57
35
  end
58
36
  end
@@ -8,6 +8,8 @@ module Rubocop
8
8
  # check and so are namespace modules - modules that have nothing in
9
9
  # their bodies except classes or other other modules.
10
10
  class Documentation < Cop
11
+ include AnnotationComment
12
+
11
13
  MSG = 'Missing top-level %s documentation comment.'
12
14
 
13
15
  def investigate(processed_source)
@@ -35,7 +37,7 @@ module Rubocop
35
37
 
36
38
  next if node.type == :class && !body
37
39
  next if namespace?(body)
38
- next unless ast_with_comments[node].empty?
40
+ next if associated_comment?(node, ast_with_comments)
39
41
  add_offence(node, :keyword, format(MSG, node.type.to_s))
40
42
  end
41
43
  end
@@ -54,6 +56,18 @@ module Rubocop
54
56
  false
55
57
  end
56
58
  end
59
+
60
+ # Returns true if the node has a comment on the line above it that
61
+ # isn't an annotation.
62
+ def associated_comment?(node, ast_with_comments)
63
+ return false if ast_with_comments[node].empty?
64
+
65
+ preceding_comment = ast_with_comments[node].last
66
+ distance = node.loc.keyword.line - preceding_comment.loc.line
67
+ return false if distance > 1
68
+
69
+ !annotation?(preceding_comment)
70
+ end
57
71
  end
58
72
  end
59
73
  end
@@ -55,20 +55,17 @@ module Rubocop
55
55
  end
56
56
 
57
57
  def check_source(start_line, end_line)
58
- if processed_source.lines[start_line].empty?
59
- range = source_range(processed_source.buffer,
60
- processed_source[0...start_line],
61
- 0,
62
- 1)
63
- add_offence(range, range, MSG_BEG)
64
- end
58
+ check_line(start_line, MSG_BEG)
59
+ check_line(end_line - 2, MSG_END) unless end_line - 2 == start_line
60
+ end
65
61
 
66
- if processed_source.lines[end_line - 2].empty?
62
+ def check_line(line, msg)
63
+ if processed_source.lines[line].empty?
67
64
  range = source_range(processed_source.buffer,
68
- processed_source[0...(end_line - 2)],
65
+ processed_source[0...line],
69
66
  0,
70
67
  1)
71
- add_offence(range, range, MSG_END)
68
+ add_offence(range, range, msg)
72
69
  end
73
70
  end
74
71
  end
@@ -42,10 +42,12 @@ module Rubocop
42
42
 
43
43
  return false unless arg.type == :str
44
44
 
45
- receiver_line = receiver.loc.expression.line
46
- arg_line = arg.loc.expression.line
45
+ plus_at_line_end?(node.loc.expression.source)
46
+ end
47
47
 
48
- receiver_line != arg_line
48
+ def plus_at_line_end?(expression)
49
+ # check if the first line of the expression ends with a +
50
+ expression =~ /.+\+\s*$/
49
51
  end
50
52
  end
51
53
  end
@@ -28,6 +28,7 @@ module Rubocop
28
28
  cond, _body = *node
29
29
 
30
30
  if cond.type == :begin
31
+ return if parens_required?(node)
31
32
  # allow safe assignment
32
33
  return if safe_assignment?(cond) && safe_assignment_allowed?
33
34
 
@@ -35,6 +36,13 @@ module Rubocop
35
36
  end
36
37
  end
37
38
 
39
+ def parens_required?(node)
40
+ expr = node.loc.expression.source
41
+ keyword = node.loc.keyword.source
42
+
43
+ expr.start_with?("#{keyword}(")
44
+ end
45
+
38
46
  def message(node)
39
47
  kw = node.loc.keyword.source
40
48
  article = kw == 'while' ? 'a' : 'an'
@@ -5,12 +5,13 @@ module Rubocop
5
5
  module Style
6
6
  # This cop checks for trailing comma in parameter lists and literals.
7
7
  class TrailingComma < Cop
8
+ include ArraySyntax
8
9
  include ConfigurableEnforcedStyle
9
10
 
10
11
  MSG = '%s comma after the last %s.'
11
12
 
12
13
  def on_array(node)
13
- check_literal(node, 'item of %s array')
14
+ check_literal(node, 'item of %s array') if square_brackets?(node)
14
15
  end
15
16
 
16
17
  def on_hash(node)
@@ -3,7 +3,7 @@
3
3
  module Rubocop
4
4
  # This module holds the RuboCop version information.
5
5
  module Version
6
- STRING = '0.18.0'
6
+ STRING = '0.18.1'
7
7
 
8
8
  MSG = '%s (using Parser %s, running on %s %s %s)'
9
9
 
@@ -144,6 +144,13 @@ describe Rubocop::Cop::Style::AccessModifierIndentation, :config do
144
144
  expect(cop.offences).to be_empty
145
145
  end
146
146
 
147
+ it 'accepts an empty class' do
148
+ inspect_source(cop,
149
+ ['class Test',
150
+ 'end'])
151
+ expect(cop.offences).to be_empty
152
+ end
153
+
147
154
  it 'handles properly nested classes' do
148
155
  inspect_source(cop,
149
156
  ['class Test',
@@ -315,5 +322,40 @@ describe Rubocop::Cop::Style::AccessModifierIndentation, :config do
315
322
  ' end',
316
323
  'end'].join("\n"))
317
324
  end
325
+
326
+ it 'auto-corrects private in complicated case' do
327
+ corrected = autocorrect_source(cop, ['class Hello',
328
+ ' def foo',
329
+ " 'hi'",
330
+ ' end',
331
+ '',
332
+ ' def bar',
333
+ ' Module.new do',
334
+ '',
335
+ ' private',
336
+ '',
337
+ ' def hi',
338
+ " 'bye'",
339
+ ' end',
340
+ ' end',
341
+ ' end',
342
+ 'end'])
343
+ expect(corrected).to eq(['class Hello',
344
+ ' def foo',
345
+ " 'hi'",
346
+ ' end',
347
+ '',
348
+ ' def bar',
349
+ ' Module.new do',
350
+ '',
351
+ ' private',
352
+ '',
353
+ ' def hi',
354
+ " 'bye'",
355
+ ' end',
356
+ ' end',
357
+ ' end',
358
+ 'end'].join("\n"))
359
+ end
318
360
  end
319
361
  end
@@ -136,6 +136,18 @@ describe Rubocop::Cop::Style::AlignHash, :config do
136
136
  expect(cop.offences).to be_empty
137
137
  end
138
138
 
139
+ it 'accepts a multiline array of single line hashes' do
140
+ inspect_source(cop, ['def self.scenarios_order',
141
+ ' [',
142
+ ' { before: %w( l k ) },',
143
+ ' { ending: %w( m l ) },',
144
+ ' { starting: %w( m n ) },',
145
+ ' { after: %w( n o ) }',
146
+ ' ]',
147
+ ' end'])
148
+ expect(cop.offences).to be_empty
149
+ end
150
+
139
151
  it 'registers an offence for misaligned hash values' do
140
152
  inspect_source(cop, ['hash1 = {',
141
153
  " 'a' => 0,",
@@ -3,7 +3,13 @@
3
3
  require 'spec_helper'
4
4
 
5
5
  describe Rubocop::Cop::Style::Documentation do
6
- subject(:cop) { described_class.new }
6
+
7
+ subject(:cop) { described_class.new(config) }
8
+ let(:config) do
9
+ Rubocop::Config.new('CommentAnnotation' => {
10
+ 'Keywords' => %w(TODO FIXME OPTIMIZE HACK REVIEW)
11
+ })
12
+ end
7
13
 
8
14
  it 'registers an offence for non-empty class' do
9
15
  inspect_source(cop,
@@ -14,6 +20,19 @@ describe Rubocop::Cop::Style::Documentation do
14
20
  expect(cop.offences.size).to eq(1)
15
21
  end
16
22
 
23
+ it 'does not consider comment followed by empty line to be class ' \
24
+ 'documentation' do
25
+ inspect_source(cop,
26
+ ['# Copyright 2014',
27
+ '# Some company',
28
+ '',
29
+ 'class My_Class',
30
+ ' TEST = 20',
31
+ 'end'
32
+ ])
33
+ expect(cop.offences.size).to eq(1)
34
+ end
35
+
17
36
  it 'registers an offence for non-namespace' do
18
37
  inspect_source(cop,
19
38
  ['module My_Class',
@@ -43,6 +62,16 @@ describe Rubocop::Cop::Style::Documentation do
43
62
  expect(cop.offences).to be_empty
44
63
  end
45
64
 
65
+ it 'registers an offence for non-empty class with annotation comment' do
66
+ inspect_source(cop,
67
+ ['# OPTIMIZE: Make this faster.',
68
+ 'class My_Class',
69
+ ' TEST = 20',
70
+ 'end'
71
+ ])
72
+ expect(cop.offences.size).to eq(1)
73
+ end
74
+
46
75
  it 'accepts non-empty module with documentation' do
47
76
  inspect_source(cop,
48
77
  ['# class comment',
@@ -85,6 +85,15 @@ describe Rubocop::Cop::Style::EmptyLinesAroundBody do
85
85
  expect(cop.offences.size).to eq(1)
86
86
  end
87
87
 
88
+ it 'autocorrects class body containing only a blank' do
89
+ corrected = autocorrect_source(cop,
90
+ ['class SomeClass',
91
+ '',
92
+ 'end'])
93
+ expect(corrected).to eq ['class SomeClass',
94
+ 'end'].join("\n")
95
+ end
96
+
88
97
  it 'registers an offence for module body starting with a blank' do
89
98
  inspect_source(cop,
90
99
  ['module SomeModule',
@@ -18,6 +18,13 @@ describe Rubocop::Cop::Style::LineEndConcatenation do
18
18
  expect(cop.offences).to be_empty
19
19
  end
20
20
 
21
+ it 'accepts string concat at line end when followed by comment' do
22
+ inspect_source(cop,
23
+ ['top = "test" + # something',
24
+ '"top"'])
25
+ expect(cop.offences).to be_empty
26
+ end
27
+
21
28
  it 'autocorrects by replacing + with \\' do
22
29
  corrected = autocorrect_source(cop,
23
30
  ['top = "test" +',
@@ -28,6 +28,11 @@ describe Rubocop::Cop::Style::ParenthesesAroundCondition, :config do
28
28
  .to eq("Don't use parentheses around the condition of a while.")
29
29
  end
30
30
 
31
+ it 'accepts parentheses if there is no space between the keyword and (.' do
32
+ inspect_source(cop, ['if(x > 5) then something end'])
33
+ expect(cop.offences).to be_empty
34
+ end
35
+
31
36
  it 'auto-corrects parentheses around condition' do
32
37
  corrected = autocorrect_source(cop, ['if (x > 10)',
33
38
  'elsif (x < 3)',
@@ -206,6 +206,15 @@ describe Rubocop::Cop::Style::TrailingComma, :config do
206
206
  expect(cop.offences).to be_empty
207
207
  end
208
208
 
209
+ it 'accepts a multiline word array' do
210
+ inspect_source(cop, ['ingredients = %w(',
211
+ ' sausage',
212
+ ' anchovies',
213
+ ' olives',
214
+ ')'])
215
+ expect(cop.offences).to be_empty
216
+ end
217
+
209
218
  it 'accepts missing comma after a heredoc' do
210
219
  # A heredoc that's the last item in a literal or parameter list can not
211
220
  # have a trailing comma. It's a syntax error.
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rubocop
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.18.0
4
+ version: 0.18.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Bozhidar Batsov
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-01-30 00:00:00.000000000 Z
11
+ date: 2014-02-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rainbow
@@ -210,6 +210,7 @@ files:
210
210
  - lib/rubocop/cop/lint/useless_else_without_rescue.rb
211
211
  - lib/rubocop/cop/lint/useless_setter_call.rb
212
212
  - lib/rubocop/cop/lint/void.rb
213
+ - lib/rubocop/cop/mixin/annotation_comment.rb
213
214
  - lib/rubocop/cop/mixin/array_syntax.rb
214
215
  - lib/rubocop/cop/mixin/autocorrect_alignment.rb
215
216
  - lib/rubocop/cop/mixin/check_assignment.rb