rubocop 0.3.1 → 0.3.2

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.

data/.rubocop.yml CHANGED
@@ -100,3 +100,24 @@ IfUnlessModifier:
100
100
 
101
101
  WhileUntilModifier:
102
102
  Enabled: true
103
+
104
+ FavorUnlessOverNegatedIf:
105
+ Enabled: true
106
+
107
+ FavorUntilOverNegatedWhile:
108
+ Enabled: true
109
+
110
+ SpaceAroundEqualsInParameterDefault:
111
+ Enabled: true
112
+
113
+ NewLambdaLiteral:
114
+ Enabled: true
115
+
116
+ ParenthesesAroundCondition:
117
+ Enabled: true
118
+
119
+ MethodAndVariableSnakeCase:
120
+ Enabled: true
121
+
122
+ ClassAndModuleCamelCase:
123
+ Enabled: true
data/.travis.yml CHANGED
@@ -1,4 +1,5 @@
1
1
  language: ruby
2
2
  rvm:
3
3
  - 1.9.3
4
+ - 2.0.0
4
5
  script: bundle exec rspec
data/Gemfile CHANGED
@@ -1,15 +1,12 @@
1
1
  source 'http://rubygems.org'
2
- # Add dependencies required to use your gem here.
3
- # Example:
4
- # gem "activesupport", ">= 2.3.5"
5
2
 
6
- # Add dependencies to develop your gem here.
7
- # Include everything needed to run rake, tests, features, etc.
3
+ gem 'term-ansicolor'
4
+
8
5
  group :development do
9
- gem 'rake', '~> 10.0.0'
10
- gem 'rspec', '~> 2.12.0'
11
- gem 'yard', '~> 0.8.0'
12
- gem 'bundler', '~> 1.2.0'
13
- gem 'jeweler', '~> 1.8.3'
6
+ gem 'rake'
7
+ gem 'rspec'
8
+ gem 'yard'
9
+ gem 'bundler'
10
+ gem 'jeweler'
14
11
  gem 'simplecov'
15
12
  end
data/Gemfile.lock CHANGED
@@ -1,39 +1,41 @@
1
1
  GEM
2
2
  remote: http://rubygems.org/
3
3
  specs:
4
- diff-lcs (1.1.3)
4
+ diff-lcs (1.2.2)
5
5
  git (1.2.5)
6
6
  jeweler (1.8.4)
7
7
  bundler (~> 1.0)
8
8
  git (>= 1.2.5)
9
9
  rake
10
10
  rdoc
11
- json (1.7.6)
12
- multi_json (1.5.0)
13
- rake (10.0.3)
14
- rdoc (3.12)
11
+ json (1.7.7)
12
+ multi_json (1.7.2)
13
+ rake (10.0.4)
14
+ rdoc (4.0.1)
15
15
  json (~> 1.4)
16
- rspec (2.12.0)
17
- rspec-core (~> 2.12.0)
18
- rspec-expectations (~> 2.12.0)
19
- rspec-mocks (~> 2.12.0)
20
- rspec-core (2.12.2)
21
- rspec-expectations (2.12.1)
22
- diff-lcs (~> 1.1.3)
23
- rspec-mocks (2.12.1)
16
+ rspec (2.13.0)
17
+ rspec-core (~> 2.13.0)
18
+ rspec-expectations (~> 2.13.0)
19
+ rspec-mocks (~> 2.13.0)
20
+ rspec-core (2.13.1)
21
+ rspec-expectations (2.13.0)
22
+ diff-lcs (>= 1.1.3, < 2.0)
23
+ rspec-mocks (2.13.0)
24
24
  simplecov (0.7.1)
25
25
  multi_json (~> 1.0)
26
26
  simplecov-html (~> 0.7.1)
27
27
  simplecov-html (0.7.1)
28
- yard (0.8.3)
28
+ term-ansicolor (1.1.4)
29
+ yard (0.8.5.2)
29
30
 
30
31
  PLATFORMS
31
32
  ruby
32
33
 
33
34
  DEPENDENCIES
34
- bundler (~> 1.2.0)
35
- jeweler (~> 1.8.3)
36
- rake (~> 10.0.0)
37
- rspec (~> 2.12.0)
35
+ bundler
36
+ jeweler
37
+ rake
38
+ rspec
38
39
  simplecov
39
- yard (~> 0.8.0)
40
+ term-ansicolor
41
+ yard
data/README.md CHANGED
@@ -1,9 +1,16 @@
1
+ [![Gem Version](https://badge.fury.io/rb/rubocop.png)](http://badge.fury.io/rb/rubocop)
1
2
  [![Build Status](https://travis-ci.org/bbatsov/rubocop.png?branch=master)](https://travis-ci.org/bbatsov/rubocop)
2
3
 
3
4
  # rubocop
4
5
 
5
6
  Ruby code style checker based on the [Ruby Style Guide](https://github.com/bbatsov/ruby-style-guide).
6
7
 
8
+ ## Installation
9
+
10
+ ```bash
11
+ $ gem install rubocop
12
+ ```
13
+
7
14
  ## Basic Usage
8
15
 
9
16
  Running `rubocop` with no arguments will check all Ruby source files in the current folder:
@@ -18,8 +25,46 @@ Alternatively you can `rubocop` a list of files and folders to check:
18
25
  $ rubocop app spec lib/something.rb
19
26
  ```
20
27
 
28
+ For more details check the available command-line options:
29
+
30
+ ```bash
31
+ $ rubocop -h
32
+ ```
33
+
34
+ ## Configuration
35
+
36
+ The behavior of `rubocop` can be controlled via the
37
+ [.rubocop.yml](https://github.com/bbatsov/rubocop/blob/master/.rubocop.yml)
38
+ configuration file. The file can be placed either in your home folder
39
+ or in some project folder.
40
+
41
+ `rubocop` will start looking for the configuration file in the directory
42
+ it was started in and continue its way up to the home folder.
43
+
44
+ The file has the following format:
45
+
46
+ ```yml
47
+ Encoding:
48
+ Enabled: true
49
+
50
+ LineLength:
51
+ Enabled: true
52
+ Max: 79
53
+ ```
54
+
55
+ It allows to enable/disable certain cops (checks) and to alter their
56
+ behavior if they accept any parameters.
57
+
58
+ ## Compatibility
59
+
60
+ Unfortunately every major Ruby implementation has its own code
61
+ analysis tooling, which makes the development of a portable code
62
+ analyzer a daunting task.
63
+
64
+ `rubocop` currently supports MRI 1.9 and MRI 2.0. Support for JRuby and
65
+ Rubinius is not planned at this point.
66
+
21
67
  ## Copyright
22
68
 
23
- Copyright (c) 2012-2013 Bozhidar Batsov. See LICENSE.txt for
69
+ Copyright (c) 2012-2013 Bozhidar Batsov. See [LICENSE.txt](LICENSE.txt) for
24
70
  further details.
25
-
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.3.1
1
+ 0.3.2
data/lib/rubocop.rb CHANGED
@@ -1,6 +1,11 @@
1
1
  # encoding: utf-8
2
2
 
3
3
  require 'ripper'
4
+ require 'term/ansicolor'
5
+
6
+ class String
7
+ include Term::ANSIColor
8
+ end
4
9
 
5
10
  require 'rubocop/cop/offence'
6
11
  require 'rubocop/cop/cop'
@@ -26,6 +31,11 @@ require 'rubocop/cop/unless_else'
26
31
  require 'rubocop/cop/ampersands_pipes_vs_and_or'
27
32
  require 'rubocop/cop/when_then'
28
33
  require 'rubocop/cop/favor_modifier'
34
+ require 'rubocop/cop/favor_unless_over_negated_if'
35
+ require 'rubocop/cop/new_lambda_literal'
36
+ require 'rubocop/cop/parentheses_around_condition'
37
+ require 'rubocop/cop/method_and_variable_snake_case'
38
+ require 'rubocop/cop/class_and_module_camel_case'
29
39
 
30
40
  require 'rubocop/report/report'
31
41
  require 'rubocop/report/plain_text'
data/lib/rubocop/cli.rb CHANGED
@@ -2,6 +2,7 @@
2
2
 
3
3
  require 'optparse'
4
4
  require 'yaml'
5
+ require_relative 'cop/grammar'
5
6
 
6
7
  module Rubocop
7
8
  # The CLI is a class responsible of handling all the command line interface
@@ -64,6 +65,7 @@ module Rubocop
64
65
  unless $options[:silent]
65
66
  print "\n#{target_files(args).count} files inspected, "
66
67
  puts "#{total_offences} offences detected"
68
+ .send(total_offences.zero? ? :green : :red)
67
69
  end
68
70
 
69
71
  return total_offences == 0 ? 0 : 1
@@ -0,0 +1,20 @@
1
+ # encoding: utf-8
2
+
3
+ module Rubocop
4
+ module Cop
5
+ class ClassAndModuleCamelCase < Cop
6
+ ERROR_MESSAGE = 'Use CamelCase for classes and modules.'
7
+
8
+ def inspect(file, source, tokens, sexp)
9
+ [:class, :module].each do |keyword|
10
+ each(keyword, sexp) do |s|
11
+ if s[1][0] == :const_ref && s[1][1][0] == :@const &&
12
+ s[1][1][1] =~ /_/
13
+ add_offence(:convention, s[1][1][2].lineno, ERROR_MESSAGE)
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,47 @@
1
+ # encoding: utf-8
2
+
3
+ module Rubocop
4
+ module Cop
5
+ module FavorOtherKeywordOverNegation
6
+ private
7
+ def check(grammar_part, sexp)
8
+ each(grammar_part, sexp) do |s|
9
+ # Don't complain about negative if/else. We don't want unless/else.
10
+ next if s[3] && [:else, :elsif].include?(s[3][0])
11
+
12
+ condition = s[1]
13
+ condition = condition[1][0] while condition[0] == :paren
14
+
15
+ if condition[0] == :unary && [:!, :not].include?(condition[1])
16
+ add_offence(:convention, all_positions(s).first.lineno,
17
+ error_message)
18
+ end
19
+ end
20
+ end
21
+ end
22
+
23
+ class FavorUnlessOverNegatedIf < Cop
24
+ include FavorOtherKeywordOverNegation
25
+
26
+ def error_message
27
+ 'Favor unless (or control flow or) over if for negative conditions.'
28
+ end
29
+
30
+ def inspect(file, source, tokens, sexp)
31
+ [:if, :if_mod].each { |grammar_part| check(grammar_part, sexp) }
32
+ end
33
+ end
34
+
35
+ class FavorUntilOverNegatedWhile < Cop
36
+ include FavorOtherKeywordOverNegation
37
+
38
+ def error_message
39
+ 'Favor until over while for negative conditions.'
40
+ end
41
+
42
+ def inspect(file, source, tokens, sexp)
43
+ [:while, :while_mod].each { |grammar_part| check(grammar_part, sexp) }
44
+ end
45
+ end
46
+ end
47
+ end
@@ -90,8 +90,9 @@ module Rubocop
90
90
  find(path, sexp, [:on_op, '|'])
91
91
  end
92
92
  path += [sexp[0]] if Symbol === sexp[0]
93
- # Compensate for reverse order of if modifier
94
- children = (sexp[0] == :if_mod) ? sexp.reverse : sexp
93
+ # Compensate for reverse order of if/unless/while/until modifier.
94
+ modifiers = [:if_mod, :unless_mod, :while_mod, :until_mod]
95
+ children = modifiers.include?(sexp[0]) ? sexp.reverse : sexp
95
96
 
96
97
  children.each do |elem|
97
98
  case elem
@@ -0,0 +1,31 @@
1
+ # encoding: utf-8
2
+
3
+ module Rubocop
4
+ module Cop
5
+ class MethodAndVariableSnakeCase < Cop
6
+ ERROR_MESSAGE = 'Use snake_case for methods and variables.'
7
+ SNAKE_CASE = /^@?[\da-z_]+[!?=]?$/
8
+
9
+ def inspect(file, source, tokens, sexp)
10
+ each(:def, sexp) { |s| check(s[1]) }
11
+
12
+ each(:assign, sexp) do |s|
13
+ case s[1][0]
14
+ when :var_field
15
+ check(s[1][1])
16
+ when :field
17
+ if s[1][1][0] == :var_ref && s[1][1][1][0..1] == [:@kw, 'self']
18
+ check(s[1][3])
19
+ end
20
+ end
21
+ end
22
+ end
23
+
24
+ def check(sexp)
25
+ if [:@ivar, :@ident].include?(sexp[0]) && sexp[1] !~ SNAKE_CASE
26
+ add_offence(:convention, sexp[2].lineno, ERROR_MESSAGE)
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,17 @@
1
+ # encoding: utf-8
2
+
3
+ module Rubocop
4
+ module Cop
5
+ class NewLambdaLiteral < Cop
6
+ ERROR_MESSAGE = 'The new lambda literal syntax is preferred in Ruby 1.9.'
7
+
8
+ def inspect(file, source, tokens, sexp)
9
+ each(:fcall, sexp) do |s|
10
+ if s[1][0..1] == [:@ident, 'lambda']
11
+ add_offence(:convention, s[1][-1].lineno, ERROR_MESSAGE)
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,24 @@
1
+ # encoding: utf-8
2
+
3
+ module Rubocop
4
+ module Cop
5
+ class ParenthesesAroundCondition < Cop
6
+ ERROR_MESSAGE = "Don't use parentheses around the condition of an " +
7
+ 'if/unless/while/until, unless the condition contains an assignment.'
8
+
9
+ def inspect(file, source, tokens, sexp)
10
+ [:if, :elsif, :unless, :while, :until,
11
+ :if_mod, :unless_mod, :while_mod, :until_mod].each do |keyword|
12
+ each(keyword, sexp) do |s|
13
+ if s[1][0] == :paren && s[1][1][0][0] != :assign
14
+ positions = all_positions(s[1])
15
+ if positions.first.lineno == positions.last.lineno
16
+ add_offence(:convention, positions.first.lineno, ERROR_MESSAGE)
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -1,37 +1,26 @@
1
1
  # encoding: utf-8
2
2
 
3
- require_relative 'grammar'
4
-
5
3
  module Rubocop
6
4
  module Cop
7
5
  module SurroundingSpace
8
6
  def inspect(file, source, tokens, sexp)
9
7
  @correlations.sort.each do |ix, grammar_path|
10
- check_missing(tokens, ix, grammar_path)
8
+ check_missing_space(tokens, ix, grammar_path)
11
9
  end
12
- tokens.each_index { |ix| check_extra(tokens, ix) }
10
+ tokens.each_index { |ix| check_unwanted_space(tokens, ix) }
13
11
  end
14
12
 
15
13
  private
16
14
 
17
- def tokens_on_same_row?(t1, t2)
18
- t1.pos.lineno == t2.pos.lineno
19
- end
20
-
21
15
  def previous_non_space(tokens, ix)
22
- (ix - 1).downto(0) do |i|
23
- t = tokens[i]
24
- return t unless whitespace?(t)
25
- end
26
- nil
16
+ tokens[0...ix].reverse.find { |t| not whitespace?(t) }
27
17
  end
28
18
 
29
19
  def ok_without_spaces?(grammar_path)
30
20
  parent, child = grammar_path.values_at(-2, -1)
31
21
  return true if [:unary, :symbol, :defs, :def, :call].include?(parent)
32
22
  return true if [:**, :block_var].include?(child)
33
- return true if parent == :command_call && child == :'::'
34
- false
23
+ parent == :command_call && child == :'::'
35
24
  end
36
25
 
37
26
  def surrounded_by_whitespace?(nearby_tokens)
@@ -40,7 +29,7 @@ module Rubocop
40
29
  end
41
30
 
42
31
  # Default implementation for classes that don't need it.
43
- def check_missing(tokens, ix, grammar_path)
32
+ def check_missing_space(tokens, ix, grammar_path)
44
33
  end
45
34
  end
46
35
 
@@ -48,7 +37,7 @@ module Rubocop
48
37
  include SurroundingSpace
49
38
  ERROR_MESSAGE = 'Surrounding space missing for operator '
50
39
 
51
- def check_missing(tokens, ix, grammar_path)
40
+ def check_missing_space(tokens, ix, grammar_path)
52
41
  t = tokens[ix]
53
42
  if t.type == :on_op
54
43
  unless surrounded_by_whitespace?(tokens[ix - 1, 3])
@@ -60,7 +49,7 @@ module Rubocop
60
49
  end
61
50
  end
62
51
 
63
- def check_extra(tokens, ix)
52
+ def check_unwanted_space(tokens, ix)
64
53
  prev, t, nxt = tokens.values_at(ix - 1, ix, ix + 1)
65
54
  if t.type == :on_op && t.text == '**' &&
66
55
  (whitespace?(prev) || whitespace?(nxt))
@@ -73,10 +62,10 @@ module Rubocop
73
62
  class SpaceAroundBraces < Cop
74
63
  include SurroundingSpace
75
64
 
76
- def check_extra(tokens, ix)
65
+ def check_unwanted_space(tokens, ix)
77
66
  end
78
67
 
79
- def check_missing(tokens, ix, grammar_path)
68
+ def check_missing_space(tokens, ix, grammar_path)
80
69
  t = tokens[ix]
81
70
  case t.type
82
71
  when :on_lbrace
@@ -93,48 +82,60 @@ module Rubocop
93
82
  end
94
83
  end
95
84
 
96
- class SpaceInsideParens < Cop
85
+ module SpaceInside
97
86
  include SurroundingSpace
98
- def check_extra(tokens, ix)
87
+
88
+ Paren = Struct.new :left, :right, :kind
89
+
90
+ def check_unwanted_space(tokens, ix)
91
+ paren = get_paren
99
92
  prev, t, nxt = tokens.values_at(ix - 1, ix, ix + 1)
100
93
  offence_detected = case t.type
101
- when :on_lparen
94
+ when paren.left
102
95
  nxt.type == :on_sp
103
- when :on_rparen
96
+ when paren.right
104
97
  if prev.type == :on_sp
105
98
  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
99
+ prev_ns &&
100
+ prev_ns.pos.lineno == tokens[ix].pos.lineno &&
101
+ # Avoid double reporting
102
+ prev_ns.type != paren.left
110
103
  end
111
104
  end
112
105
  if offence_detected
113
106
  add_offence(:convention, t.pos.lineno,
114
- 'Space inside parentheses detected.')
107
+ "Space inside #{paren.kind} detected.")
115
108
  end
116
109
  end
117
110
  end
118
111
 
112
+ class SpaceInsideParens < Cop
113
+ include SpaceInside
114
+ def get_paren
115
+ Paren.new(:on_lparen, :on_rparen, 'parentheses')
116
+ end
117
+ end
118
+
119
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.')
120
+ include SpaceInside
121
+ def get_paren
122
+ Paren.new(:on_lbracket, :on_rbracket, 'square brackets')
123
+ end
124
+ end
125
+
126
+ class SpaceAroundEqualsInParameterDefault < Cop
127
+ def inspect(file, source, tokens, sexp)
128
+ each(:params, sexp) do |s|
129
+ (s[2] || []).each do |param, value|
130
+ value_pos = all_positions(value).first or next
131
+ if param[-1].lineno == value_pos.lineno
132
+ if value_pos.column - (param[-1].column + param[1].length) <= 2
133
+ add_offence(:convention, param[-1].lineno,
134
+ 'Surrounding space missing in default value ' +
135
+ 'assignment.')
136
+ end
137
+ end
138
+ end
138
139
  end
139
140
  end
140
141
  end