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.
- checksums.yaml +4 -4
- data/.rubocop.yml +1 -1
- data/CHANGELOG.md +15 -0
- data/README.md +1 -1
- data/config/default.yml +4 -0
- data/config/enabled.yml +16 -8
- data/lib/rubocop.rb +3 -0
- data/lib/rubocop/cli.rb +1 -1
- data/lib/rubocop/config.rb +3 -160
- data/lib/rubocop/config_loader.rb +156 -0
- data/lib/rubocop/config_store.rb +6 -6
- data/lib/rubocop/cop/style/align_hash.rb +15 -11
- data/lib/rubocop/cop/style/braces_around_hash_parameters.rb +46 -0
- data/lib/rubocop/cop/style/class_length.rb +27 -4
- data/lib/rubocop/cop/style/documentation.rb +23 -25
- data/lib/rubocop/cop/style/raise_args.rb +6 -1
- data/lib/rubocop/cop/style/space_after_not.rb +37 -0
- data/lib/rubocop/cop/util.rb +18 -1
- data/lib/rubocop/formatter/clang_style_formatter.rb +11 -2
- data/lib/rubocop/options.rb +3 -3
- data/lib/rubocop/version.rb +1 -1
- data/spec/project_spec.rb +2 -2
- data/spec/rubocop/cli_spec.rb +1 -1
- data/spec/rubocop/config_loader_spec.rb +314 -0
- data/spec/rubocop/config_spec.rb +1 -308
- data/spec/rubocop/config_store_spec.rb +9 -9
- data/spec/rubocop/cop/lint/shadowing_outer_local_variable_spec.rb +1 -1
- data/spec/rubocop/cop/lint/useless_assignment_spec.rb +3 -3
- data/spec/rubocop/cop/style/align_hash_spec.rb +17 -20
- data/spec/rubocop/cop/style/braces_around_hash_parameters_spec.rb +193 -0
- data/spec/rubocop/cop/style/class_length_spec.rb +64 -0
- data/spec/rubocop/cop/style/documentation_spec.rb +10 -0
- data/spec/rubocop/cop/style/indentation_width_spec.rb +0 -7
- data/spec/rubocop/cop/style/numeric_literals_spec.rb +1 -1
- data/spec/rubocop/cop/style/raise_args_spec.rb +5 -0
- data/spec/rubocop/cop/style/space_after_not_spec.rb +22 -0
- data/spec/rubocop/cop/team_spec.rb +1 -1
- data/spec/rubocop/cop/util_spec.rb +49 -0
- data/spec/rubocop/formatter/clang_style_formatter_spec.rb +42 -16
- data/spec/rubocop/options_spec.rb +3 -2
- data/spec/spec_helper.rb +1 -1
- metadata +13 -2
data/lib/rubocop/config_store.rb
CHANGED
@@ -20,20 +20,20 @@ module Rubocop
|
|
20
20
|
end
|
21
21
|
|
22
22
|
def set_options_config(options_config)
|
23
|
-
loaded_config =
|
24
|
-
@options_config =
|
25
|
-
|
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] ||=
|
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
|
36
|
-
|
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
|
-
|
16
|
-
|
15
|
+
styles = [cop_config['EnforcedHashRocketStyle'],
|
16
|
+
cop_config['EnforcedColonStyle']]
|
17
17
|
|
18
|
-
|
19
|
-
|
20
|
-
|
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 &&
|
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
|
-
|
28
|
-
|
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
|
-
|
31
|
-
|
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
|
-
|
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
|
29
|
-
on_node(:class, ast) do |node|
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
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
|
39
|
-
|
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
|
-
|
55
|
-
|
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
|
-
|
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
|
data/lib/rubocop/cop/util.rb
CHANGED
@@ -30,11 +30,28 @@ module Rubocop
|
|
30
30
|
|
31
31
|
lines.reject!(&:blank?)
|
32
32
|
|
33
|
-
lines.reject! { |line| line
|
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(
|
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
|
data/lib/rubocop/options.rb
CHANGED
@@ -38,7 +38,7 @@ module Rubocop
|
|
38
38
|
@options[:formatters] = [
|
39
39
|
[DEFAULT_FORMATTER],
|
40
40
|
[Formatter::DisabledConfigFormatter,
|
41
|
-
|
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 #{
|
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
|
data/lib/rubocop/version.rb
CHANGED
data/spec/project_spec.rb
CHANGED
@@ -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::
|
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::
|
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
|
data/spec/rubocop/cli_spec.rb
CHANGED
@@ -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
|