rubocop 0.14.0 → 0.14.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 (42) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +1 -1
  3. data/CHANGELOG.md +15 -0
  4. data/README.md +1 -1
  5. data/config/default.yml +4 -0
  6. data/config/enabled.yml +16 -8
  7. data/lib/rubocop.rb +3 -0
  8. data/lib/rubocop/cli.rb +1 -1
  9. data/lib/rubocop/config.rb +3 -160
  10. data/lib/rubocop/config_loader.rb +156 -0
  11. data/lib/rubocop/config_store.rb +6 -6
  12. data/lib/rubocop/cop/style/align_hash.rb +15 -11
  13. data/lib/rubocop/cop/style/braces_around_hash_parameters.rb +46 -0
  14. data/lib/rubocop/cop/style/class_length.rb +27 -4
  15. data/lib/rubocop/cop/style/documentation.rb +23 -25
  16. data/lib/rubocop/cop/style/raise_args.rb +6 -1
  17. data/lib/rubocop/cop/style/space_after_not.rb +37 -0
  18. data/lib/rubocop/cop/util.rb +18 -1
  19. data/lib/rubocop/formatter/clang_style_formatter.rb +11 -2
  20. data/lib/rubocop/options.rb +3 -3
  21. data/lib/rubocop/version.rb +1 -1
  22. data/spec/project_spec.rb +2 -2
  23. data/spec/rubocop/cli_spec.rb +1 -1
  24. data/spec/rubocop/config_loader_spec.rb +314 -0
  25. data/spec/rubocop/config_spec.rb +1 -308
  26. data/spec/rubocop/config_store_spec.rb +9 -9
  27. data/spec/rubocop/cop/lint/shadowing_outer_local_variable_spec.rb +1 -1
  28. data/spec/rubocop/cop/lint/useless_assignment_spec.rb +3 -3
  29. data/spec/rubocop/cop/style/align_hash_spec.rb +17 -20
  30. data/spec/rubocop/cop/style/braces_around_hash_parameters_spec.rb +193 -0
  31. data/spec/rubocop/cop/style/class_length_spec.rb +64 -0
  32. data/spec/rubocop/cop/style/documentation_spec.rb +10 -0
  33. data/spec/rubocop/cop/style/indentation_width_spec.rb +0 -7
  34. data/spec/rubocop/cop/style/numeric_literals_spec.rb +1 -1
  35. data/spec/rubocop/cop/style/raise_args_spec.rb +5 -0
  36. data/spec/rubocop/cop/style/space_after_not_spec.rb +22 -0
  37. data/spec/rubocop/cop/team_spec.rb +1 -1
  38. data/spec/rubocop/cop/util_spec.rb +49 -0
  39. data/spec/rubocop/formatter/clang_style_formatter_spec.rb +42 -16
  40. data/spec/rubocop/options_spec.rb +3 -2
  41. data/spec/spec_helper.rb +1 -1
  42. metadata +13 -2
@@ -20,20 +20,20 @@ module Rubocop
20
20
  end
21
21
 
22
22
  def set_options_config(options_config)
23
- loaded_config = Config.load_file(options_config)
24
- @options_config = Config.merge_with_default(loaded_config,
25
- options_config)
23
+ loaded_config = ConfigLoader.load_file(options_config)
24
+ @options_config = ConfigLoader.merge_with_default(loaded_config,
25
+ options_config)
26
26
  end
27
27
 
28
28
  def for(file)
29
29
  return @options_config if @options_config
30
30
 
31
31
  dir = File.dirname(file)
32
- @path_cache[dir] ||= Config.configuration_file_for(dir)
32
+ @path_cache[dir] ||= ConfigLoader.configuration_file_for(dir)
33
33
  path = @path_cache[dir]
34
34
  @object_cache[path] ||= begin
35
- print "For #{dir}: " if Config.debug?
36
- Config.configuration_from_file(path)
35
+ print "For #{dir}: " if ConfigLoader.debug?
36
+ ConfigLoader.configuration_from_file(path)
37
37
  end
38
38
  end
39
39
  end
@@ -12,24 +12,20 @@ module Rubocop
12
12
  def on_hash(node)
13
13
  first_pair = node.children.first
14
14
 
15
- if [cop_config['EnforcedHashRocketStyle'],
16
- cop_config['EnforcedColonStyle']].include?('table')
15
+ styles = [cop_config['EnforcedHashRocketStyle'],
16
+ cop_config['EnforcedColonStyle']]
17
17
 
18
- lines_of_the_children = node.children.map do |pair|
19
- key, _value = *pair
20
- key.loc.line
21
- end
22
- on_the_same_line = lines_of_the_children.uniq.size == 1
23
- return if on_the_same_line
18
+ if styles.include?('table') || styles.include?('separator')
19
+ return if any_pairs_on_the_same_line?(node)
20
+ end
24
21
 
22
+ if styles.include?('table')
25
23
  key_widths = node.children.map do |pair|
26
24
  key, _value = *pair
27
25
  key.loc.expression.source.length
28
26
  end
29
27
  @max_key_width = key_widths.max
30
- if first_pair && !on_the_same_line &&
31
- value_delta(nil, first_pair, @max_key_width) != 0
32
-
28
+ if first_pair && value_delta(nil, first_pair, @max_key_width) != 0
33
29
  @column_deltas = {}
34
30
  convention(first_pair, :expression)
35
31
  end
@@ -41,6 +37,14 @@ module Rubocop
41
37
  end
42
38
  end
43
39
 
40
+ def any_pairs_on_the_same_line?(node)
41
+ lines_of_the_children = node.children.map do |pair|
42
+ key, _value = *pair
43
+ key.loc.line
44
+ end
45
+ lines_of_the_children.uniq.size < lines_of_the_children.size
46
+ end
47
+
44
48
  def autocorrect(node)
45
49
  # We can't use the instance variable inside the lambda. That would
46
50
  # just give each lambda the same reference and they would all get the
@@ -0,0 +1,46 @@
1
+ # encoding: utf-8
2
+
3
+ module Rubocop
4
+ module Cop
5
+ module Style
6
+ # This cop checks for braces in method calls with hash parameters.
7
+ class BracesAroundHashParameters < Cop
8
+ def on_send(node)
9
+ _receiver, method_name, *args = *node
10
+
11
+ return unless args.size == 1
12
+ # discard attr writer methods.
13
+ return if method_name.to_s.end_with?('=')
14
+ # discard operator methods
15
+ return if OPERATOR_METHODS.include?(method_name)
16
+
17
+ # we care only for the first argument
18
+ arg = args.first
19
+ return unless arg && arg.type == :hash && arg.children.any?
20
+
21
+ has_braces = !arg.loc.begin.nil?
22
+
23
+ if style == :no_braces && has_braces
24
+ convention(arg,
25
+ :expression,
26
+ 'Redundant curly braces around a hash parameter.')
27
+ elsif style == :braces && !has_braces
28
+ convention(arg,
29
+ :expression,
30
+ 'Missing curly braces around a hash parameter.')
31
+ end
32
+ end
33
+
34
+ private
35
+
36
+ def style
37
+ case cop_config['EnforcedStyle']
38
+ when 'braces' then :braces
39
+ when 'no_braces' then :no_braces
40
+ else fail 'Unknown style selected!'
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
@@ -7,6 +7,8 @@ module Rubocop
7
7
  # Comment lines can optionally be ignored.
8
8
  # The maximum allowed length is configurable.
9
9
  class ClassLength < Cop
10
+ include Util
11
+
10
12
  MSG = 'Class definition is too long. [%d/%d]'
11
13
 
12
14
  def on_class(node)
@@ -24,14 +26,35 @@ module Rubocop
24
26
  private
25
27
 
26
28
  def check(node)
27
- method_length = Util.source_length(node.loc.expression.source,
28
- count_comments?)
29
+ class_body_line_numbers = line_range(node).to_a[1...-1]
30
+
31
+ target_line_numbers = class_body_line_numbers -
32
+ line_numbers_of_inner_classes(node)
29
33
 
30
- if method_length > max_length
31
- message = sprintf(MSG, method_length, max_length)
34
+ class_length = target_line_numbers.reduce(0) do |length, line_number|
35
+ source_line = processed_source[line_number]
36
+ next length if source_line.blank?
37
+ next length if !count_comments? && comment_line?(source_line)
38
+ length + 1
39
+ end
40
+
41
+ if class_length > max_length
42
+ message = sprintf(MSG, class_length, max_length)
32
43
  convention(node, :keyword, message)
33
44
  end
34
45
  end
46
+
47
+ def line_numbers_of_inner_classes(node)
48
+ line_numbers = Set.new
49
+
50
+ on_node([:class, :module], node) do |inner_node|
51
+ next if inner_node.eql?(node)
52
+ line_range = line_range(inner_node)
53
+ line_numbers.merge(line_range)
54
+ end
55
+
56
+ line_numbers.to_a
57
+ end
35
58
  end
36
59
  end
37
60
  end
@@ -19,41 +19,39 @@ module Rubocop
19
19
  processed_source.comments
20
20
  )
21
21
 
22
- check_classes(ast, ast_with_comments)
23
- check_modules(ast, ast_with_comments)
22
+ check(ast, ast_with_comments)
24
23
  end
25
24
 
26
25
  private
27
26
 
28
- def check_classes(ast, ast_with_comments)
29
- on_node(:class, ast) do |node|
30
- _name, _superclass, body = *node
31
-
32
- if body && ast_with_comments[node].empty?
33
- convention(node, :keyword, format(MSG, 'class'))
27
+ def check(ast, ast_with_comments)
28
+ on_node([:class, :module], ast) do |node|
29
+ case node.type
30
+ when :class
31
+ _name, _superclass, body = *node
32
+ when :module
33
+ _name, body = *node
34
34
  end
35
+
36
+ next if node.type == :class && !body
37
+ next if namespace?(body)
38
+ next unless ast_with_comments[node].empty?
39
+ convention(node, :keyword, format(MSG, node.type.to_s))
35
40
  end
36
41
  end
37
42
 
38
- def check_modules(ast, ast_with_comments)
39
- on_node(:module, ast) do |node|
40
- _name, body = *node
41
-
42
- if body.nil?
43
- namespace = false
44
- elsif body.type == :begin
45
- namespace = body.children.all? do |n|
46
- [:class, :module].include?(n.type)
47
- end
48
- elsif body.type == :class || body.type == :module
49
- namespace = true
50
- else
51
- namespace = false
52
- end
43
+ def namespace?(body_node)
44
+ return false unless body_node
53
45
 
54
- if !namespace && ast_with_comments[node].empty?
55
- convention(node, :keyword, format(MSG, 'module'))
46
+ case body_node.type
47
+ when :begin
48
+ body_node.children.all? do |node|
49
+ [:class, :module].include?(node.type)
56
50
  end
51
+ when :class, :module
52
+ true
53
+ else
54
+ false
57
55
  end
58
56
  end
59
57
  end
@@ -34,7 +34,12 @@ module Rubocop
34
34
  arg, = *args
35
35
 
36
36
  if arg.type == :send && arg.loc.selector.is?('new')
37
- convention(node, :expression, message(selector))
37
+ _receiver, _selector, *constructor_args = *arg
38
+
39
+ # Allow code like `raise Ex.new(arg1, arg2)`.
40
+ unless constructor_args.size > 1
41
+ convention(node, :expression, message(selector))
42
+ end
38
43
  end
39
44
  end
40
45
 
@@ -0,0 +1,37 @@
1
+ # encoding: utf-8
2
+
3
+ module Rubocop
4
+ module Cop
5
+ module Style
6
+ # This cop checks for space after `!`.
7
+ #
8
+ # @example
9
+ # # bad
10
+ # ! something
11
+ #
12
+ # # good
13
+ # !something
14
+ class SpaceAfterNot < Cop
15
+ MSG = 'Do not leave space between `!` and its argument.'
16
+
17
+ def on_send(node)
18
+ _receiver, method_name, *_args = *node
19
+
20
+ return unless method_name == :!
21
+
22
+ if node.loc.expression.source =~ /^!\s+\w+/
23
+ # TODO: Improve source range to highlight the redundant whitespace.
24
+ convention(node, :selector)
25
+ end
26
+ end
27
+
28
+ def autocorrect(node)
29
+ @corrections << lambda do |corrector|
30
+ corrector.replace(node.loc.expression,
31
+ node.loc.expression.source.gsub(/\A!\s+/, '!'))
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
@@ -30,11 +30,28 @@ module Rubocop
30
30
 
31
31
  lines.reject!(&:blank?)
32
32
 
33
- lines.reject! { |line| line =~ /^\s*#/ } unless count_comments
33
+ lines.reject! { |line| comment_line?(line) } unless count_comments
34
34
 
35
35
  lines.size
36
36
  end
37
37
 
38
+ def comment_line?(line_source)
39
+ line_source =~ /^\s*#/
40
+ end
41
+
42
+ def line_range(arg)
43
+ source_range = case arg
44
+ when Parser::Source::Range
45
+ arg
46
+ when Parser::AST::Node
47
+ arg.loc.expression
48
+ else
49
+ fail ArgumentError, "Invalid argument #{arg}"
50
+ end
51
+
52
+ source_range.begin.line..source_range.end.line
53
+ end
54
+
38
55
  def const_name(node)
39
56
  return nil if node.nil? || node.type != :const
40
57
 
@@ -16,11 +16,20 @@ module Rubocop
16
16
 
17
17
  unless source_line.blank?
18
18
  output.puts(source_line)
19
- output.puts(' ' * o.location.column +
20
- '^' * o.location.column_range.count)
19
+ output.puts(highlight_line(o.location))
21
20
  end
22
21
  end
23
22
  end
23
+
24
+ def highlight_line(location)
25
+ column_length = if location.begin.line == location.end.line
26
+ location.column_range.count
27
+ else
28
+ location.source_line.length - location.column
29
+ end
30
+
31
+ ' ' * location.column + '^' * column_length
32
+ end
24
33
  end
25
34
  end
26
35
  end
@@ -38,7 +38,7 @@ module Rubocop
38
38
  @options[:formatters] = [
39
39
  [DEFAULT_FORMATTER],
40
40
  [Formatter::DisabledConfigFormatter,
41
- Config::AUTO_GENERATED_FILE]
41
+ ConfigLoader::AUTO_GENERATED_FILE]
42
42
  ]
43
43
  validate_auto_gen_config_option(args)
44
44
  end
@@ -148,8 +148,8 @@ module Rubocop
148
148
  target_finder.find(args).each do |file|
149
149
  config = @config_store.for(file)
150
150
  if @options[:auto_gen_config] && config.contains_auto_generated_config
151
- fail "Remove #{Config::AUTO_GENERATED_FILE} from the current " +
152
- 'configuration before generating it again.'
151
+ fail "Remove #{ConfigLoader::AUTO_GENERATED_FILE} from the " +
152
+ 'current configuration before generating it again.'
153
153
  end
154
154
  end
155
155
  end
@@ -3,7 +3,7 @@
3
3
  module Rubocop
4
4
  # This module holds the RuboCop version information.
5
5
  module Version
6
- STRING = '0.14.0'
6
+ STRING = '0.14.1'
7
7
 
8
8
  MSG = '%s (using Parser %s, running on %s %s %s)'
9
9
 
@@ -6,12 +6,12 @@ describe 'RuboCop Project' do
6
6
  describe 'default configuration file' do
7
7
  it 'has configuration for all cops' do
8
8
  cop_names = Rubocop::Cop::Cop.all.map(&:cop_name)
9
- expect(Rubocop::Config.load_file('config/default.yml').keys.sort)
9
+ expect(Rubocop::ConfigLoader.load_file('config/default.yml').keys.sort)
10
10
  .to eq((['AllCops'] + cop_names).sort)
11
11
  end
12
12
  it 'has a description for all cops' do
13
13
  cop_names = Rubocop::Cop::Cop.all.map(&:cop_name)
14
- conf = Rubocop::Config.load_file('config/default.yml')
14
+ conf = Rubocop::ConfigLoader.load_file('config/default.yml')
15
15
  cop_names.each do |name|
16
16
  expect(conf[name]['Description']).not_to be_nil
17
17
  end
@@ -12,7 +12,7 @@ describe Rubocop::CLI, :isolated_environment do
12
12
  before(:each) do
13
13
  $stdout = StringIO.new
14
14
  $stderr = StringIO.new
15
- Rubocop::Config.debug = false
15
+ Rubocop::ConfigLoader.debug = false
16
16
  end
17
17
 
18
18
  after(:each) do
@@ -0,0 +1,314 @@
1
+ # encoding: utf-8
2
+
3
+ require 'spec_helper'
4
+
5
+ DEFAULT_CONFIG = Rubocop::ConfigLoader.load_file('config/default.yml')
6
+
7
+ describe Rubocop::ConfigLoader do
8
+ include FileHelper
9
+
10
+ describe '.configuration_file_for', :isolated_environment do
11
+ subject(:configuration_file_for) do
12
+ described_class.configuration_file_for(dir_path)
13
+ end
14
+
15
+ context 'when no config file exists in ancestor directories' do
16
+ let(:dir_path) { 'dir' }
17
+ before { create_file('dir/example.rb', '') }
18
+
19
+ context 'but a config file exists in home directory' do
20
+ before { create_file('~/.rubocop.yml', '') }
21
+
22
+ it 'returns the path to the file in home directory' do
23
+ expect(configuration_file_for).to end_with('home/.rubocop.yml')
24
+ end
25
+ end
26
+
27
+ context 'and no config file exists in home directory' do
28
+ it 'falls back to the provided default file' do
29
+ expect(configuration_file_for).to end_with('config/default.yml')
30
+ end
31
+ end
32
+ end
33
+
34
+ context 'when a config file exists in the parent directory' do
35
+ let(:dir_path) { 'dir' }
36
+
37
+ before do
38
+ create_file('dir/example.rb', '')
39
+ create_file('.rubocop.yml', '')
40
+ end
41
+
42
+ it 'returns the path to that configuration file' do
43
+ expect(configuration_file_for).to end_with('work/.rubocop.yml')
44
+ end
45
+ end
46
+
47
+ context 'when multiple config files exist in ancestor directories' do
48
+ let(:dir_path) { 'dir' }
49
+
50
+ before do
51
+ create_file('dir/example.rb', '')
52
+ create_file('dir/.rubocop.yml', '')
53
+ create_file('.rubocop.yml', '')
54
+ end
55
+
56
+ it 'prefers closer config file' do
57
+ expect(configuration_file_for).to end_with('dir/.rubocop.yml')
58
+ end
59
+ end
60
+ end
61
+
62
+ describe '.configuration_from_file', :isolated_environment do
63
+ subject(:configuration_from_file) do
64
+ described_class.configuration_from_file(file_path)
65
+ end
66
+
67
+ context 'with any config file' do
68
+ let(:file_path) { '.rubocop.yml' }
69
+
70
+ before do
71
+ create_file(file_path, ['Encoding:',
72
+ ' Enabled: false'])
73
+ end
74
+ it 'returns a configuration inheriting from default.yml' do
75
+ config = DEFAULT_CONFIG['Encoding'].dup
76
+ config['Enabled'] = false
77
+ expect(configuration_from_file)
78
+ .to eql(DEFAULT_CONFIG.merge('Encoding' => config))
79
+ end
80
+ end
81
+
82
+ context 'when multiple config files exist in ancestor directories' do
83
+ let(:file_path) { 'dir/.rubocop.yml' }
84
+
85
+ before do
86
+ create_file('.rubocop.yml',
87
+ ['AllCops:',
88
+ ' Excludes:',
89
+ ' - vendor/**',
90
+ ])
91
+
92
+ create_file(file_path,
93
+ ['AllCops:',
94
+ ' Excludes: []',
95
+ ])
96
+ end
97
+
98
+ it 'gets AllCops/Excludes from the highest directory level' do
99
+ excludes = configuration_from_file['AllCops']['Excludes']
100
+ expect(excludes).to eq([File.expand_path('vendor/**')])
101
+ end
102
+ end
103
+
104
+ context 'when a file inherits from a parent file' do
105
+ let(:file_path) { 'dir/.rubocop.yml' }
106
+
107
+ before do
108
+ create_file('.rubocop.yml',
109
+ ['AllCops:',
110
+ ' Excludes:',
111
+ ' - vendor/**',
112
+ ' - !ruby/regexp /[A-Z]/',
113
+ ])
114
+
115
+ create_file(file_path, ['inherit_from: ../.rubocop.yml'])
116
+ end
117
+
118
+ it 'gets an absolute AllCops/Excludes' do
119
+ excludes = configuration_from_file['AllCops']['Excludes']
120
+ expect(excludes).to eq([File.expand_path('vendor/**'), /[A-Z]/])
121
+ end
122
+ end
123
+
124
+ context 'when a file inherits from a sibling file' do
125
+ let(:file_path) { 'dir/.rubocop.yml' }
126
+
127
+ before do
128
+ create_file('src/.rubocop.yml',
129
+ ['AllCops:',
130
+ ' Excludes:',
131
+ ' - vendor/**',
132
+ ])
133
+
134
+ create_file(file_path, ['inherit_from: ../src/.rubocop.yml'])
135
+ end
136
+
137
+ it 'gets an absolute AllCops/Exclude' do
138
+ excludes = configuration_from_file['AllCops']['Excludes']
139
+ expect(excludes).to eq([File.expand_path('src/vendor/**')])
140
+ end
141
+ end
142
+
143
+ context 'when a file inherits from a parent and grandparent file' do
144
+ let(:file_path) { 'dir/subdir/.rubocop.yml' }
145
+
146
+ before do
147
+ create_file('dir/subdir/example.rb', '')
148
+
149
+ create_file('.rubocop.yml',
150
+ ['LineLength:',
151
+ ' Enabled: false',
152
+ ' Max: 77'])
153
+
154
+ create_file('dir/.rubocop.yml',
155
+ ['inherit_from: ../.rubocop.yml',
156
+ '',
157
+ 'MethodLength:',
158
+ ' Enabled: true',
159
+ ' CountComments: false',
160
+ ' Max: 10'
161
+ ])
162
+
163
+ create_file(file_path,
164
+ ['inherit_from: ../.rubocop.yml',
165
+ '',
166
+ 'LineLength:',
167
+ ' Enabled: true',
168
+ '',
169
+ 'MethodLength:',
170
+ ' Max: 5'
171
+ ])
172
+ end
173
+
174
+ it 'returns the ancestor configuration plus local overrides' do
175
+ config = DEFAULT_CONFIG
176
+ .merge('LineLength' => {
177
+ 'Description' =>
178
+ DEFAULT_CONFIG['LineLength']['Description'],
179
+ 'Enabled' => true,
180
+ 'Max' => 77
181
+ },
182
+ 'MethodLength' => {
183
+ 'Description' =>
184
+ DEFAULT_CONFIG['MethodLength']['Description'],
185
+ 'Enabled' => true,
186
+ 'CountComments' => false,
187
+ 'Max' => 5
188
+ })
189
+ expect(configuration_from_file).to eq(config)
190
+ end
191
+ end
192
+
193
+ context 'when a file inherits from two configurations' do
194
+ let(:file_path) { '.rubocop.yml' }
195
+
196
+ before do
197
+ create_file('example.rb', '')
198
+
199
+ create_file('normal.yml',
200
+ ['MethodLength:',
201
+ ' Enabled: false',
202
+ ' CountComments: true',
203
+ ' Max: 79'])
204
+
205
+ create_file('special.yml',
206
+ ['MethodLength:',
207
+ ' Enabled: false',
208
+ ' Max: 200'])
209
+
210
+ create_file(file_path,
211
+ ['inherit_from:',
212
+ ' - normal.yml',
213
+ ' - special.yml',
214
+ '',
215
+ 'MethodLength:',
216
+ ' Enabled: true'
217
+ ])
218
+ end
219
+
220
+ it 'returns values from the last one when possible' do
221
+ expected = { 'Enabled' => true, # overridden in .rubocop.yml
222
+ 'CountComments' => true, # only defined in normal.yml
223
+ 'Max' => 200 } # special.yml takes precedence
224
+ expect(configuration_from_file['MethodLength'].to_set)
225
+ .to be_superset(expected.to_set)
226
+ end
227
+ end
228
+ end
229
+
230
+ describe '.load_file', :isolated_environment do
231
+ subject(:load_file) do
232
+ described_class.load_file(configuration_path)
233
+ end
234
+
235
+ let(:configuration_path) { '.rubocop.yml' }
236
+
237
+ it 'returns a configuration loaded from the passed path' do
238
+ create_file(configuration_path, [
239
+ 'Encoding:',
240
+ ' Enabled: true',
241
+ ])
242
+ configuration = load_file
243
+ expect(configuration['Encoding']).to eq(
244
+ 'Enabled' => true
245
+ )
246
+ end
247
+ end
248
+
249
+ describe '.merge' do
250
+ subject(:merge) { described_class.merge(base, derived) }
251
+
252
+ let(:base) do
253
+ {
254
+ 'AllCops' => {
255
+ 'Includes' => ['**/*.gemspec', '**/Rakefile'],
256
+ 'Excludes' => []
257
+ }
258
+ }
259
+ end
260
+ let(:derived) do
261
+ { 'AllCops' => { 'Excludes' => ['example.rb', 'exclude_*'] } }
262
+ end
263
+
264
+ it 'returns a recursive merge of its two arguments' do
265
+ expect(merge).to eq('AllCops' => {
266
+ 'Includes' => ['**/*.gemspec', '**/Rakefile'],
267
+ 'Excludes' => ['example.rb', 'exclude_*']
268
+ })
269
+ end
270
+ end
271
+
272
+ describe 'configuration for SymbolArray', :isolated_environment do
273
+ let(:config) do
274
+ config_path = described_class.configuration_file_for('.')
275
+ described_class.configuration_from_file(config_path)
276
+ end
277
+
278
+ context 'when no config file exists for the target file' do
279
+ it 'is disabled' do
280
+ expect(config.cop_enabled?('SymbolArray')).to be_false
281
+ end
282
+ end
283
+
284
+ context 'when a config file which does not mention SymbolArray exists' do
285
+ it 'is disabled' do
286
+ create_file('.rubocop.yml', [
287
+ 'LineLength:',
288
+ ' Max: 79'
289
+ ])
290
+ expect(config.cop_enabled?('SymbolArray')).to be_false
291
+ end
292
+ end
293
+
294
+ context 'when a config file which explicitly enables SymbolArray exists' do
295
+ it 'is enabled' do
296
+ create_file('.rubocop.yml', [
297
+ 'SymbolArray:',
298
+ ' Enabled: true'
299
+ ])
300
+ expect(config.cop_enabled?('SymbolArray')).to be_true
301
+ end
302
+ end
303
+ end
304
+
305
+ describe 'configuration for SymbolName' do
306
+ describe 'AllowCamelCase' do
307
+ it 'is enabled by default' do
308
+ default_config = described_class.default_configuration
309
+ symbol_name_config = default_config.for_cop('SymbolName')
310
+ expect(symbol_name_config['AllowCamelCase']).to be_true
311
+ end
312
+ end
313
+ end
314
+ end