rubocop 0.6.1 → 0.7.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 (87) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +4 -266
  3. data/CHANGELOG.md +49 -7
  4. data/README.md +75 -2
  5. data/Rakefile +2 -2
  6. data/bin/rubocop +15 -10
  7. data/lib/rubocop.rb +19 -1
  8. data/lib/rubocop/cli.rb +113 -116
  9. data/lib/rubocop/config.rb +202 -0
  10. data/lib/rubocop/config_store.rb +37 -0
  11. data/lib/rubocop/cop/alias.rb +2 -5
  12. data/lib/rubocop/cop/align_parameters.rb +1 -1
  13. data/lib/rubocop/cop/array_literal.rb +43 -4
  14. data/lib/rubocop/cop/avoid_for.rb +2 -4
  15. data/lib/rubocop/cop/avoid_global_vars.rb +49 -0
  16. data/lib/rubocop/cop/block_comments.rb +17 -0
  17. data/lib/rubocop/cop/brace_after_percent.rb +9 -5
  18. data/lib/rubocop/cop/{indentation.rb → case_indentation.rb} +1 -1
  19. data/lib/rubocop/cop/class_methods.rb +20 -0
  20. data/lib/rubocop/cop/colon_method_call.rb +44 -0
  21. data/lib/rubocop/cop/cop.rb +30 -2
  22. data/lib/rubocop/cop/def_parentheses.rb +1 -1
  23. data/lib/rubocop/cop/empty_line_between_defs.rb +26 -0
  24. data/lib/rubocop/cop/empty_lines.rb +10 -13
  25. data/lib/rubocop/cop/eval.rb +22 -0
  26. data/lib/rubocop/cop/favor_join.rb +37 -0
  27. data/lib/rubocop/cop/grammar.rb +2 -2
  28. data/lib/rubocop/cop/hash_literal.rb +43 -4
  29. data/lib/rubocop/cop/hash_syntax.rb +2 -2
  30. data/lib/rubocop/cop/if_then_else.rb +1 -1
  31. data/lib/rubocop/cop/leading_comment_space.rb +20 -0
  32. data/lib/rubocop/cop/line_continuation.rb +18 -0
  33. data/lib/rubocop/cop/line_length.rb +1 -1
  34. data/lib/rubocop/cop/method_and_variable_snake_case.rb +7 -6
  35. data/lib/rubocop/cop/method_length.rb +4 -15
  36. data/lib/rubocop/cop/not.rb +15 -0
  37. data/lib/rubocop/cop/offence.rb +9 -0
  38. data/lib/rubocop/cop/semicolon.rb +74 -3
  39. data/lib/rubocop/cop/single_line_methods.rb +60 -0
  40. data/lib/rubocop/cop/space_after_control_keyword.rb +28 -0
  41. data/lib/rubocop/cop/surrounding_space.rb +48 -9
  42. data/lib/rubocop/cop/symbol_array.rb +29 -0
  43. data/lib/rubocop/cop/trivial_accessors.rb +103 -0
  44. data/lib/rubocop/cop/unless_else.rb +1 -1
  45. data/lib/rubocop/cop/variable_interpolation.rb +3 -2
  46. data/lib/rubocop/cop/word_array.rb +38 -0
  47. data/lib/rubocop/version.rb +1 -1
  48. data/rubocop.gemspec +11 -7
  49. data/spec/project_spec.rb +27 -0
  50. data/spec/rubocop/cli_spec.rb +549 -487
  51. data/spec/rubocop/config_spec.rb +399 -0
  52. data/spec/rubocop/config_store_spec.rb +66 -0
  53. data/spec/rubocop/cops/alias_spec.rb +7 -0
  54. data/spec/rubocop/cops/array_literal_spec.rb +8 -1
  55. data/spec/rubocop/cops/avoid_for_spec.rb +15 -1
  56. data/spec/rubocop/cops/avoid_global_vars.rb +32 -0
  57. data/spec/rubocop/cops/block_comments_spec.rb +29 -0
  58. data/spec/rubocop/cops/brace_after_percent_spec.rb +19 -13
  59. data/spec/rubocop/cops/{indentation_spec.rb → case_indentation_spec.rb} +2 -2
  60. data/spec/rubocop/cops/class_methods_spec.rb +49 -0
  61. data/spec/rubocop/cops/colon_method_call_spec.rb +47 -0
  62. data/spec/rubocop/cops/empty_line_between_defs_spec.rb +83 -0
  63. data/spec/rubocop/cops/empty_lines_spec.rb +6 -63
  64. data/spec/rubocop/cops/eval_spec.rb +36 -0
  65. data/spec/rubocop/cops/favor_join_spec.rb +39 -0
  66. data/spec/rubocop/cops/hash_literal_spec.rb +8 -1
  67. data/spec/rubocop/cops/leading_comment_space_spec.rb +60 -0
  68. data/spec/rubocop/cops/line_continuation_spec.rb +24 -0
  69. data/spec/rubocop/cops/line_length_spec.rb +1 -0
  70. data/spec/rubocop/cops/method_and_variable_snake_case_spec.rb +20 -0
  71. data/spec/rubocop/cops/method_length_spec.rb +2 -5
  72. data/spec/rubocop/cops/new_lambda_literal_spec.rb +2 -3
  73. data/spec/rubocop/cops/not_spec.rb +34 -0
  74. data/spec/rubocop/cops/offence_spec.rb +7 -0
  75. data/spec/rubocop/cops/semicolon_spec.rb +79 -4
  76. data/spec/rubocop/cops/single_line_methods_spec.rb +50 -0
  77. data/spec/rubocop/cops/space_after_control_keyword_spec.rb +28 -0
  78. data/spec/rubocop/cops/space_around_equals_in_default_parameter_spec.rb +11 -1
  79. data/spec/rubocop/cops/space_inside_hash_literal_braces_spec.rb +74 -0
  80. data/spec/rubocop/cops/symbol_array_spec.rb +25 -0
  81. data/spec/rubocop/cops/trivial_accessors_spec.rb +332 -0
  82. data/spec/rubocop/cops/variable_interpolation_spec.rb +10 -1
  83. data/spec/rubocop/cops/word_array_spec.rb +39 -0
  84. data/spec/spec_helper.rb +16 -9
  85. data/spec/support/file_helper.rb +21 -0
  86. data/spec/support/isolated_environment.rb +27 -0
  87. metadata +66 -6
@@ -0,0 +1,399 @@
1
+ # encoding: utf-8
2
+
3
+ require 'spec_helper'
4
+
5
+ DEFAULT_CONFIG = Rubocop::Config.load_file('config/default.yml')
6
+
7
+ describe Rubocop::Config do
8
+ include FileHelper
9
+
10
+ subject(:configuration) { Rubocop::Config.new(hash, loaded_path) }
11
+ let(:hash) { {} }
12
+ let(:loaded_path) { 'example/.rubocop.yml' }
13
+
14
+ before { Rubocop::ConfigStore.prepare }
15
+
16
+ describe '.configuration_file_for', :isolated_environment do
17
+ subject(:configuration_file_for) do
18
+ Rubocop::Config.configuration_file_for(dir_path)
19
+ end
20
+
21
+ context 'when no config file exists in ancestor directories' do
22
+ let(:dir_path) { 'dir' }
23
+ before { create_file('dir/example.rb', '') }
24
+
25
+ context 'but a config file exists in home directory' do
26
+ before { create_file('~/.rubocop.yml', '') }
27
+
28
+ it 'returns the path to the file in home directory' do
29
+ expect(configuration_file_for).to end_with('home/.rubocop.yml')
30
+ end
31
+ end
32
+
33
+ context 'and no config file exists in home directory' do
34
+ it 'falls back to the provided default file' do
35
+ expect(configuration_file_for).to end_with('config/default.yml')
36
+ end
37
+ end
38
+ end
39
+
40
+ context 'when a config file exists in the parent directory' do
41
+ let(:dir_path) { 'dir' }
42
+
43
+ before do
44
+ create_file('dir/example.rb', '')
45
+ create_file('.rubocop.yml', '')
46
+ end
47
+
48
+ it 'returns the path to that configuration file' do
49
+ expect(configuration_file_for).to end_with('work/.rubocop.yml')
50
+ end
51
+ end
52
+
53
+ context 'when multiple config files exist in ancestor directories' do
54
+ let(:dir_path) { 'dir' }
55
+
56
+ before do
57
+ create_file('dir/example.rb', '')
58
+ create_file('dir/.rubocop.yml', '')
59
+ create_file('.rubocop.yml', '')
60
+ end
61
+
62
+ it 'prefers closer config file' do
63
+ expect(configuration_file_for).to end_with('dir/.rubocop.yml')
64
+ end
65
+ end
66
+ end
67
+
68
+ describe '.configuration_from_file', :isolated_environment do
69
+ subject(:configuration_from_file) do
70
+ Rubocop::Config.configuration_from_file(file_path)
71
+ end
72
+
73
+ context 'with any config file' do
74
+ let(:file_path) { '.rubocop.yml' }
75
+
76
+ before do
77
+ create_file(file_path, ['Encoding:',
78
+ ' Enabled: false'])
79
+ end
80
+
81
+ it 'returns a configuration inheriting from default.yml' do
82
+ expect(configuration_from_file)
83
+ .to eq(DEFAULT_CONFIG.merge('Encoding' => { 'Enabled' => false }))
84
+ end
85
+ end
86
+
87
+ context 'when a file inherits from a parent and grandparent file' do
88
+ let(:file_path) { 'dir/subdir/.rubocop.yml' }
89
+
90
+ before do
91
+ create_file('dir/subdir/example.rb', '')
92
+
93
+ create_file('.rubocop.yml',
94
+ ['LineLength:',
95
+ ' Enabled: false',
96
+ ' Max: 77'])
97
+
98
+ create_file('dir/.rubocop.yml',
99
+ ['inherit_from: ../.rubocop.yml',
100
+ '',
101
+ 'MethodLength:',
102
+ ' Enabled: true',
103
+ ' CountComments: false',
104
+ ' Max: 10'
105
+ ])
106
+
107
+ create_file(file_path,
108
+ ['inherit_from: ../.rubocop.yml',
109
+ '',
110
+ 'LineLength:',
111
+ ' Enabled: true',
112
+ '',
113
+ 'MethodLength:',
114
+ ' Max: 5'
115
+ ])
116
+ end
117
+
118
+ it 'returns the ancestor configuration plus local overrides' do
119
+ expect(configuration_from_file)
120
+ .to eq(DEFAULT_CONFIG.merge('LineLength' => {
121
+ 'Enabled' => true,
122
+ 'Max' => 77
123
+ },
124
+ 'MethodLength' => {
125
+ 'Enabled' => true,
126
+ 'CountComments' => false,
127
+ 'Max' => 5
128
+ }))
129
+ end
130
+ end
131
+
132
+ context 'when a file inherits from two configurations' do
133
+ let(:file_path) { '.rubocop.yml' }
134
+
135
+ before do
136
+ create_file('example.rb', '')
137
+
138
+ create_file('normal.yml',
139
+ ['MethodLength:',
140
+ ' Enabled: false',
141
+ ' CountComments: true',
142
+ ' Max: 79'])
143
+
144
+ create_file('special.yml',
145
+ ['MethodLength:',
146
+ ' Enabled: false',
147
+ ' Max: 200'])
148
+
149
+ create_file(file_path,
150
+ ['inherit_from:',
151
+ ' - normal.yml',
152
+ ' - special.yml',
153
+ '',
154
+ 'MethodLength:',
155
+ ' Enabled: true'
156
+ ])
157
+ end
158
+
159
+ it 'returns values from the last one when possible' do
160
+ expect(configuration_from_file['MethodLength'])
161
+ .to eq('Enabled' => true, # overridden in .rubocop.yml
162
+ 'CountComments' => true, # only defined in normal.yml
163
+ 'Max' => 200 # special.yml takes precedence
164
+ )
165
+ end
166
+ end
167
+ end
168
+
169
+ describe '.load_file', :isolated_environment do
170
+ subject(:load_file) do
171
+ Rubocop::Config.load_file(configuration_path)
172
+ end
173
+
174
+ let(:configuration_path) { '.rubocop.yml' }
175
+
176
+ it 'returns a configuration loaded from the passed path' do
177
+ create_file(configuration_path, [
178
+ 'Encoding:',
179
+ ' Enabled: true',
180
+ ])
181
+ configuration = load_file
182
+ expect(configuration['Encoding']).to eq({
183
+ 'Enabled' => true
184
+ })
185
+ end
186
+ end
187
+
188
+ describe '.merge' do
189
+ subject(:merge) { Rubocop::Config.merge(base, derived) }
190
+
191
+ let(:base) do
192
+ {
193
+ 'AllCops' => {
194
+ 'Includes' => ['**/*.gemspec', '**/Rakefile'],
195
+ 'Excludes' => []
196
+ }
197
+ }
198
+ end
199
+ let(:derived) do
200
+ { 'AllCops' => { 'Excludes' => ['example.rb', 'exclude_*'] } }
201
+ end
202
+
203
+ it 'returns a recursive merge of its two arguments' do
204
+ expect(merge).to eq('AllCops' => {
205
+ 'Includes' => ['**/*.gemspec', '**/Rakefile'],
206
+ 'Excludes' => ['example.rb', 'exclude_*']
207
+ })
208
+ end
209
+ end
210
+
211
+ describe '#validate!', :isolated_environment do
212
+ # TODO: Because Config.load_file now outputs the validation warning,
213
+ # it is inserting text into the rspec test output here.
214
+ # The next 2 lines should be removed eventually.
215
+ before(:each) { $stdout = StringIO.new }
216
+ after(:each) { $stdout = STDOUT }
217
+
218
+ subject(:configuration) do
219
+ Rubocop::Config.load_file(configuration_path)
220
+ end
221
+
222
+ let(:configuration_path) { '.rubocop.yml' }
223
+
224
+ context 'when the configuration includes any unrecognized cop name' do
225
+ before do
226
+ create_file(configuration_path, [
227
+ 'LyneLenth:',
228
+ ' Enabled: true',
229
+ ' Max: 100',
230
+ ])
231
+ end
232
+
233
+ it 'raises validation error' do
234
+ expect do
235
+ configuration.validate!
236
+ end.to raise_error(Rubocop::Config::ValidationError) do |error|
237
+ expect(error.message).to start_with('unrecognized cop LyneLenth')
238
+ end
239
+ end
240
+ end
241
+
242
+ context 'when the configuration includes any unrecognized parameter' do
243
+ before do
244
+ create_file(configuration_path, [
245
+ 'LineLength:',
246
+ ' Enabled: true',
247
+ ' Min: 10',
248
+ ])
249
+ end
250
+
251
+ it 'raises validation error' do
252
+ expect do
253
+ configuration.validate!
254
+ end.to raise_error(Rubocop::Config::ValidationError) do |error|
255
+ expect(error.message).to
256
+ start_with('unrecognized parameter LineLength:Min')
257
+ end
258
+ end
259
+ end
260
+ end
261
+
262
+ describe '#file_to_include?' do
263
+ let(:hash) do
264
+ {
265
+ 'AllCops' => {
266
+ 'Includes' => ['Gemfile', 'config/unicorn.rb.example']
267
+ }
268
+ }
269
+ end
270
+
271
+ let(:loaded_path) { '/home/foo/project/.rubocop.yml' }
272
+
273
+ context 'when the passed path matches any of patterns to include' do
274
+ it 'returns true' do
275
+ file_path = '/home/foo/project/Gemfile'
276
+ expect(configuration.file_to_include?(file_path)).to be_true
277
+ end
278
+ end
279
+
280
+ context 'when the passed path does not match any of patterns to include' do
281
+ it 'returns false' do
282
+ file_path = '/home/foo/project/Gemfile.lock'
283
+ expect(configuration.file_to_include?(file_path)).to be_false
284
+ end
285
+ end
286
+ end
287
+
288
+ describe '#file_to_exclude?' do
289
+ let(:hash) do
290
+ {
291
+ 'AllCops' => {
292
+ 'Excludes' => ['log/*']
293
+ }
294
+ }
295
+ end
296
+
297
+ let(:loaded_path) { '/home/foo/project/.rubocop.yml' }
298
+
299
+ context 'when the passed path matches any of patterns to exclude' do
300
+ it 'returns true' do
301
+ file_path = '/home/foo/project/log/foo.rb'
302
+ expect(configuration.file_to_exclude?(file_path)).to be_true
303
+ end
304
+ end
305
+
306
+ context 'when the passed path does not match any of patterns to exclude' do
307
+ it 'returns false' do
308
+ file_path = '/home/foo/project/log_file.rb'
309
+ expect(configuration.file_to_exclude?(file_path)).to be_false
310
+ end
311
+ end
312
+ end
313
+
314
+ describe '#patterns_to_include' do
315
+ subject(:patterns_to_include) do
316
+ configuration = Rubocop::Config.new(hash, loaded_path)
317
+ configuration.patterns_to_include
318
+ end
319
+
320
+ let(:hash) { {} }
321
+ let(:loaded_path) { 'example/.rubocop.yml' }
322
+
323
+ context 'when config file has AllCops => Includes key' do
324
+ let(:hash) do
325
+ {
326
+ 'AllCops' => {
327
+ 'Includes' => ['Gemfile', 'config/unicorn.rb.example']
328
+ }
329
+ }
330
+ end
331
+
332
+ it 'returns the Includes value' do
333
+ expect(patterns_to_include).to eq([
334
+ 'Gemfile',
335
+ 'config/unicorn.rb.example'
336
+ ])
337
+ end
338
+ end
339
+ end
340
+
341
+ describe '#patterns_to_exclude' do
342
+ subject(:patterns_to_exclude) do
343
+ configuration = Rubocop::Config.new(hash, loaded_path)
344
+ configuration.patterns_to_exclude
345
+ end
346
+
347
+ let(:hash) { {} }
348
+ let(:loaded_path) { 'example/.rubocop.yml' }
349
+
350
+ context 'when config file has AllCops => Excludes key' do
351
+ let(:hash) do
352
+ {
353
+ 'AllCops' => {
354
+ 'Excludes' => ['log/*']
355
+ }
356
+ }
357
+ end
358
+
359
+ it 'returns the Excludes value' do
360
+ expect(patterns_to_exclude).to eq(['log/*'])
361
+ end
362
+ end
363
+ end
364
+
365
+ describe 'configuration for SymbolArray', :isolated_environment do
366
+ before do
367
+ create_file('example.rb', '# encoding: utf-8')
368
+ end
369
+
370
+ context 'when no config file exists for the target file' do
371
+ it 'is disabled' do
372
+ configuration = Rubocop::ConfigStore.for('example.rb')
373
+ expect(configuration.cop_enabled?('SymbolArray')).to be_false
374
+ end
375
+ end
376
+
377
+ context 'when a config file which does not mention SymbolArray exists' do
378
+ it 'is disabled' do
379
+ create_file('.rubocop.yml', [
380
+ 'LineLength:',
381
+ ' Max: 79'
382
+ ])
383
+ configuration = Rubocop::ConfigStore.for('example.rb')
384
+ expect(configuration.cop_enabled?('SymbolArray')).to be_false
385
+ end
386
+ end
387
+
388
+ context 'when a config file which explicitly enables SymbolArray exists' do
389
+ it 'is enabled' do
390
+ create_file('.rubocop.yml', [
391
+ 'SymbolArray:',
392
+ ' Enabled: true'
393
+ ])
394
+ configuration = Rubocop::ConfigStore.for('example.rb')
395
+ expect(configuration.cop_enabled?('SymbolArray')).to be_true
396
+ end
397
+ end
398
+ end
399
+ end
@@ -0,0 +1,66 @@
1
+ # encoding: utf-8
2
+
3
+ require 'spec_helper'
4
+
5
+ module Rubocop
6
+ describe ConfigStore do
7
+ before(:each) { ConfigStore.prepare }
8
+ before do
9
+ Config.stub(:configuration_file_for) do |arg|
10
+ # File tree:
11
+ # file1
12
+ # dir/.rubocop.yml
13
+ # dir/file2
14
+ # dir/subdir/file3
15
+ (arg =~ /dir/ ? 'dir' : '.') + '/.rubocop.yml'
16
+ end
17
+ Config.stub(:configuration_from_file) { |arg| arg }
18
+ Config.stub(:load_file) { |arg| "#{arg} loaded" }
19
+ Config.stub(:merge_with_default) { |config, file| "merged #{config}" }
20
+ end
21
+
22
+ describe '.prepare' do
23
+ it 'resets @options_config' do
24
+ ConfigStore.set_options_config(:options_config)
25
+ ConfigStore.prepare
26
+ Config.should_receive(:configuration_file_for)
27
+ ConfigStore.for('file1')
28
+ end
29
+
30
+ it 'resets @config_cache' do
31
+ ConfigStore.for('file1')
32
+ ConfigStore.prepare
33
+ Config.should_receive(:configuration_file_for)
34
+ ConfigStore.for('file1')
35
+ end
36
+ end
37
+
38
+ describe '.for' do
39
+ it 'always uses config specified in command line' do
40
+ ConfigStore.set_options_config(:options_config)
41
+ expect(ConfigStore.for('file1')).to eq('merged options_config loaded')
42
+ end
43
+
44
+ context 'when no config specified in command line' do
45
+ it 'gets config path and config from cache if available' do
46
+ Config.should_receive(:configuration_file_for).once.with('dir')
47
+ Config.should_receive(:configuration_file_for).once.with('dir/' +
48
+ 'subdir')
49
+ # The stub returns the same config path for dir and dir/subdir.
50
+ Config.should_receive(:configuration_from_file).once.
51
+ with('dir/.rubocop.yml')
52
+
53
+ ConfigStore.for('dir/file2')
54
+ ConfigStore.for('dir/file2')
55
+ ConfigStore.for('dir/subdir/file3')
56
+ end
57
+
58
+ it 'searches for config path if not available in cache' do
59
+ Config.should_receive(:configuration_file_for).once
60
+ Config.should_receive(:configuration_from_file).once
61
+ ConfigStore.for('file1')
62
+ end
63
+ end
64
+ end
65
+ end
66
+ end