rubocop 0.2.1 → 0.3.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 (46) hide show
  1. data/.rubocop.yml +89 -0
  2. data/Rakefile +4 -3
  3. data/VERSION +1 -1
  4. data/lib/rubocop.rb +3 -0
  5. data/lib/rubocop/cli.rb +45 -7
  6. data/lib/rubocop/cop/ampersands_pipes_vs_and_or.rb +25 -0
  7. data/lib/rubocop/cop/blocks.rb +39 -28
  8. data/lib/rubocop/cop/cop.rb +7 -12
  9. data/lib/rubocop/cop/def_parentheses.rb +37 -24
  10. data/lib/rubocop/cop/encoding.rb +4 -4
  11. data/lib/rubocop/cop/if_then_else.rb +28 -15
  12. data/lib/rubocop/cop/offence.rb +1 -1
  13. data/lib/rubocop/cop/space_after_comma_etc.rb +27 -10
  14. data/lib/rubocop/cop/surrounding_space.rb +102 -53
  15. data/lib/rubocop/cop/ternary_operator.rb +27 -10
  16. data/lib/rubocop/cop/unless_else.rb +19 -0
  17. data/lib/rubocop/cop/when_then.rb +25 -0
  18. data/lib/rubocop/report/emacs_style.rb +2 -1
  19. data/rubocop.gemspec +24 -7
  20. data/spec/rubocop/cli_spec.rb +71 -1
  21. data/spec/rubocop/cops/align_parameters_spec.rb +4 -4
  22. data/spec/rubocop/cops/ampersands_pipes_vs_and_or_spec.rb +57 -0
  23. data/spec/rubocop/cops/cop_spec.rb +2 -2
  24. data/spec/rubocop/cops/{def_parentheses_spec.rb → def_with_parentheses_spec.rb} +3 -18
  25. data/spec/rubocop/cops/def_without_parentheses_spec.rb +26 -0
  26. data/spec/rubocop/cops/encoding_spec.rb +41 -0
  27. data/spec/rubocop/cops/end_of_line_spec.rb +6 -0
  28. data/spec/rubocop/cops/if_with_semicolon_spec.rb +17 -0
  29. data/spec/rubocop/cops/indentation_spec.rb +2 -1
  30. data/spec/rubocop/cops/{blocks_spec.rb → multiline_blocks_spec.rb} +2 -13
  31. data/spec/rubocop/cops/multiline_if_then_spec.rb +56 -0
  32. data/spec/rubocop/cops/one_line_conditional_spec.rb +17 -0
  33. data/spec/rubocop/cops/single_line_blocks_spec.rb +22 -0
  34. data/spec/rubocop/cops/{space_after_comma_etc_spec.rb → space_after_colon_spec.rb} +2 -14
  35. data/spec/rubocop/cops/space_after_comma_spec.rb +17 -0
  36. data/spec/rubocop/cops/space_after_semicolon_spec.rb +17 -0
  37. data/spec/rubocop/cops/space_around_braces_spec.rb +32 -0
  38. data/spec/rubocop/cops/{surrounding_space_spec.rb → space_around_operators_spec.rb} +4 -73
  39. data/spec/rubocop/cops/space_inside_brackets_spec.rb +43 -0
  40. data/spec/rubocop/cops/space_inside_parens_spec.rb +27 -0
  41. data/spec/rubocop/cops/ternary_operator_spec.rb +26 -6
  42. data/spec/rubocop/cops/unless_else_spec.rb +29 -0
  43. data/spec/rubocop/cops/when_then_spec.rb +38 -0
  44. data/spec/spec_helper.rb +5 -0
  45. metadata +25 -8
  46. data/spec/rubocop/cops/if_then_else_spec.rb +0 -74
@@ -4,12 +4,12 @@ module Rubocop
4
4
  module Cop
5
5
  class Encoding < Cop
6
6
  ERROR_MESSAGE = 'Missing encoding comment.'
7
- MAX_LINE_LENGTH = 80
8
7
 
9
8
  def inspect(file, source, tokens, sexp)
10
- unless source[0] =~ /#.*coding: (UTF|utf)-8/
11
- message = sprintf(ERROR_MESSAGE)
12
- add_offence(:convention, 1, message)
9
+ expected_line = 0
10
+ expected_line += 1 if source[expected_line] =~ /^#!/
11
+ unless source[expected_line] =~ /#.*coding: (UTF|utf)-8/
12
+ add_offence(:convention, 1, ERROR_MESSAGE)
13
13
  end
14
14
  end
15
15
  end
@@ -2,21 +2,13 @@
2
2
 
3
3
  module Rubocop
4
4
  module Cop
5
- class IfThenElse < Cop
6
- ERROR_MESSAGE = {
7
- multiline_if_then:
8
- 'Never use then for multi-line if/unless.',
9
- one_liner:
10
- 'Favor the ternary operator (?:) over if/then/else/end constructs.',
11
- semicolon:
12
- 'Never use if x; Use the ternary operator instead.'
13
- }
14
-
5
+ module IfThenElse
15
6
  def inspect(file, source, tokens, sexp)
16
7
  tokens.each_with_index do |t, ix|
17
8
  if t.type == :on_kw && ['if', 'unless'].include?(t.text)
18
- error = ERROR_MESSAGE[kind_of_if(tokens, ix + 1)]
19
- add_offence(:convention, t.pos.lineno, error) if error
9
+ if kind_of_if(tokens, ix + 1) == self.class
10
+ add_offence(:convention, t.pos.lineno, error_message)
11
+ end
20
12
  end
21
13
  end
22
14
  end
@@ -28,12 +20,12 @@ module Rubocop
28
20
  when :on_kw
29
21
  case t.text
30
22
  when 'then' then then_found = true
31
- when 'end' then return :one_liner
23
+ when 'end' then return OneLineConditional
32
24
  end
33
25
  when :on_ignored_nl, :on_nl
34
26
  break
35
27
  when :on_semicolon
36
- return :semicolon
28
+ return IfWithSemicolon
37
29
  when :on_comment
38
30
  break if t.text =~ /\n/
39
31
  when :on_sp
@@ -42,7 +34,28 @@ module Rubocop
42
34
  then_found = false
43
35
  end
44
36
  end
45
- then_found ? :multiline_if_then : nil
37
+ then_found ? MultilineIfThen : nil
38
+ end
39
+ end
40
+
41
+ class IfWithSemicolon < Cop
42
+ include IfThenElse
43
+ def error_message
44
+ 'Never use if x; Use the ternary operator instead.'
45
+ end
46
+ end
47
+
48
+ class MultilineIfThen < Cop
49
+ include IfThenElse
50
+ def error_message
51
+ 'Never use then for multi-line if/unless.'
52
+ end
53
+ end
54
+
55
+ class OneLineConditional < Cop
56
+ include IfThenElse
57
+ def error_message
58
+ 'Favor the ternary operator (?:) over if/then/else/end constructs.'
46
59
  end
47
60
  end
48
61
  end
@@ -14,7 +14,7 @@ module Rubocop
14
14
  end
15
15
 
16
16
  def to_s
17
- "#{encode_severity}:#{sprintf("%3d", line_number)}: #{message}"
17
+ "#{encode_severity}:%3d: #{message}" % [line_number]
18
18
  end
19
19
 
20
20
  def encode_severity
@@ -2,24 +2,41 @@
2
2
 
3
3
  module Rubocop
4
4
  module Cop
5
- class SpaceAfterCommaEtc < Cop
5
+ module SpaceAfterCommaEtc
6
6
  ERROR_MESSAGE = 'Space missing after %s.'
7
7
 
8
8
  def inspect(file, source, tokens, sexp)
9
9
  tokens.each_index do |ix|
10
10
  t = tokens[ix]
11
- kind = case t.type
12
- when :on_comma then 'comma'
13
- when :on_label then 'colon'
14
- when :on_op then 'colon' if t.text == ':'
15
- when :on_semicolon then 'semicolon'
16
- end
17
- if kind and not [:on_sp,
18
- :on_ignored_nl].include?(tokens[ix + 1].type)
19
- add_offence(:convention, t.pos.lineno, ERROR_MESSAGE % kind)
11
+ if kind(t) && !whitespace?(tokens[ix + 1])
12
+ add_offence(:convention, t.pos.lineno, ERROR_MESSAGE % kind(t))
20
13
  end
21
14
  end
22
15
  end
23
16
  end
17
+
18
+ class SpaceAfterComma < Cop
19
+ include SpaceAfterCommaEtc
20
+ def kind(token)
21
+ 'comma' if token.type == :on_comma
22
+ end
23
+ end
24
+
25
+ class SpaceAfterSemicolon < Cop
26
+ include SpaceAfterCommaEtc
27
+ def kind(token)
28
+ 'semicolon' if token.type == :on_semicolon
29
+ end
30
+ end
31
+
32
+ class SpaceAfterColon < Cop
33
+ include SpaceAfterCommaEtc
34
+ def kind(token)
35
+ case token.type
36
+ when :on_label then 'colon'
37
+ when :on_op then 'colon' if token.text == ':'
38
+ end
39
+ end
40
+ end
24
41
  end
25
42
  end
@@ -4,62 +4,12 @@ require_relative 'grammar'
4
4
 
5
5
  module Rubocop
6
6
  module Cop
7
- class SurroundingSpace < Cop
8
- ERROR_MESSAGE = 'Surrounding space missing for '
9
-
7
+ module SurroundingSpace
10
8
  def inspect(file, source, tokens, sexp)
11
9
  @correlations.sort.each do |ix, grammar_path|
12
- t = tokens[ix]
13
- case t.type
14
- when :on_op
15
- unless surrounded_by_whitespace?(tokens[ix - 1, 3])
16
- unless ok_without_spaces?(grammar_path)
17
- add_offence(:convention, t.pos.lineno,
18
- ERROR_MESSAGE + "operator '#{t.text}'.")
19
- end
20
- end
21
- when :on_lbrace
22
- unless surrounded_by_whitespace?(tokens[ix - 1, 3])
23
- add_offence(:convention, t.pos.lineno, ERROR_MESSAGE + "'{'.")
24
- end
25
- when :on_rbrace
26
- unless whitespace?(tokens[ix - 1])
27
- add_offence(:convention, t.pos.lineno,
28
- "Space missing to the left of '}'.")
29
- end
30
- end
31
- end
32
- tokens.each_index do |ix|
33
- t = tokens[ix]
34
- prev, nxt = tokens.values_at(ix - 1, ix + 1)
35
- offence_detected = case t.type
36
- when :on_lbracket, :on_lparen
37
- nxt.type == :on_sp
38
- when :on_rbracket, :on_rparen
39
- if prev.type == :on_sp
40
- prev_ns = previous_non_space(tokens, ix)
41
- prev_ns && tokens_on_same_row?(prev_ns,
42
- tokens[ix]) &&
43
- # Avoid double repoting of [ ] and ( )
44
- prev_ns.type != :on_lbracket &&
45
- prev_ns.type != :on_lparen
46
- end
47
- when :on_op
48
- t.text == '**' &&
49
- (whitespace?(prev) || whitespace?(nxt))
50
- end
51
- if offence_detected
52
- kind = case t.type
53
- when :on_lparen, :on_rparen
54
- 'inside parentheses'
55
- when :on_lbracket, :on_rbracket
56
- 'inside square brackets'
57
- when :on_op
58
- "around operator #{t.text}"
59
- end
60
- add_offence(:convention, t.pos.lineno, "Space #{kind} detected.")
61
- end
10
+ check_missing(tokens, ix, grammar_path)
62
11
  end
12
+ tokens.each_index { |ix| check_extra(tokens, ix) }
63
13
  end
64
14
 
65
15
  private
@@ -88,6 +38,105 @@ module Rubocop
88
38
  left, _, right = nearby_tokens
89
39
  whitespace?(left) && whitespace?(right)
90
40
  end
41
+
42
+ # Default implementation for classes that don't need it.
43
+ def check_missing(tokens, ix, grammar_path)
44
+ end
45
+ end
46
+
47
+ class SpaceAroundOperators < Cop
48
+ include SurroundingSpace
49
+ ERROR_MESSAGE = 'Surrounding space missing for operator '
50
+
51
+ def check_missing(tokens, ix, grammar_path)
52
+ t = tokens[ix]
53
+ if t.type == :on_op
54
+ unless surrounded_by_whitespace?(tokens[ix - 1, 3])
55
+ unless ok_without_spaces?(grammar_path)
56
+ add_offence(:convention, t.pos.lineno,
57
+ ERROR_MESSAGE + "'#{t.text}'.")
58
+ end
59
+ end
60
+ end
61
+ end
62
+
63
+ def check_extra(tokens, ix)
64
+ prev, t, nxt = tokens.values_at(ix - 1, ix, ix + 1)
65
+ if t.type == :on_op && t.text == '**' &&
66
+ (whitespace?(prev) || whitespace?(nxt))
67
+ add_offence(:convention, t.pos.lineno,
68
+ "Space around operator #{t.text} detected.")
69
+ end
70
+ end
71
+ end
72
+
73
+ class SpaceAroundBraces < Cop
74
+ include SurroundingSpace
75
+
76
+ def check_extra(tokens, ix)
77
+ end
78
+
79
+ def check_missing(tokens, ix, grammar_path)
80
+ t = tokens[ix]
81
+ case t.type
82
+ when :on_lbrace
83
+ unless surrounded_by_whitespace?(tokens[ix - 1, 3])
84
+ add_offence(:convention, t.pos.lineno,
85
+ "Surrounding space missing for '{'.")
86
+ end
87
+ when :on_rbrace
88
+ unless whitespace?(tokens[ix - 1])
89
+ add_offence(:convention, t.pos.lineno,
90
+ "Space missing to the left of '}'.")
91
+ end
92
+ end
93
+ end
94
+ end
95
+
96
+ class SpaceInsideParens < Cop
97
+ include SurroundingSpace
98
+ def check_extra(tokens, ix)
99
+ prev, t, nxt = tokens.values_at(ix - 1, ix, ix + 1)
100
+ offence_detected = case t.type
101
+ when :on_lparen
102
+ nxt.type == :on_sp
103
+ when :on_rparen
104
+ if prev.type == :on_sp
105
+ prev_ns = previous_non_space(tokens, ix)
106
+ prev_ns && tokens_on_same_row?(prev_ns,
107
+ tokens[ix]) &&
108
+ # Avoid double repoting of ( )
109
+ prev_ns.type != :on_lparen
110
+ end
111
+ end
112
+ if offence_detected
113
+ add_offence(:convention, t.pos.lineno,
114
+ 'Space inside parentheses detected.')
115
+ end
116
+ end
117
+ end
118
+
119
+ class SpaceInsideBrackets < Cop
120
+ include SurroundingSpace
121
+ def check_extra(tokens, ix)
122
+ prev, t, nxt = tokens.values_at(ix - 1, ix, ix + 1)
123
+ offence_detected = case t.type
124
+ when :on_lbracket
125
+ nxt.type == :on_sp
126
+ when :on_rbracket
127
+ if prev.type == :on_sp
128
+ prev_ns = previous_non_space(tokens, ix)
129
+ prev_ns && tokens_on_same_row?(prev_ns,
130
+ tokens[ix]) &&
131
+ # Avoid double repoting of [ ] and ( )
132
+ prev_ns.type != :on_lbracket
133
+ end
134
+ end
135
+ if offence_detected
136
+ add_offence(:convention, t.pos.lineno,
137
+ 'Space inside square brackets detected.')
138
+ end
139
+ end
91
140
  end
92
141
  end
93
142
  end
@@ -2,22 +2,39 @@
2
2
 
3
3
  module Rubocop
4
4
  module Cop
5
- class TernaryOperator < Cop
6
- ERROR_MESSAGE = 'Avoid multi-line ?: (the ternary operator); use ' +
7
- 'if/unless instead.'
8
-
5
+ module TernaryOperator
9
6
  def inspect(file, source, tokens, sexp)
10
7
  each(:ifop, sexp) do |ifop|
11
- line_numbers = all_positions(ifop).map(&:lineno)
12
- if line_numbers.uniq.size > 1
13
- add_offence(:convention, line_numbers[0], ERROR_MESSAGE)
8
+ if offends?(ifop)
9
+ add_offence(:convention, all_positions(ifop).first.lineno,
10
+ error_message)
14
11
  end
15
12
  end
16
13
  end
14
+ end
15
+
16
+ class MultilineTernaryOperator < Cop
17
+ include TernaryOperator
18
+
19
+ def error_message
20
+ 'Avoid multi-line ?: (the ternary operator); use if/unless instead.'
21
+ end
22
+
23
+ def offends?(ifop)
24
+ all_positions(ifop).map(&:lineno).uniq.size > 1
25
+ end
26
+ end
27
+
28
+ class NestedTernaryOperator < Cop
29
+ include TernaryOperator
30
+
31
+ def error_message
32
+ 'Ternary operators must not be nested. Prefer if/else constructs ' +
33
+ 'instead.'
34
+ end
17
35
 
18
- def all_positions(sexp)
19
- return [sexp[2]] if sexp[0] =~ /^@/
20
- sexp.grep(Array).inject([]) { |memo, s| memo + all_positions(s) }
36
+ def offends?(ifop)
37
+ ifop.flatten[1..-1].include?(:ifop)
21
38
  end
22
39
  end
23
40
  end
@@ -0,0 +1,19 @@
1
+ # encoding: utf-8
2
+
3
+ module Rubocop
4
+ module Cop
5
+ class UnlessElse < Cop
6
+ ERROR_MESSAGE = 'Never use unless with else. Rewrite these with the ' +
7
+ 'positive case first.'
8
+
9
+ def inspect(file, source, tokens, sexp)
10
+ each(:unless, sexp) do |unless_sexp|
11
+ if unless_sexp.compact.find { |s| s[0] == :else }
12
+ add_offence(:convention, all_positions(unless_sexp).first.lineno,
13
+ ERROR_MESSAGE)
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,25 @@
1
+ # encoding: utf-8
2
+
3
+ module Rubocop
4
+ module Cop
5
+ class WhenThen < Cop
6
+ ERROR_MESSAGE = 'Never use "when x;". Use "when x then" instead.'
7
+
8
+ def inspect(file, source, tokens, sexp)
9
+ each(:when, sexp) do |s|
10
+ # The grammar is:
11
+ # when <value> <divider> <body>
12
+ # where divider is either semicolon, then, or line break.
13
+ last_pos_in_value = all_positions(s[1])[-1]
14
+ start_index = tokens.index { |t| t.pos == last_pos_in_value }
15
+ tokens[start_index..-1].each do |t|
16
+ break if ['then', "\n"].include?(t.text)
17
+ if t.type == :on_semicolon
18
+ add_offence(:convention, t.pos.lineno, ERROR_MESSAGE)
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -7,7 +7,8 @@ module Rubocop
7
7
  # Generates a string representation of the report
8
8
  def generate
9
9
  report = entries.map do |e|
10
- "#@filename:#{e.line_number}: #{e.encode_severity}: #{e.message}"
10
+ '%s:%d: %s: %s' % [@filename, e.line_number, e.encode_severity,
11
+ e.message]
11
12
  end
12
13
  report.join("\n")
13
14
  end
data/rubocop.gemspec CHANGED
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = "rubocop"
8
- s.version = "0.2.1"
8
+ s.version = "0.3.0"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Bozhidar Batsov"]
12
- s.date = "2013-01-12"
12
+ s.date = "2013-02-11"
13
13
  s.description = "Automatic Ruby code style checking tool. Aims to enforce the community-driven Ruby Style Guide."
14
14
  s.email = "bozhidar@batsov.com"
15
15
  s.executables = ["rubocop"]
@@ -21,6 +21,7 @@ Gem::Specification.new do |s|
21
21
  ".document",
22
22
  ".rbenv-version",
23
23
  ".rspec",
24
+ ".rubocop.yml",
24
25
  ".rvmrc",
25
26
  ".travis.yml",
26
27
  "CONTRIBUTING.md",
@@ -37,6 +38,7 @@ Gem::Specification.new do |s|
37
38
  "lib/rubocop.rb",
38
39
  "lib/rubocop/cli.rb",
39
40
  "lib/rubocop/cop/align_parameters.rb",
41
+ "lib/rubocop/cop/ampersands_pipes_vs_and_or.rb",
40
42
  "lib/rubocop/cop/blocks.rb",
41
43
  "lib/rubocop/cop/cop.rb",
42
44
  "lib/rubocop/cop/def_parentheses.rb",
@@ -57,6 +59,8 @@ Gem::Specification.new do |s|
57
59
  "lib/rubocop/cop/tab.rb",
58
60
  "lib/rubocop/cop/ternary_operator.rb",
59
61
  "lib/rubocop/cop/trailing_whitespace.rb",
62
+ "lib/rubocop/cop/unless_else.rb",
63
+ "lib/rubocop/cop/when_then.rb",
60
64
  "lib/rubocop/report/emacs_style.rb",
61
65
  "lib/rubocop/report/plain_text.rb",
62
66
  "lib/rubocop/report/report.rb",
@@ -64,25 +68,38 @@ Gem::Specification.new do |s|
64
68
  "rubocop.gemspec",
65
69
  "spec/rubocop/cli_spec.rb",
66
70
  "spec/rubocop/cops/align_parameters_spec.rb",
67
- "spec/rubocop/cops/blocks_spec.rb",
71
+ "spec/rubocop/cops/ampersands_pipes_vs_and_or_spec.rb",
68
72
  "spec/rubocop/cops/cop_spec.rb",
69
- "spec/rubocop/cops/def_parentheses_spec.rb",
73
+ "spec/rubocop/cops/def_with_parentheses_spec.rb",
74
+ "spec/rubocop/cops/def_without_parentheses_spec.rb",
70
75
  "spec/rubocop/cops/empty_lines_spec.rb",
76
+ "spec/rubocop/cops/encoding_spec.rb",
71
77
  "spec/rubocop/cops/end_of_line_spec.rb",
72
78
  "spec/rubocop/cops/grammar_spec.rb",
73
79
  "spec/rubocop/cops/hash_syntax_spec.rb",
74
- "spec/rubocop/cops/if_then_else_spec.rb",
80
+ "spec/rubocop/cops/if_with_semicolon_spec.rb",
75
81
  "spec/rubocop/cops/indentation_spec.rb",
76
82
  "spec/rubocop/cops/line_length_spec.rb",
83
+ "spec/rubocop/cops/multiline_blocks_spec.rb",
84
+ "spec/rubocop/cops/multiline_if_then_spec.rb",
77
85
  "spec/rubocop/cops/numeric_literals_spec.rb",
78
86
  "spec/rubocop/cops/offence_spec.rb",
87
+ "spec/rubocop/cops/one_line_conditional_spec.rb",
79
88
  "spec/rubocop/cops/parameter_lists_spec.rb",
80
- "spec/rubocop/cops/space_after_comma_etc_spec.rb",
89
+ "spec/rubocop/cops/single_line_blocks_spec.rb",
90
+ "spec/rubocop/cops/space_after_colon_spec.rb",
91
+ "spec/rubocop/cops/space_after_comma_spec.rb",
92
+ "spec/rubocop/cops/space_after_semicolon_spec.rb",
93
+ "spec/rubocop/cops/space_around_braces_spec.rb",
94
+ "spec/rubocop/cops/space_around_operators_spec.rb",
95
+ "spec/rubocop/cops/space_inside_brackets_spec.rb",
96
+ "spec/rubocop/cops/space_inside_parens_spec.rb",
81
97
  "spec/rubocop/cops/string_literals_spec.rb",
82
- "spec/rubocop/cops/surrounding_space_spec.rb",
83
98
  "spec/rubocop/cops/tab_spec.rb",
84
99
  "spec/rubocop/cops/ternary_operator_spec.rb",
85
100
  "spec/rubocop/cops/trailing_whitespace_spec.rb",
101
+ "spec/rubocop/cops/unless_else_spec.rb",
102
+ "spec/rubocop/cops/when_then_spec.rb",
86
103
  "spec/rubocop/reports/emacs_style_spec.rb",
87
104
  "spec/rubocop/reports/report_spec.rb",
88
105
  "spec/spec_helper.rb"