rubocop 0.13.0 → 0.13.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.

Files changed (35) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +18 -0
  3. data/config/default.yml +4 -0
  4. data/config/enabled.yml +13 -9
  5. data/lib/rubocop.rb +5 -1
  6. data/lib/rubocop/backports/bsearch.rb +39 -0
  7. data/lib/rubocop/cop/lint/useless_comparison.rb +2 -0
  8. data/lib/rubocop/cop/lint/useless_setter_call.rb +88 -13
  9. data/lib/rubocop/cop/style/align_array.rb +2 -20
  10. data/lib/rubocop/cop/style/align_parameters.rb +2 -20
  11. data/lib/rubocop/cop/style/ascii_comments.rb +1 -1
  12. data/lib/rubocop/cop/style/ascii_identifiers.rb +1 -1
  13. data/lib/rubocop/cop/style/autocorrect_alignment.rb +32 -0
  14. data/lib/rubocop/cop/style/character_literal.rb +5 -13
  15. data/lib/rubocop/cop/style/final_newline.rb +2 -2
  16. data/lib/rubocop/cop/style/hash_syntax.rb +10 -3
  17. data/lib/rubocop/cop/style/lambda_call.rb +39 -0
  18. data/lib/rubocop/cop/style/nil_comparison.rb +2 -0
  19. data/lib/rubocop/cop/style/redundant_self.rb +48 -2
  20. data/lib/rubocop/cop/style/string_help.rb +27 -0
  21. data/lib/rubocop/cop/style/string_literals.rb +5 -13
  22. data/lib/rubocop/cop/style/surrounding_space.rb +17 -5
  23. data/lib/rubocop/version.rb +1 -1
  24. data/rubocop.gemspec +0 -1
  25. data/spec/rubocop/cli_spec.rb +909 -914
  26. data/spec/rubocop/cop/lint/useless_comparison_spec.rb +5 -0
  27. data/spec/rubocop/cop/lint/useless_setter_call_spec.rb +41 -0
  28. data/spec/rubocop/cop/style/final_newline_spec.rb +6 -0
  29. data/spec/rubocop/cop/style/hash_syntax_spec.rb +26 -21
  30. data/spec/rubocop/cop/style/lambda_call_spec.rb +29 -0
  31. data/spec/rubocop/cop/style/nil_comparison_spec.rb +5 -0
  32. data/spec/rubocop/cop/style/redundant_self_spec.rb +18 -0
  33. data/spec/rubocop/cop/style/space_around_block_braces_spec.rb +68 -0
  34. metadata +20 -50
  35. data/spec/rubocop/cop/style/space_around_braces_spec.rb +0 -50
@@ -5,24 +5,16 @@ module Rubocop
5
5
  module Style
6
6
  # Checks for uses of the character literal ?x.
7
7
  class CharacterLiteral < Cop
8
- MSG = 'Do not use the character literal - use string literal instead.'
8
+ include StringHelp
9
9
 
10
- def on_str(node)
11
- # Constants like __FILE__ are handled as strings,
12
- # but don't respond to begin.
13
- return unless node.loc.respond_to?(:begin) && node.loc.begin
14
- return if part_of_ignored_node?(node)
10
+ MSG = 'Do not use the character literal - use string literal instead.'
15
11
 
12
+ def offence?(node)
16
13
  # we don't register an offence for things like ?\C-\M-d
17
- if node.loc.begin.is?('?') &&
18
- node.loc.expression.source.size.between?(2, 3)
19
- convention(node, :expression)
20
- end
14
+ node.loc.begin.is?('?') &&
15
+ node.loc.expression.source.size.between?(2, 3)
21
16
  end
22
17
 
23
- alias_method :on_dstr, :ignore_node
24
- alias_method :on_regexp, :ignore_node
25
-
26
18
  def autocorrect_action(node)
27
19
  @corrections << lambda do |corrector|
28
20
  string = node.loc.expression.source[1..-1]
@@ -5,12 +5,12 @@ module Rubocop
5
5
  module Style
6
6
  # This cop enforces the presence of a final newline in each source file.
7
7
  class FinalNewline < Cop
8
- MSG = 'Source files should end with a newline(\n).'
8
+ MSG = 'Source files should end with a newline (\n).'
9
9
 
10
10
  def investigate(processed_source)
11
11
  final_line = processed_source.raw_lines.to_a.last
12
12
 
13
- unless final_line.end_with?("\n")
13
+ unless final_line.nil? || final_line.end_with?("\n")
14
14
  convention(nil,
15
15
  source_range(processed_source.buffer,
16
16
  processed_source[0...-1],
@@ -18,14 +18,21 @@ module Rubocop
18
18
  if sym_indices
19
19
  pairs.each do |pair|
20
20
  if pair.loc.operator && pair.loc.operator.is?('=>')
21
- convention(nil,
22
- pair.loc.expression.begin.join(pair.loc.operator),
23
- MSG)
21
+ convention(pair,
22
+ pair.loc.expression.begin.join(pair.loc.operator))
24
23
  end
25
24
  end
26
25
  end
27
26
  end
28
27
 
28
+ def autocorrect_action(node)
29
+ @corrections << lambda do |corrector|
30
+ replacement = node.loc.expression.source[1..-1]
31
+ .sub(/\s*=>\s*/, ': ')
32
+ corrector.replace(node.loc.expression, replacement)
33
+ end
34
+ end
35
+
29
36
  private
30
37
 
31
38
  def word_symbol_pair?(pair)
@@ -0,0 +1,39 @@
1
+ # encoding: utf-8
2
+
3
+ module Rubocop
4
+ module Cop
5
+ module Style
6
+ # This cop checks for use of the lambda.(args) syntax.
7
+ #
8
+ # @example
9
+ #
10
+ # # bad
11
+ # lambda.(x, y)
12
+ #
13
+ # # good
14
+ # lambda.call(x, y)
15
+ class LambdaCall < Cop
16
+ MSG = 'Prefer the use of `lambda.call(...)` over `lambda.(...)`.'
17
+
18
+ def on_send(node)
19
+ _receiver, selector, = *node
20
+
21
+ # lambda.() does not have a selector
22
+ return unless selector == :call && node.loc.selector.nil?
23
+
24
+ convention(node, :expression)
25
+ end
26
+
27
+ def autocorrect_action(node)
28
+ @corrections << lambda do |corrector|
29
+ receiver_node, = *node
30
+ expr = node.loc.expression
31
+ receiver = receiver_node.loc.expression.source
32
+ replacement = expr.source.sub("#{receiver}.", "#{receiver}.call")
33
+ corrector.replace(expr, replacement)
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
@@ -22,6 +22,8 @@ module Rubocop
22
22
  NIL_NODE = s(:nil)
23
23
 
24
24
  def on_send(node)
25
+ # lambda.() does not have a selector
26
+ return unless node.loc.selector
25
27
  op = node.loc.selector.source
26
28
 
27
29
  if OPS.include?(op)
@@ -3,8 +3,40 @@
3
3
  module Rubocop
4
4
  module Cop
5
5
  module Style
6
- # This cop checks for redundant uses of `self`. It is only needed when
7
- # calling a write accessor on self.
6
+ # This cop checks for redundant uses of `self`.
7
+ #
8
+ # `self` is only needed when:
9
+ #
10
+ # * Sending a message to same object with zero arguments in
11
+ # presence of a method name clash with an argument or a local
12
+ # variable.
13
+ #
14
+ # Note, with using explicit self you can only send messages
15
+ # with public or protected scope, you cannot send private
16
+ # messages this way.
17
+ #
18
+ # Example:
19
+ #
20
+ # def bar
21
+ # :baz
22
+ # end
23
+ #
24
+ # def foo(bar)
25
+ # self.bar # resolves name clash with argument
26
+ # end
27
+ #
28
+ # def foo2
29
+ # bar = 1
30
+ # self.bar # resolves name class with local variable
31
+ # end
32
+ #
33
+ # * Calling an attribute writer to prevent an local variable assignment
34
+ #
35
+ # attr_writer :bar
36
+ #
37
+ # def foo
38
+ # self.bar= 1 # Make sure above attr writer is called
39
+ # end
8
40
  #
9
41
  # Special cases:
10
42
  #
@@ -43,6 +75,14 @@ module Rubocop
43
75
  @local_variables = []
44
76
  end
45
77
 
78
+ def on_arg(node)
79
+ on_argument(node)
80
+ end
81
+
82
+ def on_blockarg(node)
83
+ on_argument(node)
84
+ end
85
+
46
86
  def on_lvasgn(node)
47
87
  lhs, _rhs = *node
48
88
  @local_variables << lhs
@@ -70,6 +110,11 @@ module Rubocop
70
110
 
71
111
  private
72
112
 
113
+ def on_argument(node)
114
+ name, _ = *node
115
+ @local_variables << name
116
+ end
117
+
73
118
  def operator?(method_name)
74
119
  method_name.to_s =~ /\W/
75
120
  end
@@ -88,6 +133,7 @@ module Rubocop
88
133
  @allowed_send_nodes << node if receiver && receiver.type == :self
89
134
  end
90
135
  end
136
+
91
137
  end
92
138
  end
93
139
  end
@@ -0,0 +1,27 @@
1
+ # encoding: utf-8
2
+
3
+ module Rubocop
4
+ module Cop
5
+ module Style
6
+ # Checks for uses of double quotes where single quotes would do.
7
+ module StringHelp
8
+ def on_str(node)
9
+ # Constants like __FILE__ are handled as strings,
10
+ # but don't respond to begin.
11
+ return unless node.loc.respond_to?(:begin) && node.loc.begin
12
+ return if part_of_ignored_node?(node)
13
+
14
+ convention(node, :expression) if offence?(node)
15
+ end
16
+
17
+ def on_dstr(node)
18
+ ignore_node(node)
19
+ end
20
+
21
+ def on_regexp(node)
22
+ ignore_node(node)
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -5,27 +5,19 @@ module Rubocop
5
5
  module Style
6
6
  # Checks for uses of double quotes where single quotes would do.
7
7
  class StringLiterals < Cop
8
+ include StringHelp
9
+
8
10
  MSG = "Prefer single-quoted strings when you don't need " +
9
11
  'string interpolation or special symbols.'
10
12
 
11
- def on_str(node)
12
- # Constants like __FILE__ are handled as strings,
13
- # but don't respond to begin.
14
- return unless node.loc.respond_to?(:begin)
15
- return if part_of_ignored_node?(node)
16
-
13
+ def offence?(node)
17
14
  # regex matches IF there is a ' or there is a \\ in the string that
18
15
  # is not preceeded/followed by another \\ (e.g. "\\x34") but not
19
16
  # "\\\\"
20
- if node.loc.expression.source !~ /' | (?<! \\) \\{2}* \\ (?! \\)/x &&
21
- node.loc.begin && node.loc.begin.is?('"')
22
- convention(node, :expression)
23
- end
17
+ node.loc.expression.source !~ /' | (?<! \\) \\{2}* \\ (?! \\)/x &&
18
+ node.loc.begin && node.loc.begin.is?('"')
24
19
  end
25
20
 
26
- alias_method :on_dstr, :ignore_node
27
- alias_method :on_regexp, :ignore_node
28
-
29
21
  def autocorrect_action(node)
30
22
  @corrections << lambda do |corrector|
31
23
  corrector.replace(node.loc.begin, "'")
@@ -174,11 +174,14 @@ module Rubocop
174
174
  end
175
175
  end
176
176
 
177
- # Checks that block braces have surrounding space.
178
- class SpaceAroundBraces < Cop
177
+ # Checks that block braces have surrounding space. For blocks taking
178
+ # parameters, it check that the left brace has or doesn't have trailing
179
+ # space depending on configuration.
180
+ class SpaceAroundBlockBraces < Cop
179
181
  include SurroundingSpace
180
182
  MSG_LEFT = "Surrounding space missing for '{'."
181
183
  MSG_RIGHT = "Space missing to the left of '}'."
184
+ MSG_PIPE = 'Space between { and | detected.'
182
185
 
183
186
  def investigate(processed_source)
184
187
  return unless processed_source.ast
@@ -188,9 +191,14 @@ module Rubocop
188
191
  next if ([t1.pos, t2.pos] - positions_not_to_check).size < 2
189
192
 
190
193
  type1, type2 = t1.type, t2.type
191
- # :tLBRACE in hash literals, :tLCURLY otherwise.
192
- next if [:tLCURLY, :tLBRACE].include?(type1) && type2 == :tRCURLY
193
- check(t1, t2, MSG_LEFT) if type1 == :tLCURLY || type2 == :tLCURLY
194
+ check(t1, t2, MSG_LEFT) if type2 == :tLCURLY
195
+ if type1 == :tLCURLY
196
+ if type2 == :tPIPE && cop_config['NoSpaceBeforeBlockParameters']
197
+ check_pipe(t1, t2, MSG_PIPE)
198
+ else
199
+ check(t1, t2, MSG_LEFT)
200
+ end
201
+ end
194
202
  check(t1, t2, MSG_RIGHT) if type2 == :tRCURLY
195
203
  end
196
204
  end
@@ -227,6 +235,10 @@ module Rubocop
227
235
  convention(nil, brace_token.pos, msg)
228
236
  end
229
237
  end
238
+
239
+ def check_pipe(t1, t2, msg)
240
+ convention(nil, t1.pos, msg) if space_between?(t1, t2)
241
+ end
230
242
  end
231
243
 
232
244
  # Common functionality for checking for spaces inside various
@@ -3,7 +3,7 @@
3
3
  module Rubocop
4
4
  # This module holds the RuboCop version information.
5
5
  module Version
6
- STRING = '0.13.0'
6
+ STRING = '0.13.1'
7
7
 
8
8
  MSG = '%s (using Parser %s, running on %s %s %s)'
9
9
 
data/rubocop.gemspec CHANGED
@@ -28,7 +28,6 @@ Gem::Specification.new do |s|
28
28
 
29
29
  s.add_runtime_dependency('rainbow', '>= 1.1.4')
30
30
  s.add_runtime_dependency('parser', '~> 2.0.0.pre6')
31
- s.add_runtime_dependency('backports', '~> 3.3.3')
32
31
  s.add_runtime_dependency('powerpack', '~> 0.0.6')
33
32
  s.add_development_dependency('rake', '~> 10.1')
34
33
  s.add_development_dependency('rspec', '~> 2.14')
@@ -25,19 +25,20 @@ module Rubocop
25
25
  File.expand_path(path)
26
26
  end
27
27
 
28
- describe '-h/--help option' do
29
- it 'exits cleanly' do
30
- expect { cli.run ['-h'] }.to exit_with_code(0)
31
- expect { cli.run ['--help'] }.to exit_with_code(0)
32
- end
33
-
34
- it 'shows help text' do
35
- begin
36
- cli.run(['--help'])
37
- rescue SystemExit # rubocop:disable HandleExceptions
28
+ describe 'option' do
29
+ describe '-h/--help' do
30
+ it 'exits cleanly' do
31
+ expect { cli.run ['-h'] }.to exit_with_code(0)
32
+ expect { cli.run ['--help'] }.to exit_with_code(0)
38
33
  end
39
34
 
40
- expected_help = <<-END
35
+ it 'shows help text' do
36
+ begin
37
+ cli.run(['--help'])
38
+ rescue SystemExit # rubocop:disable HandleExceptions
39
+ end
40
+
41
+ expected_help = <<-END
41
42
  Usage: rubocop [options] [file1, file2, ...]
42
43
  -d, --debug Display debug info.
43
44
  -c, --config FILE Specify configuration file.
@@ -70,44 +71,514 @@ Usage: rubocop [options] [file1, file2, ...]
70
71
  -V, --verbose-version Display verbose version.
71
72
  END
72
73
 
73
- expect($stdout.string).to eq(expected_help)
74
+ expect($stdout.string).to eq(expected_help)
75
+ end
76
+
77
+ it 'lists all builtin formatters' do
78
+ begin
79
+ cli.run(['--help'])
80
+ rescue SystemExit # rubocop:disable HandleExceptions
81
+ end
82
+
83
+ option_sections = $stdout.string.lines.slice_before(/^\s*-/)
84
+
85
+ format_section = option_sections.find do |lines|
86
+ lines.first =~ /^\s*-f/
87
+ end
88
+
89
+ formatter_keys = format_section.reduce([]) do |keys, line|
90
+ match = line.match(/^[ ]{39}(\[[a-z\]]+)/)
91
+ next keys unless match
92
+ keys << match.captures.first.gsub(/\[|\]/, '')
93
+ end.sort
94
+
95
+ expected_formatter_keys =
96
+ Formatter::FormatterSet::BUILTIN_FORMATTERS_FOR_KEYS.keys.sort
97
+
98
+ expect(formatter_keys).to eq(expected_formatter_keys)
99
+ end
74
100
  end
75
101
 
76
- it 'lists all builtin formatters' do
77
- begin
78
- cli.run(['--help'])
79
- rescue SystemExit # rubocop:disable HandleExceptions
102
+ describe '--version' do
103
+ it 'exits cleanly' do
104
+ expect { cli.run ['-v'] }.to exit_with_code(0)
105
+ expect { cli.run ['--version'] }.to exit_with_code(0)
106
+ expect($stdout.string).to eq((Rubocop::Version::STRING + "\n") * 2)
107
+ end
108
+ end
109
+
110
+ describe '--auto-gen-config' do
111
+ it 'exits with error if asked to re-generate a todo list that is in ' +
112
+ 'use' do
113
+ create_file('example1.rb', ['# encoding: utf-8',
114
+ 'x= 0 ',
115
+ '#' * 85,
116
+ 'y ',
117
+ 'puts x'])
118
+ todo_contents = ['# This configuration was generated with `rubocop' +
119
+ ' --auto-gen-config`',
120
+ '',
121
+ 'LineLength:',
122
+ ' Enabled: false']
123
+ create_file('rubocop-todo.yml', todo_contents)
124
+ expect(IO.read('rubocop-todo.yml'))
125
+ .to eq(todo_contents.join("\n") + "\n")
126
+ create_file('.rubocop.yml', ['inherit_from: rubocop-todo.yml'])
127
+ expect(cli.run(['--auto-gen-config'])).to eq(1)
128
+ expect($stderr.string).to eq('Remove rubocop-todo.yml from the ' +
129
+ 'current configuration before ' +
130
+ "generating it again.\n")
80
131
  end
81
132
 
82
- option_sections = $stdout.string.lines.slice_before(/^\s*-/)
133
+ it 'exits with error if file arguments are given' do
134
+ create_file('example1.rb', ['# encoding: utf-8',
135
+ 'x= 0 ',
136
+ '#' * 85,
137
+ 'y ',
138
+ 'puts x'])
139
+ expect(cli.run(['--auto-gen-config', 'example1.rb'])).to eq(1)
140
+ expect($stderr.string)
141
+ .to eq('--auto-gen-config can not be combined with any other ' +
142
+ "arguments.\n")
143
+ expect($stdout.string).to eq('')
144
+ end
83
145
 
84
- format_section = option_sections.find do |lines|
85
- lines.first =~ /^\s*-f/
146
+ it 'can generate a todo list' do
147
+ create_file('example1.rb', ['# encoding: utf-8',
148
+ 'x= 0 ',
149
+ '#' * 85,
150
+ 'y ',
151
+ 'puts x'])
152
+ create_file('example2.rb', ['# encoding: utf-8',
153
+ "\tx = 0",
154
+ 'puts x'])
155
+ expect(cli.run(['--auto-gen-config'])).to eq(1)
156
+ expect($stderr.string).to eq('')
157
+ expect($stdout.string)
158
+ .to include([
159
+ 'Created rubocop-todo.yml.',
160
+ 'Run rubocop with --config rubocop-todo.yml, or',
161
+ 'add inherit_from: rubocop-todo.yml in a ' +
162
+ '.rubocop.yml file.',
163
+ ''].join("\n"))
164
+ expect(IO.read('rubocop-todo.yml'))
165
+ .to eq(['# This configuration was generated by `rubocop' +
166
+ ' --auto-gen-config`.',
167
+ '# The point is for the user to remove these' +
168
+ ' configuration records',
169
+ '# one by one as the offences are removed from the code ' +
170
+ 'base.',
171
+ '',
172
+ 'LineLength:',
173
+ ' Enabled: false',
174
+ '',
175
+ 'SpaceAroundOperators:',
176
+ ' Enabled: false',
177
+ '',
178
+ 'Tab:',
179
+ ' Enabled: false',
180
+ '',
181
+ 'TrailingWhitespace:',
182
+ ' Enabled: false',
183
+ ''].join("\n"))
86
184
  end
185
+ end
87
186
 
88
- formatter_keys = format_section.reduce([]) do |keys, line|
89
- match = line.match(/^[ ]{39}(\[[a-z\]]+)/)
90
- next keys unless match
91
- keys << match.captures.first.gsub(/\[|\]/, '')
92
- end.sort
187
+ describe '--only' do
188
+ it 'runs just one cop' do
189
+ create_file('example.rb', ['if x== 0 ',
190
+ "\ty",
191
+ 'end'])
192
+ # IfUnlessModifier depends on the configuration of LineLength.
193
+
194
+ expect(cli.run(['--format', 'simple',
195
+ '--only', 'IfUnlessModifier',
196
+ 'example.rb'])).to eq(1)
197
+ expect($stdout.string)
198
+ .to eq(['== example.rb ==',
199
+ 'C: 1: 1: Favor modifier if/unless usage when you ' +
200
+ 'have a single-line body. Another good alternative is ' +
201
+ 'the usage of control flow &&/||.',
202
+ '',
203
+ '1 file inspected, 1 offence detected',
204
+ ''].join("\n"))
205
+ end
93
206
 
94
- expected_formatter_keys =
95
- Formatter::FormatterSet::BUILTIN_FORMATTERS_FOR_KEYS.keys.sort
207
+ it 'exits with error if an incorrect cop name is passed' do
208
+ expect(cli.run(%w(--only 123))).to eq(1)
209
+ expect($stderr.string).to eq("Unrecognized cop name: 123.\n")
210
+ end
211
+ end
96
212
 
97
- expect(formatter_keys).to eq(expected_formatter_keys)
213
+ describe '--lint' do
214
+ it 'runs only lint cops' do
215
+ create_file('example.rb', ['if 0 ',
216
+ "\ty",
217
+ 'end'])
218
+ # IfUnlessModifier depends on the configuration of LineLength.
219
+
220
+ expect(cli.run(['--format', 'simple', '--lint',
221
+ 'example.rb'])).to eq(1)
222
+ expect($stdout.string)
223
+ .to eq(['== example.rb ==',
224
+ 'W: 1: 4: Literal 0 appeared in a condition.',
225
+ '',
226
+ '1 file inspected, 1 offence detected',
227
+ ''].join("\n"))
228
+ end
98
229
  end
99
- end
100
230
 
101
- it 'exits cleanly when -v is used' do
102
- expect { cli.run ['-v'] }.to exit_with_code(0)
103
- expect { cli.run ['--version'] }.to exit_with_code(0)
104
- expect($stdout.string).to eq((Rubocop::Version::STRING + "\n") * 2)
231
+ describe '--show-cops' do
232
+ let(:cops) { Cop::Cop.all }
233
+
234
+ let(:global_conf) do
235
+ config_path = Rubocop::Config.configuration_file_for(Dir.pwd.to_s)
236
+ Rubocop::Config.configuration_from_file(config_path)
237
+ end
238
+
239
+ let(:stdout) { $stdout.string }
240
+
241
+ before do
242
+ expect { cli.run ['--show-cops'] }.to exit_with_code(0)
243
+ end
244
+
245
+ # Extracts the first line out of the description
246
+ def short_description_of_cop(cop)
247
+ desc = full_description_of_cop(cop)
248
+ desc ? desc.lines.first.strip : ''
249
+ end
250
+
251
+ # Gets the full description of the cop or nil if no description is set.
252
+ def full_description_of_cop(cop)
253
+ cop_config = global_conf.for_cop(cop)
254
+ cop_config['Description']
255
+ end
256
+
257
+ it 'prints all available cops and their description' do
258
+ cops.each do |cop|
259
+ expect(stdout).to include cop.cop_name
260
+ expect(stdout).to include short_description_of_cop(cop)
261
+ end
262
+ end
263
+
264
+ it 'prints all types' do
265
+ cops
266
+ .types
267
+ .map(&:to_s)
268
+ .map(&:capitalize)
269
+ .each { |type| expect(stdout).to include(type) }
270
+ end
271
+
272
+ it 'prints all cops in their right type listing' do
273
+ lines = stdout.lines
274
+ lines.slice_before(/Type /).each do |slice|
275
+ types = cops.types.map(&:to_s).map(&:capitalize)
276
+ current = types.delete(slice.shift[/Type '(?<c>[^'']+)'/, 'c'])
277
+ # all cops in their type listing
278
+ cops.with_type(current).each do |cop|
279
+ expect(slice.any? { |l| l.include? cop.cop_name }).to be_true
280
+ end
281
+
282
+ # no cop in wrong type listing
283
+ types.each do |type|
284
+ cops.with_type(type).each do |cop|
285
+ expect(slice.any? { |l| l.include? cop.cop_name }).to be_false
286
+ end
287
+ end
288
+ end
289
+ end
290
+
291
+ it 'prints the current configuration' do
292
+ out = stdout.lines.to_a
293
+ cops.each do |cop|
294
+ conf = global_conf[cop.cop_name].dup
295
+ confstrt =
296
+ out.find_index { |i| i.include?("- #{cop.cop_name}") } + 1
297
+ c = out[confstrt, conf.keys.size].to_s
298
+ conf.delete('Description')
299
+ expect(c).to include(short_description_of_cop(cop))
300
+ conf.each do |k, v|
301
+ # ugly hack to get hash/array content tested
302
+ if v.kind_of?(Hash) || v.kind_of?(Array)
303
+ expect(c).to include "#{k}: #{v.to_s.dump[2, -2]}"
304
+ else
305
+ expect(c).to include "#{k}: #{v}"
306
+ end
307
+ end
308
+ end
309
+ end
310
+ end
311
+
312
+ describe '-d/--debug' do
313
+ it 'shows config files', ruby: 2.0 do
314
+ create_file('example1.rb', "\tputs 0")
315
+ expect(cli.run(['--debug', 'example1.rb'])).to eq(1)
316
+ home = File.dirname(File.dirname(File.dirname(__FILE__)))
317
+ expect($stdout.string.lines[2, 7].map(&:chomp).join("\n"))
318
+ .to eq(["For #{abs('')}:" +
319
+ " configuration from #{home}/config/default.yml",
320
+ "Inheriting configuration from #{home}/config/enabled.yml",
321
+ "Inheriting configuration from #{home}/config/" +
322
+ 'disabled.yml',
323
+ "AllCops/Excludes configuration from #{home}/.rubocop.yml",
324
+ "Inheriting configuration from #{home}/config/default.yml",
325
+ "Inheriting configuration from #{home}/config/enabled.yml",
326
+ "Inheriting configuration from #{home}/config/disabled.yml"
327
+ ].join("\n"))
328
+ end
329
+
330
+ it 'shows cop names', ruby: 2.0 do
331
+ create_file('example1.rb', "\tputs 0")
332
+ expect(cli.run(['--format',
333
+ 'emacs',
334
+ '--debug',
335
+ 'example1.rb'])).to eq(1)
336
+ expect($stdout.string.lines[-1])
337
+ .to eq(["#{abs('example1.rb')}:1:1: C: Tab: Tab detected.",
338
+ ''].join("\n"))
339
+ end
340
+ end
341
+
342
+ describe '--require' do
343
+ let(:required_file_path) { './path/to/required_file.rb' }
344
+
345
+ before do
346
+ create_file('example.rb', '# encoding: utf-8')
347
+
348
+ create_file(required_file_path, [
349
+ '# encoding: utf-8',
350
+ "puts 'Hello from required file!'"
351
+ ])
352
+ end
353
+
354
+ it 'requires the passed path' do
355
+ cli.run(['--require', required_file_path, 'example.rb'])
356
+ expect($stdout.string).to start_with('Hello from required file!')
357
+ end
358
+ end
359
+
360
+ describe '-f/--format' do
361
+ let(:target_file) { 'example.rb' }
362
+
363
+ before do
364
+ create_file(target_file, [
365
+ '# encoding: utf-8',
366
+ '#' * 90
367
+ ])
368
+ end
369
+
370
+ describe 'builtin formatters' do
371
+ context 'when simple format is specified' do
372
+ it 'outputs with simple format' do
373
+ cli.run(['--format', 'simple', 'example.rb'])
374
+ expect($stdout.string)
375
+ .to include([
376
+ "== #{target_file} ==",
377
+ 'C: 2: 80: Line is too long. [90/79]'
378
+ ].join("\n"))
379
+ end
380
+ end
381
+
382
+ context 'when clang format is specified' do
383
+ it 'outputs with clang format' do
384
+ create_file('example1.rb', ['# encoding: utf-8',
385
+ 'x= 0 ',
386
+ '#' * 85,
387
+ 'y ',
388
+ 'puts x'])
389
+ create_file('example2.rb', ['# encoding: utf-8',
390
+ "\tx",
391
+ 'def a',
392
+ ' puts',
393
+ 'end'])
394
+ create_file('example3.rb', ['# encoding: utf-8',
395
+ 'def badName',
396
+ ' if something',
397
+ ' test',
398
+ ' end',
399
+ 'end'])
400
+ expect(cli.run(['--format', 'clang', 'example1.rb',
401
+ 'example2.rb', 'example3.rb']))
402
+ .to eq(1)
403
+ expect($stdout.string)
404
+ .to eq(['example1.rb:2:2: C: Surrounding space missing for ' +
405
+ "operator '='.",
406
+ 'x= 0 ',
407
+ ' ^',
408
+ 'example1.rb:2:5: C: Trailing whitespace detected.',
409
+ 'x= 0 ',
410
+ ' ^',
411
+ 'example1.rb:3:80: C: Line is too long. [85/79]',
412
+ '###################################################' +
413
+ '##################################',
414
+ ' ' +
415
+ ' ^^^^^^',
416
+ 'example1.rb:4:2: C: Trailing whitespace detected.',
417
+ 'y ',
418
+ ' ^',
419
+ 'example2.rb:2:1: C: Tab detected.',
420
+ "\tx",
421
+ '^^^^^',
422
+ 'example2.rb:4:1: C: Use 2 (not 3) spaces for ' +
423
+ 'indentation.',
424
+ ' puts',
425
+ '^^^',
426
+ 'example3.rb:2:5: C: Use snake_case for methods and ' +
427
+ 'variables.',
428
+ 'def badName',
429
+ ' ^^^^^^^',
430
+ 'example3.rb:3:3: C: Favor modifier if/unless usage ' +
431
+ 'when you have a single-line body. Another good ' +
432
+ 'alternative is the usage of control flow &&/||.',
433
+ ' if something',
434
+ ' ^^',
435
+ 'example3.rb:5:5: W: end at 5, 4 is not aligned ' +
436
+ 'with if at 3, 2',
437
+ ' end',
438
+ ' ^^^',
439
+ '',
440
+ '3 files inspected, 9 offences detected',
441
+ ''].join("\n"))
442
+ end
443
+ end
444
+
445
+ context 'when emacs format is specified' do
446
+ it 'outputs with emacs format' do
447
+ create_file('example1.rb', ['# encoding: utf-8',
448
+ 'x= 0 ',
449
+ 'y ',
450
+ 'puts x'])
451
+ create_file('example2.rb', ['# encoding: utf-8',
452
+ "\tx = 0",
453
+ 'puts x'])
454
+ expect(cli.run(['--format', 'emacs', 'example1.rb',
455
+ 'example2.rb'])).to eq(1)
456
+ expected_output =
457
+ ["#{abs('example1.rb')}:2:2: C: Surrounding space missing" +
458
+ " for operator '='.",
459
+ "#{abs('example1.rb')}:2:5: C: Trailing whitespace detected.",
460
+ "#{abs('example1.rb')}:3:2: C: Trailing whitespace detected.",
461
+ "#{abs('example2.rb')}:2:1: C: Tab detected.",
462
+ ''].join("\n")
463
+ expect($stdout.string).to eq(expected_output)
464
+ end
465
+ end
466
+
467
+ context 'when unknown format name is specified' do
468
+ it 'aborts with error message' do
469
+ expect { cli.run(['--format', 'unknown', 'example.rb']) }
470
+ .to exit_with_code(1)
471
+ expect($stderr.string)
472
+ .to include('No formatter for "unknown"')
473
+ end
474
+ end
475
+ end
476
+
477
+ describe 'custom formatter' do
478
+ let(:target_file) { abs('example.rb') }
479
+
480
+ context 'when a class name is specified' do
481
+ it 'uses the class as a formatter' do
482
+ module ::MyTool
483
+ class RubocopFormatter < Rubocop::Formatter::BaseFormatter
484
+ def started(all_files)
485
+ output.puts "started: #{all_files.join(',')}"
486
+ end
487
+
488
+ def file_started(file, options)
489
+ output.puts "file_started: #{file}"
490
+ end
491
+
492
+ def file_finished(file, offences)
493
+ output.puts "file_finished: #{file}"
494
+ end
495
+
496
+ def finished(processed_files)
497
+ output.puts "finished: #{processed_files.join(',')}"
498
+ end
499
+ end
500
+ end
501
+
502
+ cli.run(['--format', 'MyTool::RubocopFormatter', 'example.rb'])
503
+ expect($stdout.string).to eq([
504
+ "started: #{target_file}",
505
+ "file_started: #{target_file}",
506
+ "file_finished: #{target_file}",
507
+ "finished: #{target_file}",
508
+ ''
509
+ ].join("\n"))
510
+ end
511
+ end
512
+
513
+ context 'when unknown class name is specified' do
514
+ it 'aborts with error message' do
515
+ args = '--format UnknownFormatter example.rb'
516
+ expect { cli.run(args.split) }.to exit_with_code(1)
517
+ expect($stderr.string).to include('UnknownFormatter')
518
+ end
519
+ end
520
+ end
521
+
522
+ it 'can be used multiple times' do
523
+ cli.run(['--format', 'simple', '--format', 'emacs', 'example.rb'])
524
+ expect($stdout.string)
525
+ .to include([
526
+ "== #{target_file} ==",
527
+ 'C: 2: 80: Line is too long. [90/79]',
528
+ "#{abs(target_file)}:2:80: C: Line is too long. " +
529
+ '[90/79]'
530
+ ].join("\n"))
531
+ end
532
+ end
533
+
534
+ describe '-o/--out option' do
535
+ let(:target_file) { 'example.rb' }
536
+
537
+ before do
538
+ create_file(target_file, [
539
+ '# encoding: utf-8',
540
+ '#' * 90
541
+ ])
542
+ end
543
+
544
+ it 'redirects output to the specified file' do
545
+ cli.run(['--out', 'output.txt', target_file])
546
+ expect(File.read('output.txt')).to include('Line is too long.')
547
+ end
548
+
549
+ it 'is applied to the previously specified formatter' do
550
+ cli.run([
551
+ '--format', 'simple',
552
+ '--format', 'emacs', '--out', 'emacs_output.txt',
553
+ target_file
554
+ ])
555
+
556
+ expect($stdout.string).to eq([
557
+ "== #{target_file} ==",
558
+ 'C: 2: 80: Line is too long. [90/79]',
559
+ '',
560
+ '1 file inspected, 1 offence detected',
561
+ ''
562
+ ].join("\n"))
563
+
564
+ expect(File.read('emacs_output.txt'))
565
+ .to eq("#{abs(target_file)}:2:80: C: Line is too long. [90/79]\n")
566
+ end
567
+ end
105
568
  end
106
569
 
107
570
  describe '#wants_to_quit?' do
108
571
  it 'is initially false' do
109
572
  expect(cli.wants_to_quit?).to be_false
110
573
  end
574
+
575
+ context 'when true' do
576
+ it 'returns 1' do
577
+ create_file('example.rb', '# encoding: utf-8')
578
+ cli.wants_to_quit = true
579
+ expect(cli.run(['example.rb'])).to eq(1)
580
+ end
581
+ end
111
582
  end
112
583
 
113
584
  describe '#trap_interrupt' do
@@ -154,20 +625,12 @@ Usage: rubocop [options] [file1, file2, ...]
154
625
  end
155
626
  end
156
627
 
157
- context 'when #wants_to_quit? is true' do
158
- it 'returns 1' do
159
- create_file('example.rb', '# encoding: utf-8')
160
- cli.wants_to_quit = true
161
- expect(cli.run(['example.rb'])).to eq(1)
162
- end
163
- end
164
-
165
628
  it 'checks a given correct file and returns 0' do
166
629
  create_file('example.rb', [
167
- '# encoding: utf-8',
168
- 'x = 0',
169
- 'puts x'
170
- ])
630
+ '# encoding: utf-8',
631
+ 'x = 0',
632
+ 'puts x'
633
+ ])
171
634
  expect(cli.run(['--format', 'simple', 'example.rb'])).to eq(0)
172
635
  expect($stdout.string)
173
636
  .to eq("\n1 file inspected, no offences detected\n")
@@ -175,10 +638,10 @@ Usage: rubocop [options] [file1, file2, ...]
175
638
 
176
639
  it 'checks a given file with faults and returns 1' do
177
640
  create_file('example.rb', [
178
- '# encoding: utf-8',
179
- 'x = 0 ',
180
- 'puts x'
181
- ])
641
+ '# encoding: utf-8',
642
+ 'x = 0 ',
643
+ 'puts x'
644
+ ])
182
645
  expect(cli.run(['--format', 'simple', 'example.rb'])).to eq(1)
183
646
  expect($stdout.string)
184
647
  .to eq ['== example.rb ==',
@@ -188,598 +651,12 @@ Usage: rubocop [options] [file1, file2, ...]
188
651
  ''].join("\n")
189
652
  end
190
653
 
191
- it 'can report in emacs style', ruby: 1.9 do
192
- create_file('example1.rb', [
193
- 'x= 0 ',
194
- 'y ',
195
- 'puts x'
196
- ])
197
- create_file('example2.rb', [
198
- "\tx = 0",
199
- 'puts x'
200
- ])
201
- expect(cli.run(['--format', 'emacs', 'example1.rb', 'example2.rb']))
202
- .to eq(1)
203
- expect($stdout.string)
204
- .to eq(
205
- ["#{abs('example1.rb')}:1:1: C: Missing utf-8 encoding comment.",
206
- "#{abs('example1.rb')}:1:2: C: Surrounding space missing" +
207
- " for operator '='.",
208
- "#{abs('example1.rb')}:1:5: C: Trailing whitespace detected.",
209
- "#{abs('example1.rb')}:2:2: C: Trailing whitespace detected.",
210
- "#{abs('example2.rb')}:1:1: C: Missing utf-8 encoding comment.",
211
- "#{abs('example2.rb')}:1:1: C: Tab detected.",
212
- ''].join("\n"))
213
- end
214
-
215
- it 'can report in emacs style', ruby: 2.0 do
216
- create_file('example1.rb', [
217
- 'x= 0 ',
218
- 'y ',
219
- 'puts x'
220
- ])
221
- create_file('example2.rb', [
222
- "\tx = 0",
223
- 'puts x'
224
- ])
225
- expect(cli.run(['--format', 'emacs', 'example1.rb', 'example2.rb']))
226
- .to eq(1)
227
- expect($stdout.string)
228
- .to eq(
229
- ["#{abs('example1.rb')}:1:2: C: Surrounding space missing" +
230
- " for operator '='.",
231
- "#{abs('example1.rb')}:1:5: C: Trailing whitespace detected.",
232
- "#{abs('example1.rb')}:2:2: C: Trailing whitespace detected.",
233
- "#{abs('example2.rb')}:1:1: C: Tab detected.",
234
- ''].join("\n"))
235
- end
236
-
237
- it 'can report in clang style' do
238
- create_file('example1.rb', ['# encoding: utf-8',
239
- 'x= 0 ',
240
- '#' * 85,
241
- 'y ',
242
- 'puts x'])
243
- create_file('example2.rb', ['# encoding: utf-8',
244
- "\tx",
245
- 'def a',
246
- ' puts',
247
- 'end'])
248
- create_file('example3.rb', ['# encoding: utf-8',
249
- 'def badName',
250
- ' if something',
251
- ' test',
252
- ' end',
253
- 'end'])
254
- expect(cli.run(['--format', 'clang', 'example1.rb', 'example2.rb',
255
- 'example3.rb']))
256
- .to eq(1)
257
- expect($stdout.string)
258
- .to eq(['example1.rb:2:2: C: Surrounding space missing for operator ' +
259
- "'='.",
260
- 'x= 0 ',
261
- ' ^',
262
- 'example1.rb:2:5: C: Trailing whitespace detected.',
263
- 'x= 0 ',
264
- ' ^',
265
- 'example1.rb:3:80: C: Line is too long. [85/79]',
266
- '###########################################################' +
267
- '##########################',
268
- ' ' +
269
- ' ^^^^^^',
270
- 'example1.rb:4:2: C: Trailing whitespace detected.',
271
- 'y ',
272
- ' ^',
273
- 'example2.rb:2:1: C: Tab detected.',
274
- "\tx",
275
- '^^^^^',
276
- 'example2.rb:4:1: C: Use 2 (not 3) spaces for indentation.',
277
- ' puts',
278
- '^^^',
279
- 'example3.rb:2:5: C: Use snake_case for methods and ' +
280
- 'variables.',
281
- 'def badName',
282
- ' ^^^^^^^',
283
- 'example3.rb:3:3: C: Favor modifier if/unless usage when ' +
284
- 'you have a single-line body. Another good alternative is ' +
285
- 'the usage of control flow &&/||.',
286
- ' if something',
287
- ' ^^',
288
- 'example3.rb:5:5: W: end at 5, 4 is not aligned with if at ' +
289
- '3, 2',
290
- ' end',
291
- ' ^^^',
292
- '',
293
- '3 files inspected, 9 offences detected',
294
- ''].join("\n"))
295
- end
296
-
297
- it 'exits with error if asked to re-generate a todo list that is in use' do
298
- create_file('example1.rb', ['# encoding: utf-8',
299
- 'x= 0 ',
300
- '#' * 85,
301
- 'y ',
302
- 'puts x'])
303
- todo_contents = ['# This configuration was generated with `rubocop' +
304
- ' --auto-gen-config`',
305
- '',
306
- 'LineLength:',
307
- ' Enabled: false']
308
- create_file('rubocop-todo.yml', todo_contents)
309
- expect(IO.read('rubocop-todo.yml'))
310
- .to eq(todo_contents.join("\n") + "\n")
311
- create_file('.rubocop.yml', ['inherit_from: rubocop-todo.yml'])
312
- expect(cli.run(['--auto-gen-config'])).to eq(1)
313
- expect($stderr.string).to eq('Remove rubocop-todo.yml from the current' +
314
- ' configuration before generating it' +
315
- " again.\n")
316
- end
317
-
318
- it 'exits with error if file arguments are given with --auto-gen-config' do
319
- create_file('example1.rb', ['# encoding: utf-8',
320
- 'x= 0 ',
321
- '#' * 85,
322
- 'y ',
323
- 'puts x'])
324
- expect(cli.run(['--auto-gen-config', 'example1.rb'])).to eq(1)
325
- expect($stderr.string).to eq('--auto-gen-config can not be combined ' +
326
- "with any other arguments.\n")
327
- expect($stdout.string).to eq('')
328
- end
329
-
330
- it 'can generate a todo list' do
331
- create_file('example1.rb', ['# encoding: utf-8',
332
- 'x= 0 ',
333
- '#' * 85,
334
- 'y ',
335
- 'puts x'])
336
- create_file('example2.rb', ['# encoding: utf-8',
337
- "\tx = 0",
338
- 'puts x'])
339
- expect(cli.run(['--auto-gen-config'])).to eq(1)
340
- expect($stderr.string).to eq('')
341
- expect($stdout.string).to include([
342
- 'Created rubocop-todo.yml.',
343
- 'Run rubocop with --config rubocop-todo.yml, or',
344
- 'add inherit_from: rubocop-todo.yml in a .rubocop.yml file.',
345
- ''].join("\n"))
346
- expect(IO.read('rubocop-todo.yml'))
347
- .to eq(['# This configuration was generated by `rubocop' +
348
- ' --auto-gen-config`.',
349
- '# The point is for the user to remove these configuration' +
350
- ' records',
351
- '# one by one as the offences are removed from the code base.',
352
- '',
353
- 'LineLength:',
354
- ' Enabled: false',
355
- '',
356
- 'SpaceAroundOperators:',
357
- ' Enabled: false',
358
- '',
359
- 'Tab:',
360
- ' Enabled: false',
361
- '',
362
- 'TrailingWhitespace:',
363
- ' Enabled: false',
364
- ''].join("\n"))
365
- end
366
-
367
- it 'runs just one cop if --only is passed' do
368
- create_file('example.rb', ['if x== 0 ',
369
- "\ty",
370
- 'end'])
371
- # IfUnlessModifier depends on the configuration of LineLength.
372
-
373
- expect(cli.run(['--format', 'simple',
374
- '--only', 'IfUnlessModifier', 'example.rb'])).to eq(1)
375
- expect($stdout.string)
376
- .to eq(['== example.rb ==',
377
- 'C: 1: 1: Favor modifier if/unless usage when you have a ' +
378
- 'single-line body. Another good alternative is the usage of ' +
379
- 'control flow &&/||.',
380
- '',
381
- '1 file inspected, 1 offence detected',
382
- ''].join("\n"))
383
- end
384
-
385
- it 'runs only lint cops if --lint is passed' do
386
- create_file('example.rb', ['if 0 ',
387
- "\ty",
388
- 'end'])
389
- # IfUnlessModifier depends on the configuration of LineLength.
390
-
391
- expect(cli.run(['--format', 'simple', '--lint', 'example.rb'])).to eq(1)
392
- expect($stdout.string)
393
- .to eq(['== example.rb ==',
394
- 'W: 1: 4: Literal 0 appeared in a condition.',
395
- '',
396
- '1 file inspected, 1 offence detected',
397
- ''].join("\n"))
398
-
399
- end
400
-
401
- it 'exits with error if an incorrect cop name is passed to --only' do
402
- expect(cli.run(%w(--only 123))).to eq(1)
403
-
404
- expect($stderr.string).to eq("Unrecognized cop name: 123.\n")
405
- end
406
-
407
- describe '--show-cops option' do
408
- let(:cops) { Cop::Cop.all }
409
-
410
- let(:global_conf) do
411
- config_path = Rubocop::Config.configuration_file_for(Dir.pwd.to_s)
412
- Rubocop::Config.configuration_from_file(config_path)
413
- end
414
-
415
- let(:stdout) { $stdout.string }
416
-
417
- before do
418
- expect { cli.run ['--show-cops'] }.to exit_with_code(0)
419
- end
420
-
421
- # Extracts the first line out of the description
422
- def short_description_of_cop(cop)
423
- desc = full_description_of_cop(cop)
424
- desc ? desc.lines.first.strip : ''
425
- end
426
-
427
- # Gets the full description of the cop or nil if no description is set.
428
- def full_description_of_cop(cop)
429
- cop_config = global_conf.for_cop(cop)
430
- cop_config['Description']
431
- end
432
-
433
- it 'prints all available cops and their description' do
434
- cops.each do |cop|
435
- expect(stdout).to include cop.cop_name
436
- expect(stdout).to include short_description_of_cop(cop)
437
- end
438
- end
439
-
440
- it 'prints all types' do
441
- cops
442
- .types
443
- .map(&:to_s)
444
- .map(&:capitalize)
445
- .each { |type| expect(stdout).to include(type) }
446
- end
447
-
448
- it 'prints all cops in their right type listing' do
449
- lines = stdout.lines
450
- lines.slice_before(/Type /).each do |slice|
451
- types = cops.types.map(&:to_s).map(&:capitalize)
452
- current = types.delete(slice.shift[/Type '(?<c>[^'']+)'/, 'c'])
453
- # all cops in their type listing
454
- cops.with_type(current).each do |cop|
455
- expect(slice.any? { |l| l.include? cop.cop_name }).to be_true
456
- end
457
-
458
- # no cop in wrong type listing
459
- types.each do |type|
460
- cops.with_type(type).each do |cop|
461
- expect(slice.any? { |l| l.include? cop.cop_name }).to be_false
462
- end
463
- end
464
- end
465
- end
466
-
467
- it 'prints the current configuration' do
468
- out = stdout.lines.to_a
469
- cops.each do |cop|
470
- conf = global_conf[cop.cop_name].dup
471
- confstrt = out.find_index { |i| i.include?("- #{cop.cop_name}") } + 1
472
- c = out[confstrt, conf.keys.size].to_s
473
- conf.delete('Description')
474
- expect(c).to include(short_description_of_cop(cop))
475
- conf.each do |k, v|
476
- # ugly hack to get hash/array content tested
477
- if v.kind_of?(Hash) || v.kind_of?(Array)
478
- expect(c).to include "#{k}: #{v.to_s.dump[2, -2]}"
479
- else
480
- expect(c).to include "#{k}: #{v}"
481
- end
482
- end
483
- end
484
- end
485
- end
486
-
487
- it 'shows config files when --debug is passed', ruby: 2.0 do
488
- create_file('example1.rb', "\tputs 0")
489
- expect(cli.run(['--debug', 'example1.rb'])).to eq(1)
490
- home = File.dirname(File.dirname(File.dirname(__FILE__)))
491
- expect($stdout.string.lines[2, 7].map(&:chomp).join("\n"))
492
- .to eq(["For #{abs('')}:" +
493
- " configuration from #{home}/config/default.yml",
494
- "Inheriting configuration from #{home}/config/enabled.yml",
495
- "Inheriting configuration from #{home}/config/disabled.yml",
496
- "AllCops/Excludes configuration from #{home}/.rubocop.yml",
497
- "Inheriting configuration from #{home}/config/default.yml",
498
- "Inheriting configuration from #{home}/config/enabled.yml",
499
- "Inheriting configuration from #{home}/config/disabled.yml"
500
- ].join("\n"))
501
- end
502
-
503
- it 'shows cop names when --debug is passed', ruby: 2.0 do
504
- create_file('example1.rb', "\tputs 0")
505
- expect(cli.run(['--format',
506
- 'emacs',
507
- '--debug',
508
- 'example1.rb'])).to eq(1)
509
- expect($stdout.string.lines[-1]).to eq(
510
- ["#{abs('example1.rb')}:1:1: C: Tab: Tab detected.",
511
- ''].join("\n"))
512
- end
513
-
514
- it 'can be configured with option to disable a certain error' do
515
- create_file('example1.rb', 'puts 0 ')
516
- create_file('rubocop.yml', [
517
- 'Encoding:',
518
- ' Enabled: false',
519
- '',
520
- 'CaseIndentation:',
521
- ' Enabled: false'
522
- ])
523
- expect(cli.run(['--format', 'simple',
524
- '-c', 'rubocop.yml', 'example1.rb'])).to eq(1)
525
- expect($stdout.string).to eq(
526
- ['== example1.rb ==',
527
- 'C: 1: 7: Trailing whitespace detected.',
528
- '',
529
- '1 file inspected, 1 offence detected',
530
- ''].join("\n"))
531
- end
532
-
533
- it 'can be configured to override a parameter that is a hash' do
534
- create_file('example1.rb',
535
- ['# encoding: utf-8',
536
- 'arr.find_all { |e| e > 0 }.collect { |e| -e }'])
537
- # We only care about select over find_all. All other preferred methods
538
- # appearing in the default config are gone when we override
539
- # PreferredMethods. We get no report about collect.
540
- create_file('rubocop.yml',
541
- ['CollectionMethods:',
542
- ' PreferredMethods:',
543
- ' find_all: select'])
544
- cli.run(['--format', 'simple', '-c', 'rubocop.yml', 'example1.rb'])
545
- expect($stdout.string).to eq(
546
- ['== example1.rb ==',
547
- 'C: 2: 5: Prefer select over find_all.',
548
- '',
549
- '1 file inspected, 1 offence detected',
550
- ''].join("\n"))
551
- end
552
-
553
- it 'works when a cop that others depend on is disabled' do
554
- create_file('example1.rb', ['if a',
555
- ' b',
556
- 'end'])
557
- create_file('rubocop.yml', [
558
- 'Encoding:',
559
- ' Enabled: false',
560
- '',
561
- 'LineLength:',
562
- ' Enabled: false'
563
- ])
564
- result = cli.run(['--format', 'simple',
565
- '-c', 'rubocop.yml', 'example1.rb'])
566
- expect($stdout.string).to eq(
567
- ['== example1.rb ==',
568
- 'C: 1: 1: Favor modifier if/unless usage when you have a ' +
569
- 'single-line body. Another good alternative is the usage of ' +
570
- 'control flow &&/||.',
571
- '',
572
- '1 file inspected, 1 offence detected',
573
- ''].join("\n"))
574
- expect(result).to eq(1)
575
- end
576
-
577
- it 'can be configured with project config to disable a certain error' do
578
- create_file('example_src/example1.rb', 'puts 0 ')
579
- create_file('example_src/.rubocop.yml', [
580
- 'Encoding:',
581
- ' Enabled: false',
582
- '',
583
- 'CaseIndentation:',
584
- ' Enabled: false'
585
- ])
586
- expect(cli.run(['--format', 'simple',
587
- 'example_src/example1.rb'])).to eq(1)
588
- expect($stdout.string).to eq(
589
- ['== example_src/example1.rb ==',
590
- 'C: 1: 7: Trailing whitespace detected.',
591
- '',
592
- '1 file inspected, 1 offence detected',
593
- ''].join("\n"))
594
- end
595
-
596
- it 'can use an alternative max line length from a config file' do
597
- create_file('example_src/example1.rb', [
598
- '# encoding: utf-8',
599
- '#' * 90
600
- ])
601
- create_file('example_src/.rubocop.yml', [
602
- 'LineLength:',
603
- ' Enabled: true',
604
- ' Max: 100'
605
- ])
606
- expect(cli.run(['--format', 'simple',
607
- 'example_src/example1.rb'])).to eq(0)
608
- expect($stdout.string).to eq(
609
- ['', '1 file inspected, no offences detected',
610
- ''].join("\n"))
611
- end
612
-
613
- it 'can have different config files in different directories' do
614
- %w(src lib).each do |dir|
615
- create_file("example/#{dir}/example1.rb", [
616
- '# encoding: utf-8',
617
- '#' * 90
618
- ])
619
- end
620
- create_file('example/src/.rubocop.yml', [
621
- 'LineLength:',
622
- ' Enabled: true',
623
- ' Max: 100'
624
- ])
625
- expect(cli.run(%w(--format simple example))).to eq(1)
626
- expect($stdout.string).to eq(
627
- ['== example/lib/example1.rb ==',
628
- 'C: 2: 80: Line is too long. [90/79]',
629
- '',
630
- '2 files inspected, 1 offence detected',
631
- ''].join("\n"))
632
- end
633
-
634
- it 'prefers a config file in ancestor directory to another in home' do
635
- create_file('example_src/example1.rb', [
636
- '# encoding: utf-8',
637
- '#' * 90
638
- ])
639
- create_file('example_src/.rubocop.yml', [
640
- 'LineLength:',
641
- ' Enabled: true',
642
- ' Max: 100'
643
- ])
644
- create_file("#{Dir.home}/.rubocop.yml", [
645
- 'LineLength:',
646
- ' Enabled: true',
647
- ' Max: 80'
648
- ])
649
- expect(cli.run(['--format', 'simple',
650
- 'example_src/example1.rb'])).to eq(0)
651
- expect($stdout.string).to eq(
652
- ['', '1 file inspected, no offences detected',
653
- ''].join("\n"))
654
- end
655
-
656
- it 'can exclude directories relative to .rubocop.yml' do
657
- %w(src etc/test etc/spec tmp/test tmp/spec).each do |dir|
658
- create_file("example/#{dir}/example1.rb", [
659
- '# encoding: utf-8',
660
- '#' * 90
661
- ])
662
- end
663
-
664
- create_file('example/.rubocop.yml', [
665
- 'AllCops:',
666
- ' Excludes:',
667
- ' - src/**',
668
- ' - etc/**',
669
- ' - tmp/spec/**'
670
- ])
671
-
672
- expect(cli.run(%w(--format simple example))).to eq(1)
673
- expect($stdout.string).to eq(
674
- ['== example/tmp/test/example1.rb ==',
675
- 'C: 2: 80: Line is too long. [90/79]',
676
- '',
677
- '1 file inspected, 1 offence detected',
678
- ''].join("\n"))
679
- end
680
-
681
- it 'can exclude a typical vendor directory' do
682
- create_file('vendor/bundle/ruby/1.9.1/gems/parser-2.0.0/.rubocop.yml',
683
- ['AllCops:',
684
- ' Excludes:',
685
- ' - lib/parser/lexer.rb'])
686
-
687
- create_file('vendor/bundle/ruby/1.9.1/gems/parser-2.0.0/lib/ex.rb',
688
- ['# encoding: utf-8',
689
- '#' * 90])
690
-
691
- create_file('.rubocop.yml',
692
- ['AllCops:',
693
- ' Excludes:',
694
- ' - vendor/**'])
695
-
696
- cli.run(%w(--format simple))
697
- expect($stdout.string).to eq(
698
- ['',
699
- '0 files inspected, no offences detected',
700
- ''].join("\n"))
701
- end
702
-
703
- # Relative exclude paths in .rubocop.yml files are relative to that file,
704
- # but in configuration files with other names they will be relative to
705
- # whatever file inherits from them.
706
- it 'can exclude a vendor directory indirectly' do
707
- create_file('vendor/bundle/ruby/1.9.1/gems/parser-2.0.0/.rubocop.yml',
708
- ['AllCops:',
709
- ' Excludes:',
710
- ' - lib/parser/lexer.rb'])
711
-
712
- create_file('vendor/bundle/ruby/1.9.1/gems/parser-2.0.0/lib/ex.rb',
713
- ['# encoding: utf-8',
714
- '#' * 90])
715
-
716
- create_file('.rubocop.yml',
717
- ['inherit_from: config/default.yml'])
718
-
719
- create_file('config/default.yml',
720
- ['AllCops:',
721
- ' Excludes:',
722
- ' - vendor/**'])
723
-
724
- cli.run(%w(--format simple))
725
- expect($stdout.string).to eq(
726
- ['',
727
- '0 files inspected, no offences detected',
728
- ''].join("\n"))
729
- end
730
-
731
- it 'prints a warning for an unrecognized cop name in .rubocop.yml' do
732
- create_file('example/example1.rb', [
733
- '# encoding: utf-8',
734
- '#' * 90
735
- ])
736
-
737
- create_file('example/.rubocop.yml', [
738
- 'LyneLenth:',
739
- ' Enabled: true',
740
- ' Max: 100'
741
- ])
742
-
743
- expect(cli.run(%w(--format simple example))).to eq(1)
744
- expect($stdout.string).to eq(
745
- ['Warning: unrecognized cop LyneLenth found in ' +
746
- File.expand_path('example/.rubocop.yml'),
747
- '== example/example1.rb ==',
748
- 'C: 2: 80: Line is too long. [90/79]',
749
- '',
750
- '1 file inspected, 1 offence detected',
751
- ''].join("\n"))
752
- end
753
-
754
- it 'prints a warning for an unrecognized configuration parameter' do
755
- create_file('example/example1.rb', [
756
- '# encoding: utf-8',
757
- '#' * 90
758
- ])
759
-
760
- create_file('example/.rubocop.yml', [
761
- 'LineLength:',
762
- ' Enabled: true',
763
- ' Min: 10'
764
- ])
765
-
766
- expect(cli.run(%w(--format simple example))).to eq(1)
767
- expect($stdout.string).to eq(
768
- ['Warning: unrecognized parameter LineLength:Min found in ' +
769
- File.expand_path('example/.rubocop.yml'),
770
- '== example/example1.rb ==',
771
- 'C: 2: 80: Line is too long. [90/79]',
772
- '',
773
- '1 file inspected, 1 offence detected',
774
- ''].join("\n"))
775
- end
776
-
777
654
  it 'registers an offence for a syntax error' do
778
655
  create_file('example.rb', [
779
- '# encoding: utf-8',
780
- 'class Test',
781
- 'en'
782
- ])
656
+ '# encoding: utf-8',
657
+ 'class Test',
658
+ 'en'
659
+ ])
783
660
  expect(cli.run(['--format', 'emacs', 'example.rb'])).to eq(1)
784
661
  expect($stdout.string)
785
662
  .to eq(["#{abs('example.rb')}:3:3: E: unexpected " +
@@ -805,280 +682,435 @@ Usage: rubocop [options] [file1, file2, ...]
805
682
 
806
683
  it 'can process a file with an invalid UTF-8 byte sequence' do
807
684
  create_file('example.rb', [
808
- '# encoding: utf-8',
809
- "# #{'f9'.hex.chr}#{'29'.hex.chr}"
810
- ])
685
+ '# encoding: utf-8',
686
+ "# #{'f9'.hex.chr}#{'29'.hex.chr}"
687
+ ])
811
688
  expect(cli.run(['--format', 'emacs', 'example.rb'])).to eq(0)
812
689
  end
813
690
 
814
- it 'can have all cops disabled in a code section' do
815
- create_file('example.rb', [
816
- '# encoding: utf-8',
817
- '# rubocop:disable all',
818
- '#' * 90,
819
- 'x(123456)',
820
- 'y("123")',
821
- 'def func',
822
- ' # rubocop: enable LineLength, StringLiterals',
823
- ' ' + '#' * 93,
824
- ' x(123456)',
825
- ' y("123")',
826
- 'end'
827
- ])
828
- expect(cli.run(['--format', 'emacs', 'example.rb'])).to eq(1)
829
- # all cops were disabled, then 2 were enabled again, so we
830
- # should get 2 offences reported.
831
- expect($stdout.string).to eq(
832
- ["#{abs('example.rb')}:8:80: C: Line is too long. [95/79]",
833
- "#{abs('example.rb')}:10:5: C: Prefer single-quoted strings when " +
834
- "you don't need string interpolation or special symbols.",
835
- ''].join("\n"))
836
- end
691
+ describe 'rubocop:disable comment' do
692
+ it 'can disable all cops in a code section' do
693
+ create_file('example.rb',
694
+ ['# encoding: utf-8',
695
+ '# rubocop:disable all',
696
+ '#' * 90,
697
+ 'x(123456)',
698
+ 'y("123")',
699
+ 'def func',
700
+ ' # rubocop: enable LineLength, StringLiterals',
701
+ ' ' + '#' * 93,
702
+ ' x(123456)',
703
+ ' y("123")',
704
+ 'end'])
705
+ expect(cli.run(['--format', 'emacs', 'example.rb'])).to eq(1)
706
+ # all cops were disabled, then 2 were enabled again, so we
707
+ # should get 2 offences reported.
708
+ expect($stdout.string)
709
+ .to eq(["#{abs('example.rb')}:8:80: C: Line is too long. [95/79]",
710
+ "#{abs('example.rb')}:10:5: C: Prefer single-quoted " +
711
+ "strings when you don't need string interpolation or " +
712
+ 'special symbols.',
713
+ ''].join("\n"))
714
+ end
837
715
 
838
- it 'can have selected cops disabled in a code section' do
839
- create_file('example.rb', [
840
- '# encoding: utf-8',
841
- '# rubocop:disable LineLength,NumericLiterals,StringLiterals',
842
- '#' * 90,
843
- 'x(123456)',
844
- 'y("123")',
845
- 'def func',
846
- ' # rubocop: enable LineLength, StringLiterals',
847
- ' ' + '#' * 93,
848
- ' x(123456)',
849
- ' y("123")',
850
- 'end'
851
- ])
852
- expect(cli.run(['--format', 'emacs', 'example.rb'])).to eq(1)
853
- # 3 cops were disabled, then 2 were enabled again, so we
854
- # should get 2 offences reported.
855
- expect($stdout.string).to eq(
856
- ["#{abs('example.rb')}:8:80: C: Line is too long. [95/79]",
857
- "#{abs('example.rb')}:10:5: C: Prefer single-quoted strings when " +
858
- "you don't need string interpolation or special symbols.",
859
- ''].join("\n"))
860
- end
716
+ it 'can disable selected cops in a code section' do
717
+ create_file('example.rb',
718
+ ['# encoding: utf-8',
719
+ '# rubocop:disable LineLength,NumericLiterals,' +
720
+ 'StringLiterals',
721
+ '#' * 90,
722
+ 'x(123456)',
723
+ 'y("123")',
724
+ 'def func',
725
+ ' # rubocop: enable LineLength, StringLiterals',
726
+ ' ' + '#' * 93,
727
+ ' x(123456)',
728
+ ' y("123")',
729
+ 'end'])
730
+ expect(cli.run(['--format', 'emacs', 'example.rb'])).to eq(1)
731
+ # 3 cops were disabled, then 2 were enabled again, so we
732
+ # should get 2 offences reported.
733
+ expect($stdout.string)
734
+ .to eq(["#{abs('example.rb')}:8:80: C: Line is too long. [95/79]",
735
+ "#{abs('example.rb')}:10:5: C: Prefer single-quoted " +
736
+ "strings when you don't need string interpolation or " +
737
+ 'special symbols.',
738
+ ''].join("\n"))
739
+ end
861
740
 
862
- it 'can have all cops disabled on a single line' do
863
- create_file('example.rb', [
864
- '# encoding: utf-8',
865
- 'y("123", 123456) # rubocop:disable all'
866
- ])
867
- expect(cli.run(['--format', 'emacs', 'example.rb'])).to eq(0)
868
- expect($stdout.string).to be_empty
869
- end
741
+ it 'can disable all cops on a single line' do
742
+ create_file('example.rb', [
743
+ '# encoding: utf-8',
744
+ 'y("123", 123456) # rubocop:disable all'
745
+ ])
746
+ expect(cli.run(['--format', 'emacs', 'example.rb'])).to eq(0)
747
+ expect($stdout.string).to be_empty
748
+ end
870
749
 
871
- it 'can have selected cops disabled on a single line' do
872
- create_file('example.rb', [
873
- '# encoding: utf-8',
874
- '#' * 90 + ' # rubocop:disable LineLength',
875
- '#' * 95,
876
- 'y("123") # rubocop:disable LineLength,StringLiterals'
877
- ])
878
- expect(cli.run(['--format', 'emacs', 'example.rb'])).to eq(1)
879
- expect($stdout.string).to eq(
880
- ["#{abs('example.rb')}:3:80: C: Line is too long. [95/79]",
881
- ''].join("\n"))
750
+ it 'can disable selected cops on a single line' do
751
+ create_file('example.rb',
752
+ [
753
+ '# encoding: utf-8',
754
+ '#' * 90 + ' # rubocop:disable LineLength',
755
+ '#' * 95,
756
+ 'y("123") # rubocop:disable LineLength,StringLiterals'
757
+ ])
758
+ expect(cli.run(['--format', 'emacs', 'example.rb'])).to eq(1)
759
+ expect($stdout.string)
760
+ .to eq(
761
+ ["#{abs('example.rb')}:3:80: C: Line is too long. [95/79]",
762
+ ''].join("\n"))
763
+ end
882
764
  end
883
-
765
+
884
766
  it 'finds a file with no .rb extension but has a shebang line' do
885
767
  create_file('example', [
886
- '#!/usr/bin/env ruby',
887
- '# encoding: utf-8',
888
- 'x = 0',
889
- 'puts x'
890
- ])
768
+ '#!/usr/bin/env ruby',
769
+ '# encoding: utf-8',
770
+ 'x = 0',
771
+ 'puts x'
772
+ ])
891
773
  expect(cli.run(%w(--format simple))).to eq(0)
892
- expect($stdout.string).to eq(
893
- ['', '1 file inspected, no offences detected',
894
- ''].join("\n"))
895
- end
896
-
897
- it 'finds included files' do
898
- create_file('example', [
899
- '# encoding: utf-8',
900
- 'x = 0',
901
- 'puts x'
902
- ])
903
- create_file('regexp', [
904
- '# encoding: utf-8',
905
- 'x = 0',
906
- 'puts x'
907
- ])
908
- create_file('.rubocop.yml', [
909
- 'AllCops:',
910
- ' Includes:',
911
- ' - example',
912
- ' - !ruby/regexp /regexp$/'
913
- ])
914
- expect(cli.run(%w(--format simple))).to eq(0)
915
- expect($stdout.string).to eq(
916
- ['', '2 files inspected, no offences detected',
917
- ''].join("\n"))
918
- end
919
-
920
- it 'ignores excluded files' do
921
- create_file('example.rb', [
922
- '# encoding: utf-8',
923
- 'x = 0',
924
- 'puts x'
925
- ])
926
- create_file('regexp.rb', [
927
- '# encoding: utf-8',
928
- 'x = 0',
929
- 'puts x'
930
- ])
931
- create_file('exclude_glob.rb', [
932
- '#!/usr/bin/env ruby',
933
- '# encoding: utf-8',
934
- 'x = 0',
935
- 'puts x'
936
- ])
937
- create_file('.rubocop.yml', [
938
- 'AllCops:',
939
- ' Excludes:',
940
- ' - example.rb',
941
- ' - !ruby/regexp /regexp.rb$/',
942
- ' - "exclude_*"'
943
- ])
944
- expect(cli.run(%w(--format simple))).to eq(0)
945
- expect($stdout.string).to eq(
946
- ['', '0 files inspected, no offences detected',
947
- ''].join("\n"))
774
+ expect($stdout.string)
775
+ .to eq(['', '1 file inspected, no offences detected', ''].join("\n"))
948
776
  end
949
777
 
950
- # With rubinius 2.0.0.rc1 + rspec 2.13.1,
951
- # File.stub(:open).and_call_original causes SystemStackError.
952
- it 'does not read files in excluded list', broken: :rbx do
953
- %w(rb.rb non-rb.ext without-ext).each do |filename|
954
- create_file("example/ignored/#{filename}", [
955
- '# encoding: utf-8',
956
- '#' * 90
957
- ])
778
+ describe 'configuration from file' do
779
+ it 'finds included files' do
780
+ create_file('example', [
781
+ '# encoding: utf-8',
782
+ 'x = 0',
783
+ 'puts x'
784
+ ])
785
+ create_file('regexp', [
786
+ '# encoding: utf-8',
787
+ 'x = 0',
788
+ 'puts x'
789
+ ])
790
+ create_file('.rubocop.yml', [
791
+ 'AllCops:',
792
+ ' Includes:',
793
+ ' - example',
794
+ ' - !ruby/regexp /regexp$/'
795
+ ])
796
+ expect(cli.run(%w(--format simple))).to eq(0)
797
+ expect($stdout.string)
798
+ .to eq(['', '2 files inspected, no offences detected',
799
+ ''].join("\n"))
958
800
  end
959
801
 
960
- create_file('example/.rubocop.yml', [
961
- 'AllCops:',
962
- ' Excludes:',
963
- ' - ignored/**',
964
- ])
965
- File.should_not_receive(:open).with(%r(/ignored/))
966
- File.stub(:open).and_call_original
967
- expect(cli.run(%w(--format simple example))).to eq(0)
968
- expect($stdout.string).to eq(
969
- ['', '0 files inspected, no offences detected',
970
- ''].join("\n"))
971
- end
972
-
973
- describe '--require option' do
974
- let(:required_file_path) { './path/to/required_file.rb' }
802
+ it 'ignores excluded files' do
803
+ create_file('example.rb', [
804
+ '# encoding: utf-8',
805
+ 'x = 0',
806
+ 'puts x'
807
+ ])
808
+ create_file('regexp.rb', [
809
+ '# encoding: utf-8',
810
+ 'x = 0',
811
+ 'puts x'
812
+ ])
813
+ create_file('exclude_glob.rb', [
814
+ '#!/usr/bin/env ruby',
815
+ '# encoding: utf-8',
816
+ 'x = 0',
817
+ 'puts x'
818
+ ])
819
+ create_file('.rubocop.yml', [
820
+ 'AllCops:',
821
+ ' Excludes:',
822
+ ' - example.rb',
823
+ ' - !ruby/regexp /regexp.rb$/',
824
+ ' - "exclude_*"'
825
+ ])
826
+ expect(cli.run(%w(--format simple))).to eq(0)
827
+ expect($stdout.string)
828
+ .to eq(['', '0 files inspected, no offences detected',
829
+ ''].join("\n"))
830
+ end
975
831
 
976
- before do
977
- create_file('example.rb', '# encoding: utf-8')
832
+ # With rubinius 2.0.0.rc1 + rspec 2.13.1,
833
+ # File.stub(:open).and_call_original causes SystemStackError.
834
+ it 'does not read files in excluded list', broken: :rbx do
835
+ %w(rb.rb non-rb.ext without-ext).each do |filename|
836
+ create_file("example/ignored/#{filename}", [
837
+ '# encoding: utf-8',
838
+ '#' * 90
839
+ ])
840
+ end
978
841
 
979
- create_file(required_file_path, [
980
- '# encoding: utf-8',
981
- "puts 'Hello from required file!'"
982
- ])
842
+ create_file('example/.rubocop.yml', [
843
+ 'AllCops:',
844
+ ' Excludes:',
845
+ ' - ignored/**',
846
+ ])
847
+ File.should_not_receive(:open).with(%r(/ignored/))
848
+ File.stub(:open).and_call_original
849
+ expect(cli.run(%w(--format simple example))).to eq(0)
850
+ expect($stdout.string)
851
+ .to eq(['', '0 files inspected, no offences detected',
852
+ ''].join("\n"))
983
853
  end
984
854
 
985
- it 'requires the passed path' do
986
- cli.run(['--require', required_file_path, 'example.rb'])
987
- expect($stdout.string).to start_with('Hello from required file!')
855
+ it 'can be configured with option to disable a certain error' do
856
+ create_file('example1.rb', 'puts 0 ')
857
+ create_file('rubocop.yml', [
858
+ 'Encoding:',
859
+ ' Enabled: false',
860
+ '',
861
+ 'CaseIndentation:',
862
+ ' Enabled: false'
863
+ ])
864
+ expect(cli.run(['--format', 'simple',
865
+ '-c', 'rubocop.yml', 'example1.rb'])).to eq(1)
866
+ expect($stdout.string)
867
+ .to eq(['== example1.rb ==',
868
+ 'C: 1: 7: Trailing whitespace detected.',
869
+ '',
870
+ '1 file inspected, 1 offence detected',
871
+ ''].join("\n"))
988
872
  end
989
- end
990
873
 
991
- describe '-f/--format option' do
992
- let(:target_file) { 'example.rb' }
874
+ it 'can be configured to override a parameter that is a hash' do
875
+ create_file('example1.rb',
876
+ ['# encoding: utf-8',
877
+ 'arr.find_all { |e| e > 0 }.collect { |e| -e }'])
878
+ # We only care about select over find_all. All other preferred methods
879
+ # appearing in the default config are gone when we override
880
+ # PreferredMethods. We get no report about collect.
881
+ create_file('rubocop.yml',
882
+ ['CollectionMethods:',
883
+ ' PreferredMethods:',
884
+ ' find_all: select'])
885
+ cli.run(['--format', 'simple', '-c', 'rubocop.yml', 'example1.rb'])
886
+ expect($stdout.string)
887
+ .to eq(['== example1.rb ==',
888
+ 'C: 2: 5: Prefer select over find_all.',
889
+ '',
890
+ '1 file inspected, 1 offence detected',
891
+ ''].join("\n"))
892
+ end
993
893
 
994
- before do
995
- create_file(target_file, [
996
- '# encoding: utf-8',
997
- '#' * 90
998
- ])
894
+ it 'works when a cop that others depend on is disabled' do
895
+ create_file('example1.rb', ['if a',
896
+ ' b',
897
+ 'end'])
898
+ create_file('rubocop.yml', [
899
+ 'Encoding:',
900
+ ' Enabled: false',
901
+ '',
902
+ 'LineLength:',
903
+ ' Enabled: false'
904
+ ])
905
+ result = cli.run(['--format', 'simple',
906
+ '-c', 'rubocop.yml', 'example1.rb'])
907
+ expect($stdout.string)
908
+ .to eq(['== example1.rb ==',
909
+ 'C: 1: 1: Favor modifier if/unless usage when you have ' +
910
+ 'a single-line body. Another good alternative is the ' +
911
+ 'usage of control flow &&/||.',
912
+ '',
913
+ '1 file inspected, 1 offence detected',
914
+ ''].join("\n"))
915
+ expect(result).to eq(1)
999
916
  end
1000
917
 
1001
- describe 'builtin formatters' do
1002
- context 'when simple format is specified' do
1003
- it 'outputs with simple format' do
1004
- cli.run(['--format', 'simple', 'example.rb'])
1005
- expect($stdout.string).to include([
1006
- "== #{target_file} ==",
1007
- 'C: 2: 80: Line is too long. [90/79]'
1008
- ].join("\n"))
1009
- end
1010
- end
918
+ it 'can be configured with project config to disable a certain error' do
919
+ create_file('example_src/example1.rb', 'puts 0 ')
920
+ create_file('example_src/.rubocop.yml', [
921
+ 'Encoding:',
922
+ ' Enabled: false',
923
+ '',
924
+ 'CaseIndentation:',
925
+ ' Enabled: false'
926
+ ])
927
+ expect(cli.run(['--format', 'simple',
928
+ 'example_src/example1.rb'])).to eq(1)
929
+ expect($stdout.string)
930
+ .to eq(['== example_src/example1.rb ==',
931
+ 'C: 1: 7: Trailing whitespace detected.',
932
+ '',
933
+ '1 file inspected, 1 offence detected',
934
+ ''].join("\n"))
935
+ end
1011
936
 
1012
- context 'when emacs format is specified' do
1013
- it 'outputs with emacs format' do
1014
- cli.run(['--format', 'emacs', 'example.rb'])
1015
- expect($stdout.string).to include(
1016
- "#{abs(target_file)}:2:80: C: Line is too long. [90/79]")
1017
- end
1018
- end
937
+ it 'can use an alternative max line length from a config file' do
938
+ create_file('example_src/example1.rb', [
939
+ '# encoding: utf-8',
940
+ '#' * 90
941
+ ])
942
+ create_file('example_src/.rubocop.yml', [
943
+ 'LineLength:',
944
+ ' Enabled: true',
945
+ ' Max: 100'
946
+ ])
947
+ expect(cli.run(['--format', 'simple',
948
+ 'example_src/example1.rb'])).to eq(0)
949
+ expect($stdout.string)
950
+ .to eq(['', '1 file inspected, no offences detected', ''].join("\n"))
951
+ end
1019
952
 
1020
- context 'when unknown format name is specified' do
1021
- it 'aborts with error message' do
1022
- expect { cli.run(['--format', 'unknown', 'example.rb']) }
1023
- .to exit_with_code(1)
1024
- expect($stderr.string)
1025
- .to include('No formatter for "unknown"')
1026
- end
953
+ it 'can have different config files in different directories' do
954
+ %w(src lib).each do |dir|
955
+ create_file("example/#{dir}/example1.rb", [
956
+ '# encoding: utf-8',
957
+ '#' * 90
958
+ ])
1027
959
  end
960
+ create_file('example/src/.rubocop.yml', [
961
+ 'LineLength:',
962
+ ' Enabled: true',
963
+ ' Max: 100'
964
+ ])
965
+ expect(cli.run(%w(--format simple example))).to eq(1)
966
+ expect($stdout.string).to eq(
967
+ ['== example/lib/example1.rb ==',
968
+ 'C: 2: 80: Line is too long. [90/79]',
969
+ '',
970
+ '2 files inspected, 1 offence detected',
971
+ ''].join("\n"))
1028
972
  end
1029
973
 
1030
- describe 'custom formatter' do
1031
- let(:target_file) { abs('example.rb') }
1032
-
1033
- context 'when a class name is specified' do
1034
- it 'uses the class as a formatter' do
1035
- module ::MyTool
1036
- class RubocopFormatter < Rubocop::Formatter::BaseFormatter
1037
- def started(all_files)
1038
- output.puts "started: #{all_files.join(',')}"
1039
- end
974
+ it 'prefers a config file in ancestor directory to another in home' do
975
+ create_file('example_src/example1.rb', [
976
+ '# encoding: utf-8',
977
+ '#' * 90
978
+ ])
979
+ create_file('example_src/.rubocop.yml', [
980
+ 'LineLength:',
981
+ ' Enabled: true',
982
+ ' Max: 100'
983
+ ])
984
+ create_file("#{Dir.home}/.rubocop.yml", [
985
+ 'LineLength:',
986
+ ' Enabled: true',
987
+ ' Max: 80'
988
+ ])
989
+ expect(cli.run(['--format', 'simple',
990
+ 'example_src/example1.rb'])).to eq(0)
991
+ expect($stdout.string)
992
+ .to eq(['', '1 file inspected, no offences detected', ''].join("\n"))
993
+ end
1040
994
 
1041
- def file_started(file, options)
1042
- output.puts "file_started: #{file}"
1043
- end
995
+ it 'can exclude directories relative to .rubocop.yml' do
996
+ %w(src etc/test etc/spec tmp/test tmp/spec).each do |dir|
997
+ create_file("example/#{dir}/example1.rb", [
998
+ '# encoding: utf-8',
999
+ '#' * 90
1000
+ ])
1001
+ end
1044
1002
 
1045
- def file_finished(file, offences)
1046
- output.puts "file_finished: #{file}"
1047
- end
1003
+ create_file('example/.rubocop.yml', [
1004
+ 'AllCops:',
1005
+ ' Excludes:',
1006
+ ' - src/**',
1007
+ ' - etc/**',
1008
+ ' - tmp/spec/**'
1009
+ ])
1010
+
1011
+ expect(cli.run(%w(--format simple example))).to eq(1)
1012
+ expect($stdout.string).to eq(
1013
+ ['== example/tmp/test/example1.rb ==',
1014
+ 'C: 2: 80: Line is too long. [90/79]',
1015
+ '',
1016
+ '1 file inspected, 1 offence detected',
1017
+ ''].join("\n"))
1018
+ end
1048
1019
 
1049
- def finished(processed_files)
1050
- output.puts "finished: #{processed_files.join(',')}"
1051
- end
1052
- end
1053
- end
1020
+ it 'can exclude a typical vendor directory' do
1021
+ create_file('vendor/bundle/ruby/1.9.1/gems/parser-2.0.0/.rubocop.yml',
1022
+ ['AllCops:',
1023
+ ' Excludes:',
1024
+ ' - lib/parser/lexer.rb'])
1025
+
1026
+ create_file('vendor/bundle/ruby/1.9.1/gems/parser-2.0.0/lib/ex.rb',
1027
+ ['# encoding: utf-8',
1028
+ '#' * 90])
1029
+
1030
+ create_file('.rubocop.yml',
1031
+ ['AllCops:',
1032
+ ' Excludes:',
1033
+ ' - vendor/**'])
1034
+
1035
+ cli.run(%w(--format simple))
1036
+ expect($stdout.string)
1037
+ .to eq(['', '0 files inspected, no offences detected',
1038
+ ''].join("\n"))
1039
+ end
1054
1040
 
1055
- cli.run(['--format', 'MyTool::RubocopFormatter', 'example.rb'])
1056
- expect($stdout.string).to eq([
1057
- "started: #{target_file}",
1058
- "file_started: #{target_file}",
1059
- "file_finished: #{target_file}",
1060
- "finished: #{target_file}",
1061
- ''
1062
- ].join("\n"))
1063
- end
1064
- end
1041
+ # Relative exclude paths in .rubocop.yml files are relative to that file,
1042
+ # but in configuration files with other names they will be relative to
1043
+ # whatever file inherits from them.
1044
+ it 'can exclude a vendor directory indirectly' do
1045
+ create_file('vendor/bundle/ruby/1.9.1/gems/parser-2.0.0/.rubocop.yml',
1046
+ ['AllCops:',
1047
+ ' Excludes:',
1048
+ ' - lib/parser/lexer.rb'])
1049
+
1050
+ create_file('vendor/bundle/ruby/1.9.1/gems/parser-2.0.0/lib/ex.rb',
1051
+ ['# encoding: utf-8',
1052
+ '#' * 90])
1053
+
1054
+ create_file('.rubocop.yml',
1055
+ ['inherit_from: config/default.yml'])
1056
+
1057
+ create_file('config/default.yml',
1058
+ ['AllCops:',
1059
+ ' Excludes:',
1060
+ ' - vendor/**'])
1061
+
1062
+ cli.run(%w(--format simple))
1063
+ expect($stdout.string)
1064
+ .to eq(['', '0 files inspected, no offences detected',
1065
+ ''].join("\n"))
1066
+ end
1065
1067
 
1066
- context 'when unknown class name is specified' do
1067
- it 'aborts with error message' do
1068
- expect { cli.run(['--format', 'UnknownFormatter', 'example.rb']) }
1069
- .to exit_with_code(1)
1070
- expect($stderr.string).to include('UnknownFormatter')
1071
- end
1072
- end
1068
+ it 'prints a warning for an unrecognized cop name in .rubocop.yml' do
1069
+ create_file('example/example1.rb', [
1070
+ '# encoding: utf-8',
1071
+ '#' * 90
1072
+ ])
1073
+
1074
+ create_file('example/.rubocop.yml', [
1075
+ 'LyneLenth:',
1076
+ ' Enabled: true',
1077
+ ' Max: 100'
1078
+ ])
1079
+
1080
+ expect(cli.run(%w(--format simple example))).to eq(1)
1081
+ expect($stdout.string)
1082
+ .to eq(
1083
+ ['Warning: unrecognized cop LyneLenth found in ' +
1084
+ File.expand_path('example/.rubocop.yml'),
1085
+ '== example/example1.rb ==',
1086
+ 'C: 2: 80: Line is too long. [90/79]',
1087
+ '',
1088
+ '1 file inspected, 1 offence detected',
1089
+ ''].join("\n"))
1073
1090
  end
1074
1091
 
1075
- it 'can be used multiple times' do
1076
- cli.run(['--format', 'simple', '--format', 'emacs', 'example.rb'])
1077
- expect($stdout.string).to include([
1078
- "== #{target_file} ==",
1079
- 'C: 2: 80: Line is too long. [90/79]',
1080
- "#{abs(target_file)}:2:80: C: Line is too long. [90/79]"
1081
- ].join("\n"))
1092
+ it 'prints a warning for an unrecognized configuration parameter' do
1093
+ create_file('example/example1.rb', [
1094
+ '# encoding: utf-8',
1095
+ '#' * 90
1096
+ ])
1097
+
1098
+ create_file('example/.rubocop.yml', [
1099
+ 'LineLength:',
1100
+ ' Enabled: true',
1101
+ ' Min: 10'
1102
+ ])
1103
+
1104
+ expect(cli.run(%w(--format simple example))).to eq(1)
1105
+ expect($stdout.string)
1106
+ .to eq(
1107
+ ['Warning: unrecognized parameter LineLength:Min found in ' +
1108
+ File.expand_path('example/.rubocop.yml'),
1109
+ '== example/example1.rb ==',
1110
+ 'C: 2: 80: Line is too long. [90/79]',
1111
+ '',
1112
+ '1 file inspected, 1 offence detected',
1113
+ ''].join("\n"))
1082
1114
  end
1083
1115
  end
1084
1116
 
@@ -1101,43 +1133,6 @@ Usage: rubocop [options] [file1, file2, ...]
1101
1133
  end
1102
1134
  end
1103
1135
 
1104
- describe '-o/--out option' do
1105
- let(:target_file) { 'example.rb' }
1106
-
1107
- before do
1108
- create_file(target_file, [
1109
- '# encoding: utf-8',
1110
- '#' * 90
1111
- ])
1112
- end
1113
-
1114
- it 'redirects output to the specified file' do
1115
- cli.run(['--out', 'output.txt', target_file])
1116
- expect(File.read('output.txt')).to include('Line is too long.')
1117
- end
1118
-
1119
- it 'is applied to the previously specified formatter' do
1120
- cli.run([
1121
- '--format', 'simple',
1122
- '--format', 'emacs', '--out', 'emacs_output.txt',
1123
- target_file
1124
- ])
1125
-
1126
- expect($stdout.string).to eq([
1127
- "== #{target_file} ==",
1128
- 'C: 2: 80: Line is too long. [90/79]',
1129
- '',
1130
- '1 file inspected, 1 offence detected',
1131
- ''
1132
- ].join("\n"))
1133
-
1134
- expect(File.read('emacs_output.txt')).to eq([
1135
- "#{abs(target_file)}:2:80: C: Line is too long. [90/79]",
1136
- ''
1137
- ].join("\n"))
1138
- end
1139
- end
1140
-
1141
1136
  describe '#display_error_summary' do
1142
1137
  it 'displays an error message to stderr when errors are present' do
1143
1138
  msg = 'An error occurred while Encoding cop was inspecting file.rb.'