rubocop 0.5.0 → 0.6.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 (57) hide show
  1. data/.rubocop.yml +59 -1
  2. data/CHANGELOG.md +38 -0
  3. data/Gemfile +1 -10
  4. data/README.md +28 -1
  5. data/Rakefile +1 -15
  6. data/lib/rubocop.rb +14 -0
  7. data/lib/rubocop/cli.rb +70 -7
  8. data/lib/rubocop/cop/alias.rb +5 -8
  9. data/lib/rubocop/cop/array_literal.rb +22 -0
  10. data/lib/rubocop/cop/ascii_identifiers_and_comments.rb +18 -0
  11. data/lib/rubocop/cop/avoid_perlisms.rb +19 -28
  12. data/lib/rubocop/cop/brace_after_percent.rb +28 -0
  13. data/lib/rubocop/cop/cop.rb +15 -3
  14. data/lib/rubocop/cop/encoding.rb +1 -1
  15. data/lib/rubocop/cop/ensure_return.rb +36 -0
  16. data/lib/rubocop/cop/favor_percent_r.rb +19 -0
  17. data/lib/rubocop/cop/favor_sprintf.rb +2 -10
  18. data/lib/rubocop/cop/grammar.rb +6 -3
  19. data/lib/rubocop/cop/handle_exceptions.rb +21 -0
  20. data/lib/rubocop/cop/hash_literal.rb +22 -0
  21. data/lib/rubocop/cop/method_length.rb +66 -0
  22. data/lib/rubocop/cop/op_method.rb +23 -0
  23. data/lib/rubocop/cop/percent_literals.rb +25 -0
  24. data/lib/rubocop/cop/percent_r.rb +19 -0
  25. data/lib/rubocop/cop/reduce_arguments.rb +67 -0
  26. data/lib/rubocop/cop/rescue_exception.rb +39 -0
  27. data/lib/rubocop/cop/rescue_modifier.rb +20 -0
  28. data/lib/rubocop/cop/symbol_snake_case.rb +5 -5
  29. data/lib/rubocop/cop/syntax.rb +13 -2
  30. data/lib/rubocop/version.rb +3 -1
  31. data/rubocop.gemspec +36 -169
  32. data/spec/rubocop/cli_spec.rb +146 -15
  33. data/spec/rubocop/cops/alias_spec.rb +10 -1
  34. data/spec/rubocop/cops/array_literal_spec.rb +29 -0
  35. data/spec/rubocop/cops/ascii_identifiers_and_comments_spec.rb +38 -0
  36. data/spec/rubocop/cops/avoid_perlisms_spec.rb +12 -0
  37. data/spec/rubocop/cops/brace_after_percent_spec.rb +27 -0
  38. data/spec/rubocop/cops/encoding_spec.rb +2 -2
  39. data/spec/rubocop/cops/ensure_return_spec.rb +37 -0
  40. data/spec/rubocop/cops/favor_percent_r.rb +29 -0
  41. data/spec/rubocop/cops/favor_sprintf_spec.rb +8 -1
  42. data/spec/rubocop/cops/grammar_spec.rb +54 -40
  43. data/spec/rubocop/cops/handle_exceptions_spec.rb +36 -0
  44. data/spec/rubocop/cops/hash_literal_spec.rb +29 -0
  45. data/spec/rubocop/cops/method_length_spec.rb +150 -0
  46. data/spec/rubocop/cops/op_method_spec.rb +58 -0
  47. data/spec/rubocop/cops/percent_literals_spec.rb +47 -0
  48. data/spec/rubocop/cops/percent_r_spec.rb +29 -0
  49. data/spec/rubocop/cops/reduce_arguments_spec.rb +57 -0
  50. data/spec/rubocop/cops/rescue_exception_spec.rb +73 -0
  51. data/spec/rubocop/cops/rescue_modifier.rb +40 -0
  52. data/spec/rubocop/cops/space_around_operators_spec.rb +7 -0
  53. data/spec/rubocop/cops/symbol_snake_case_spec.rb +19 -7
  54. data/spec/rubocop/cops/tab_spec.rb +1 -1
  55. metadata +131 -50
  56. data/Gemfile.lock +0 -41
  57. data/VERSION +0 -1
@@ -10,6 +10,12 @@ LineLength:
10
10
  Enabled: true
11
11
  Max: 79
12
12
 
13
+ # Avoid methods longer than 10 lines of code
14
+ MethodLength:
15
+ Enabled: true
16
+ CountComments: false # count full line comments?
17
+ Max: 65
18
+
13
19
  # No hard tabs.
14
20
  Tab:
15
21
  Enabled: true
@@ -204,4 +210,56 @@ FavorSprintf:
204
210
 
205
211
  # Use alias_method instead of alias.
206
212
  Alias:
207
- Enabled: true
213
+ Enabled: true
214
+
215
+ # Avoid using rescue in its modifier form.
216
+ RescueModifier:
217
+ Enabled: true
218
+
219
+ # Avoid the use of %q, %Q, %s and %x.
220
+ PercentLiterals:
221
+ Enabled: true
222
+
223
+ # Prefer () as delimiters for all % literals.
224
+ BraceAfterPercent:
225
+ Enabled: true
226
+
227
+ # Never use return in an ensure block.
228
+ EnsureReturn:
229
+ Enabled: true
230
+
231
+ # Don't suppress exception.
232
+ HandleExceptions:
233
+ Enabled: true
234
+
235
+ # Use only ascii symbols in identifiers and comments.
236
+ AsciiIdentifiersAndComments:
237
+ Enabled: true
238
+
239
+ # Avoid rescuing the Exception class.
240
+ RescueException:
241
+ Enabled: true
242
+
243
+ # Prefer array literal to Array.new.
244
+ ArrayLiteral:
245
+ Enabled: true
246
+
247
+ # Prefer hash {} literail to Hash.new.
248
+ HashLiteral:
249
+ Enabled: true
250
+
251
+ # When defining binary operators, name the argument other.
252
+ OpMethod:
253
+ Enabled: true
254
+
255
+ # Name reduce arguments |a, e| (accumulator, element)
256
+ ReduceArguments:
257
+ Enabled: true
258
+
259
+ # Use %r only for regular expressions matching more than one '/' character.
260
+ PercentR:
261
+ Enabled: true
262
+
263
+ # Use %r for regular expressions matching more than one '/' character.
264
+ FavorPercentR:
265
+ Enabled: true
@@ -6,6 +6,44 @@
6
6
 
7
7
  ### Bugs fixed
8
8
 
9
+ ## 0.6.0 (04/23/2013)
10
+
11
+ ### New features
12
+
13
+ * New cop `ReduceArguments` tracks argument names in reduce calls
14
+ * New cop `MethodLength` tracks number of LOC (lines of code) in methods
15
+ * New cop `RescueModifier` tracks uses of `rescue` in modifier form.
16
+ * New cop `PercentLiterals` tracks uses of `%q`, `%Q`, `%s` and `%x`.
17
+ * New cop `BraceAfterPercent` tracks uses of % literals with
18
+ delimiters other than ().
19
+ * Support for disabling cops locally in a file with rubocop:disable comments.
20
+ * New cop `EnsureReturn` tracks usages of `return` in `ensure` blocks.
21
+ * New cop `HandleExceptions` tracks suppressed exceptions.
22
+ * New cop `AsciiIdentifiersAndComments` tracks uses of non-ascii
23
+ characters in identifiers and comments.
24
+ * New cop `RescueException` tracks uses of rescuing the `Exception` class.
25
+ * New cop `ArrayLiteral` tracks uses of Array.new.
26
+ * New cop `HashLiteral` tracks uses of Hash.new.
27
+ * New cop `OpMethod` tracks the argument name in operator methods.
28
+ * New cop `PercentR` tracks uses of %r literals with zero or one slash in the regexp.
29
+ * New cop `FavorPercentR` tracks uses of // literals with more than one slash in the regexp.
30
+
31
+ ### Bugs fixed
32
+
33
+ * [#62](https://github.com/bbatsov/rubocop/issues/62) - Config files in ancestor directories are ignored if another exists in home directory
34
+ * [#65](https://github.com/bbatsov/rubocop/issues/65) - Suggests to convert symbols :==, :<=> and the like to snake_case
35
+ * [#66](https://github.com/bbatsov/rubocop/issues/66) - Does not crash on unreadable or unparseable files
36
+ * [#70](https://github.com/bbatsov/rubocop/issues/70) - Support `alias` with bareword arguments
37
+ * [#64](https://github.com/bbatsov/rubocop/issues/64) - Performance issue with Bundler
38
+ * [#75](https://github.com/bbatsov/rubocop/issues/75) - Make it clear that some global variables require the use of the English library
39
+ * [#79](https://github.com/bbatsov/rubocop/issues/79) - Ternary operator missing whitespace detection
40
+
41
+ ### Misc
42
+
43
+ * Dropped Jeweler for gem release management since it's no longer
44
+ actively maintained.
45
+ * Handle pluralization properly in the final summary.
46
+
9
47
  ## 0.5.0 (04/17/2013)
10
48
 
11
49
  ### New features
data/Gemfile CHANGED
@@ -1,12 +1,3 @@
1
1
  source 'http://rubygems.org'
2
2
 
3
- gem 'term-ansicolor'
4
-
5
- group :development do
6
- gem 'rake'
7
- gem 'rspec'
8
- gem 'yard'
9
- gem 'bundler'
10
- gem 'jeweler'
11
- gem 'simplecov'
12
- end
3
+ gemspec
data/README.md CHANGED
@@ -3,6 +3,9 @@
3
3
 
4
4
  # RuboCop
5
5
 
6
+ > Role models are important. <br/>
7
+ > -- Officer Alex J. Murphy / RoboCop
8
+
6
9
  **RuboCop** is a Ruby code style checker based on the
7
10
  [Ruby Style Guide](https://github.com/bbatsov/ruby-style-guide).
8
11
 
@@ -23,7 +26,7 @@ in the current folder:
23
26
  $ rubocop
24
27
  ```
25
28
 
26
- Alternatively you can `rubocop` a list of files and folders to check:
29
+ Alternatively you can pass `rubocop` a list of files and folders to check:
27
30
 
28
31
  ```bash
29
32
  $ rubocop app spec lib/something.rb
@@ -67,6 +70,30 @@ LineLength:
67
70
  It allows to enable/disable certain cops (checks) and to alter their
68
71
  behavior if they accept any parameters.
69
72
 
73
+ One or more individual cops can be disabled locally in a section of a
74
+ file by adding a comment such as
75
+
76
+ ```ruby
77
+ # rubocop:disable LineLength, StringLiterals
78
+ [...]
79
+ # rubocop:enable LineLength, StringLiterals
80
+ ```
81
+
82
+ You can also disable *all* cops with
83
+
84
+ ```ruby
85
+ # rubocop:disable all
86
+ [...]
87
+ # rubocop:enable all
88
+ ```
89
+
90
+ One or more cops can be disabled on a single line with an end-of-line
91
+ comment.
92
+
93
+ ```ruby
94
+ for x in (0..19) # rubocop:disable AvoidFor
95
+ ```
96
+
70
97
  ## Compatibility
71
98
 
72
99
  Unfortunately every major Ruby implementation has its own code
data/Rakefile CHANGED
@@ -2,6 +2,7 @@
2
2
 
3
3
  require 'rubygems'
4
4
  require 'bundler'
5
+ require 'bundler/gem_tasks'
5
6
  begin
6
7
  Bundler.setup(:default, :development)
7
8
  rescue Bundler::BundlerError => e
@@ -10,21 +11,6 @@ rescue Bundler::BundlerError => e
10
11
  exit e.status_code
11
12
  end
12
13
  require 'rake'
13
-
14
- require 'jeweler'
15
- Jeweler::Tasks.new do |gem|
16
- # gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
17
- gem.name = "rubocop"
18
- gem.homepage = "http://github.com/bbatsov/rubocop"
19
- gem.license = "MIT"
20
- gem.summary = %Q{Automatic Ruby code style checking tool.}
21
- gem.description = %Q{Automatic Ruby code style checking tool. Aims to enforce the community-driven Ruby Style Guide.}
22
- gem.email = "bozhidar@batsov.com"
23
- gem.authors = ["Bozhidar Batsov"]
24
- # dependencies defined in Gemfile
25
- end
26
- Jeweler::RubygemsDotOrgTasks.new
27
-
28
14
  require 'rspec/core'
29
15
  require 'rspec/core/rake_task'
30
16
  RSpec::Core::RakeTask.new(:spec) do |spec|
@@ -47,6 +47,20 @@ require 'rubocop/cop/variable_interpolation'
47
47
  require 'rubocop/cop/semicolon'
48
48
  require 'rubocop/cop/favor_sprintf'
49
49
  require 'rubocop/cop/alias'
50
+ require 'rubocop/cop/rescue_modifier'
51
+ require 'rubocop/cop/percent_literals'
52
+ require 'rubocop/cop/brace_after_percent'
53
+ require 'rubocop/cop/ensure_return'
54
+ require 'rubocop/cop/handle_exceptions'
55
+ require 'rubocop/cop/rescue_exception'
56
+ require 'rubocop/cop/ascii_identifiers_and_comments'
57
+ require 'rubocop/cop/hash_literal'
58
+ require 'rubocop/cop/array_literal'
59
+ require 'rubocop/cop/method_length'
60
+ require 'rubocop/cop/op_method'
61
+ require 'rubocop/cop/reduce_arguments'
62
+ require 'rubocop/cop/percent_r'
63
+ require 'rubocop/cop/favor_percent_r'
50
64
 
51
65
  require 'rubocop/report/report'
52
66
  require 'rubocop/report/plain_text'
@@ -31,7 +31,7 @@ module Rubocop
31
31
  $options[:silent] = s
32
32
  end
33
33
  opts.on('-v', '--version', 'Display version') do
34
- puts Rubocop::VERSION
34
+ puts Rubocop::Version::STRING
35
35
  exit(0)
36
36
  end
37
37
  end.parse!(args)
@@ -42,6 +42,8 @@ module Rubocop
42
42
  @configs = {}
43
43
 
44
44
  target_files(args).each do |file|
45
+ puts "Scanning #{file}" if $options[:debug]
46
+
45
47
  report = Report.create(file, $options[:mode])
46
48
  source = File.readlines(file).map do |line|
47
49
  get_rid_of_invalid_byte_sequences(line)
@@ -59,13 +61,16 @@ module Rubocop
59
61
  else
60
62
  tokens, sexp, correlations = CLI.rip_source(source)
61
63
  config = $options[:config] || config_from_dotfile(File.dirname(file))
64
+ disabled_lines = disabled_lines_in(source)
62
65
 
63
66
  cops.each do |cop_klass|
64
- cop_config = config[cop_klass.name.split('::').last] if config
67
+ cop_name = cop_klass.name.split('::').last
68
+ cop_config = config[cop_name] if config
65
69
  if cop_config.nil? || cop_config['Enabled']
66
70
  cop_klass.config = cop_config
67
71
  cop = cop_klass.new
68
72
  cop.correlations = correlations
73
+ cop.disabled_lines = disabled_lines[cop_name]
69
74
  cop.inspect(file, source, tokens, sexp)
70
75
  total_offences += cop.offences.count
71
76
  report << cop if cop.has_report?
@@ -77,14 +82,58 @@ module Rubocop
77
82
  end
78
83
 
79
84
  unless $options[:silent]
80
- print "\n#{target_files(args).count} files inspected, "
81
- puts "#{total_offences} offences detected"
82
- .send(total_offences.zero? ? :green : :red)
85
+ display_summary(target_files(args).count, total_offences)
83
86
  end
84
87
 
85
88
  return total_offences == 0 ? 0 : 1
86
89
  end
87
90
 
91
+ def display_summary(num_files, total_offences)
92
+ print "\n#{num_files} file#{num_files > 1 ? 's' : ''} inspected, "
93
+ offences_string = if total_offences.zero?
94
+ 'no offences'
95
+ elsif total_offences == 1
96
+ '1 offence'
97
+ else
98
+ "#{total_offences} offences"
99
+ end
100
+ puts "#{offences_string} detected"
101
+ .send(total_offences.zero? ? :green : :red)
102
+ end
103
+
104
+ def disabled_lines_in(source)
105
+ disabled_lines = Hash.new([])
106
+ disabled_section = {}
107
+ regexp = '# rubocop : (%s)\b ((?:\w+,? )+)'.gsub(' ', '\s*')
108
+ section_regexp = '^\s*' + sprintf(regexp, '(?:dis|en)able')
109
+ single_line_regexp = '\S.*' + sprintf(regexp, 'disable')
110
+
111
+ source.each_with_index do |line, ix|
112
+ each_mentioned_cop(/#{section_regexp}/, line) do |cop_name, kind|
113
+ disabled_section[cop_name] = (kind == 'disable')
114
+ end
115
+ disabled_section.keys.each do |cop_name|
116
+ disabled_lines[cop_name] += [ix + 1] if disabled_section[cop_name]
117
+ end
118
+
119
+ each_mentioned_cop(/#{single_line_regexp}/, line) do |cop_name, kind|
120
+ disabled_lines[cop_name] += [ix + 1] if kind == 'disable'
121
+ end
122
+ end
123
+ disabled_lines
124
+ end
125
+
126
+ def each_mentioned_cop(regexp, line)
127
+ match = line.match(regexp)
128
+ if match
129
+ kind, cops = match.captures
130
+ if cops.include?('all')
131
+ cops = Cop::Cop.all.map { |c| c.name.split('::').last }.join(',')
132
+ end
133
+ cops.split(/,\s*/).each { |cop_name| yield cop_name, kind }
134
+ end
135
+ end
136
+
88
137
  def get_rid_of_invalid_byte_sequences(line)
89
138
  enc = line.encoding.name
90
139
  # UTF-16 works better in this algorithm but is not supported in 1.9.2.
@@ -116,7 +165,7 @@ module Rubocop
116
165
  path = File.join(dir, '.rubocop.yml')
117
166
  if File.exist?(path)
118
167
  @configs[target_file_dir] = YAML.load_file(path)
119
- break
168
+ return @configs[target_file_dir]
120
169
  end
121
170
  dir = File.expand_path('..', dir)
122
171
  end
@@ -179,10 +228,24 @@ module Rubocop
179
228
  rb << files.select { |file| File.extname(file) == '.rb' }
180
229
  rb << files.select do |file|
181
230
  File.extname(file) == '' &&
182
- File.open(file) { |f| f.readline } =~ /#!.*ruby/
231
+ begin
232
+ File.open(file) { |f| f.readline } =~ /#!.*ruby/
233
+ rescue EOFError, ArgumentError => e
234
+ log_error(e, "Unprocessable file #{file.inspect}: ")
235
+ false
236
+ end
183
237
  end
184
238
 
185
239
  rb.flatten
186
240
  end
241
+
242
+ private
243
+
244
+ def log_error(e, msg='')
245
+ if $options[:debug]
246
+ error_message = "#{e.class}, #{e.message}"
247
+ STDERR.puts "#{msg}\t#{error_message}"
248
+ end
249
+ end
187
250
  end
188
251
  end
@@ -6,14 +6,11 @@ module Rubocop
6
6
  ERROR_MESSAGE = 'Use alias_method instead of alias.'
7
7
 
8
8
  def inspect(file, source, tokens, sexp)
9
- each(:alias, sexp) do |s|
10
- lineno = s[1][1][1][2].lineno
11
-
12
- add_offence(
13
- :convention,
14
- lineno,
15
- ERROR_MESSAGE
16
- )
9
+ tokens.each_index do |ix|
10
+ t = tokens[ix]
11
+ if t.type == :on_kw && t.text == 'alias'
12
+ add_offence(:convention, t.pos.lineno, ERROR_MESSAGE)
13
+ end
17
14
  end
18
15
  end
19
16
  end
@@ -0,0 +1,22 @@
1
+ # encoding: utf-8
2
+
3
+ module Rubocop
4
+ module Cop
5
+ class ArrayLiteral < Cop
6
+ ERROR_MESSAGE = 'Use array literal [] instead of Array.new.'
7
+
8
+ def inspect(file, source, tokens, sexp)
9
+ each(:method_add_arg, sexp) do |s|
10
+ potential_class = s[1][1][1]
11
+
12
+ if potential_class[1] == 'Array' && s[1][3][1] == 'new' &&
13
+ s[2] == [:arg_paren, nil]
14
+ add_offence(:convention,
15
+ potential_class[2].lineno,
16
+ ERROR_MESSAGE)
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,18 @@
1
+ # encoding: utf-8
2
+
3
+ module Rubocop
4
+ module Cop
5
+ class AsciiIdentifiersAndComments < Cop
6
+ ERROR_MESSAGE = 'Use only ascii symbols in identifiers and comments.'
7
+
8
+ def inspect(file, source, tokens, sexp)
9
+ tokens.each do |t|
10
+ if [:on_ident, :on_comment].include?(t.type) &&
11
+ t.text =~ /[^\x00-\x7f]/
12
+ add_offence(:convention, t.pos.lineno, ERROR_MESSAGE)
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
@@ -7,34 +7,25 @@ module Rubocop
7
7
  '$:' => '$LOAD_PATH',
8
8
  '$"' => '$LOADED_FEATURES',
9
9
  '$0' => '$PROGRAM_NAME',
10
- '$1' => 'MatchData',
11
- '$2' => 'MatchData',
12
- '$3' => 'MatchData',
13
- '$4' => 'MatchData',
14
- '$5' => 'MatchData',
15
- '$6' => 'MatchData',
16
- '$7' => 'MatchData',
17
- '$8' => 'MatchData',
18
- '$9' => 'MatchData',
19
- '$!' => '$ERROR_INFO',
20
- '$@' => '$ERROR_POSITION',
21
- '$;' => '$FIELD_SEPARATOR',
22
- '$,' => '$OUTPUT_FIELD_SEPARATOR',
23
- '$/' => '$INPUT_RECORD_SEPARATOR',
24
- '$\\' => 'OUTPUT_RECORD_SEPARATOR',
25
- '$.' => '$INPUT_LINE_NUMBER',
26
- '$_' => '$LAST_READ_LINE',
27
- '$>' => '$DEFAULT_OUTPUT',
28
- '$<' => '$DEFAULT_INPUT',
29
- '$$' => '$PROCESS_ID',
30
- '$?' => '$CHILD_STATUS',
31
- '$~' => '$LAST_MATCH_INFO',
32
- '$=' => '$IGNORECASE',
33
- '$*' => '$ARGV',
34
- '$&' => '$MATCH',
35
- '$`' => '$PREMATCH',
36
- '$\'' => 'POSTMATCH',
37
- '$+' => '$LAST_PAREN_MATCH'
10
+ '$!' => '$ERROR_INFO from English library',
11
+ '$@' => '$ERROR_POSITION from English library',
12
+ '$;' => '$FS or $FIELD_SEPARATOR from English library',
13
+ '$,' => '$OFS or $OUTPUT_FIELD_SEPARATOR from English library',
14
+ '$/' => '$RS or $INPUT_RECORD_SEPARATOR from English library',
15
+ '$\\' => '$ORS or $OUTPUT_RECORD_SEPARATOR from English library',
16
+ '$.' => '$NR or $INPUT_LINE_NUMBER from English library',
17
+ '$_' => '$LAST_READ_LINE from English library',
18
+ '$>' => '$DEFAULT_OUTPUT from English library',
19
+ '$<' => '$DEFAULT_INPUT from English library',
20
+ '$$' => '$PID or $PROCESS_ID from English library',
21
+ '$?' => '$CHILD_STATUS from English library',
22
+ '$~' => '$LAST_MATCH_INFO from English library',
23
+ '$=' => '$IGNORECASE from English library',
24
+ '$*' => '$ARGV from English library or ARGV constant',
25
+ '$&' => '$MATCH from English library',
26
+ '$`' => '$PREMATCH from English library',
27
+ '$\'' => '$POSTMATCH from English library',
28
+ '$+' => '$LAST_PAREN_MATCH from English library'
38
29
  }
39
30
 
40
31
  def inspect(file, source, tokens, sexp)