rubocop 0.14.1 → 0.15.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of rubocop might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/.rubocop.yml +5 -3
- data/CHANGELOG.md +245 -198
- data/README.md +7 -0
- data/Rakefile +5 -1
- data/config/default.yml +27 -4
- data/config/enabled.yml +18 -4
- data/lib/rubocop.rb +13 -1
- data/lib/rubocop/cli.rb +83 -23
- data/lib/rubocop/config.rb +1 -1
- data/lib/rubocop/cop/cop.rb +31 -6
- data/lib/rubocop/cop/lint/block_alignment.rb +11 -8
- data/lib/rubocop/cop/lint/parentheses_as_grouped_expression.rb +21 -14
- data/lib/rubocop/cop/lint/useless_setter_call.rb +1 -1
- data/lib/rubocop/cop/rails/output.rb +35 -0
- data/lib/rubocop/cop/style/{access_control.rb → access_modifier_indentation.rb} +18 -15
- data/lib/rubocop/cop/style/alias.rb +14 -2
- data/lib/rubocop/cop/style/align_hash.rb +174 -109
- data/lib/rubocop/cop/style/autocorrect_alignment.rb +38 -18
- data/lib/rubocop/cop/style/blocks.rb +4 -6
- data/lib/rubocop/cop/style/braces_around_hash_parameters.rb +3 -3
- data/lib/rubocop/cop/style/cyclomatic_complexity.rb +46 -0
- data/lib/rubocop/cop/style/empty_lines_around_access_modifier.rb +48 -0
- data/lib/rubocop/cop/style/empty_lines_around_body.rb +62 -0
- data/lib/rubocop/cop/style/end_of_line.rb +6 -2
- data/lib/rubocop/cop/style/favor_modifier.rb +11 -1
- data/lib/rubocop/cop/style/final_newline.rb +10 -4
- data/lib/rubocop/cop/style/hash_syntax.rb +32 -21
- data/lib/rubocop/cop/style/leading_comment_space.rb +9 -0
- data/lib/rubocop/cop/style/method_call_parentheses.rb +11 -1
- data/lib/rubocop/cop/style/numeric_literals.rb +11 -15
- data/lib/rubocop/cop/style/redundant_return.rb +7 -4
- data/lib/rubocop/cop/style/redundant_self.rb +3 -3
- data/lib/rubocop/cop/style/signal_exception.rb +4 -2
- data/lib/rubocop/cop/style/space_after_comma_etc.rb +7 -1
- data/lib/rubocop/cop/style/space_after_control_keyword.rb +6 -0
- data/lib/rubocop/cop/style/space_after_method_name.rb +7 -1
- data/lib/rubocop/cop/style/space_after_not.rb +6 -2
- data/lib/rubocop/cop/style/space_around_block_braces.rb +149 -0
- data/lib/rubocop/cop/style/space_around_equals_in_parameter_default.rb +33 -0
- data/lib/rubocop/cop/style/space_around_operators.rb +169 -0
- data/lib/rubocop/cop/style/space_before_modifier_keyword.rb +6 -0
- data/lib/rubocop/cop/style/space_inside.rb +35 -0
- data/lib/rubocop/cop/style/space_inside_brackets.rb +18 -0
- data/lib/rubocop/cop/style/space_inside_hash_literal_braces.rb +99 -0
- data/lib/rubocop/cop/style/space_inside_parens.rb +18 -0
- data/lib/rubocop/cop/style/special_global_vars.rb +52 -25
- data/lib/rubocop/cop/style/string_literals.rb +1 -1
- data/lib/rubocop/cop/style/surrounding_space.rb +1 -344
- data/lib/rubocop/cop/style/trailing_blank_lines.rb +17 -5
- data/lib/rubocop/cop/style/trailing_whitespace.rb +9 -5
- data/lib/rubocop/cop/style/trivial_accessors.rb +1 -2
- data/lib/rubocop/cop/style/word_array.rb +16 -1
- data/lib/rubocop/cop/team.rb +5 -5
- data/lib/rubocop/cop/util.rb +1 -0
- data/lib/rubocop/formatter/offence_count_formatter.rb +0 -1
- data/lib/rubocop/options.rb +76 -111
- data/lib/rubocop/rake_task.rb +4 -2
- data/lib/rubocop/target_finder.rb +3 -3
- data/lib/rubocop/version.rb +1 -1
- data/spec/rubocop/cli_spec.rb +123 -13
- data/spec/rubocop/config_spec.rb +2 -2
- data/spec/rubocop/cop/lint/rescue_exception_spec.rb +10 -0
- data/spec/rubocop/cop/lint/useless_setter_call_spec.rb +13 -0
- data/spec/rubocop/cop/offence_spec.rb +2 -0
- data/spec/rubocop/cop/rails/output_spec.rb +40 -0
- data/spec/rubocop/cop/style/access_modifier_indentation_spec.rb +243 -0
- data/spec/rubocop/cop/style/alias_spec.rb +8 -0
- data/spec/rubocop/cop/style/align_array_spec.rb +12 -0
- data/spec/rubocop/cop/style/align_hash_spec.rb +15 -0
- data/spec/rubocop/cop/style/braces_around_hash_parameters_spec.rb +7 -4
- data/spec/rubocop/cop/style/cyclomatic_complexity_spec.rb +203 -0
- data/spec/rubocop/cop/style/empty_lines_around_access_modifier_spec.rb +56 -0
- data/spec/rubocop/cop/style/empty_lines_around_body_spec.rb +87 -0
- data/spec/rubocop/cop/style/end_of_line_spec.rb +17 -8
- data/spec/rubocop/cop/style/favor_modifier_spec.rb +34 -0
- data/spec/rubocop/cop/style/final_newline_spec.rb +5 -0
- data/spec/rubocop/cop/style/hash_syntax_spec.rb +22 -2
- data/spec/rubocop/cop/style/leading_comment_space_spec.rb +5 -0
- data/spec/rubocop/cop/style/method_call_parentheses_spec.rb +39 -4
- data/spec/rubocop/cop/style/numeric_literals_spec.rb +5 -0
- data/spec/rubocop/cop/style/signal_exception_spec.rb +11 -0
- data/spec/rubocop/cop/style/space_after_colon_spec.rb +7 -0
- data/spec/rubocop/cop/style/space_after_comma_spec.rb +5 -0
- data/spec/rubocop/cop/style/space_after_control_keyword_spec.rb +29 -8
- data/spec/rubocop/cop/style/space_after_method_name_spec.rb +15 -0
- data/spec/rubocop/cop/style/space_after_semicolon_spec.rb +5 -0
- data/spec/rubocop/cop/style/space_around_block_braces_spec.rb +68 -0
- data/spec/rubocop/cop/style/space_around_equals_in_default_parameter_spec.rb +5 -0
- data/spec/rubocop/cop/style/space_around_operators_spec.rb +43 -0
- data/spec/rubocop/cop/style/space_before_modifier_keyword_spec.rb +23 -0
- data/spec/rubocop/cop/style/space_inside_brackets_spec.rb +7 -0
- data/spec/rubocop/cop/style/space_inside_hash_literal_braces_spec.rb +65 -23
- data/spec/rubocop/cop/style/space_inside_parens_spec.rb +7 -0
- data/spec/rubocop/cop/style/special_global_vars_spec.rb +12 -2
- data/spec/rubocop/cop/style/string_literals_spec.rb +6 -0
- data/spec/rubocop/cop/style/symbol_array_spec.rb +5 -7
- data/spec/rubocop/cop/style/trailing_blank_lines_spec.rb +26 -1
- data/spec/rubocop/cop/style/trailing_whitespace_spec.rb +7 -0
- data/spec/rubocop/cop/style/trivial_accessors_spec.rb +8 -0
- data/spec/rubocop/cop/style/word_array_spec.rb +33 -2
- data/spec/rubocop/cop/team_spec.rb +4 -4
- data/spec/rubocop/formatter/json_formatter_spec.rb +1 -1
- data/spec/rubocop/options_spec.rb +5 -96
- data/spec/rubocop/processed_source_spec.rb +3 -3
- data/spec/spec_helper.rb +28 -23
- data/spec/support/mri_syntax_checker.rb +20 -16
- metadata +24 -5
- data/spec/rubocop/cop/style/access_control_spec.rb +0 -164
@@ -13,26 +13,15 @@ module Rubocop
|
|
13
13
|
MSG = '(...) interpreted as grouped expression.'
|
14
14
|
|
15
15
|
def on_send(node)
|
16
|
-
|
16
|
+
_receiver, method_name, args = *node
|
17
17
|
if OPERATOR_METHODS.include?(method_name) ||
|
18
18
|
method_name.to_s.end_with?('=')
|
19
19
|
return
|
20
20
|
end
|
21
21
|
if args && args.loc.expression.source.start_with?('(')
|
22
|
-
|
23
|
-
|
24
|
-
else
|
25
|
-
0
|
26
|
-
end
|
27
|
-
without_receiver = node.loc.expression.source[receiver_length..-1]
|
28
|
-
|
29
|
-
# Escape question mark if any.
|
30
|
-
method_regexp = Regexp.escape(method_name)
|
31
|
-
|
32
|
-
if (match =
|
33
|
-
without_receiver.match(/^\s*\.?\s*#{method_regexp}(\s+)\(/))
|
22
|
+
space_length = spaces_before_left_parenthesis(node)
|
23
|
+
if space_length > 0
|
34
24
|
expr = args.loc.expression
|
35
|
-
space_length = match.captures[0].length
|
36
25
|
space_range =
|
37
26
|
Parser::Source::Range.new(expr.source_buffer,
|
38
27
|
expr.begin_pos - space_length,
|
@@ -41,6 +30,24 @@ module Rubocop
|
|
41
30
|
end
|
42
31
|
end
|
43
32
|
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
def spaces_before_left_parenthesis(node)
|
37
|
+
receiver, method_name, _args = *node
|
38
|
+
receiver_length = if receiver
|
39
|
+
receiver.loc.expression.source.length
|
40
|
+
else
|
41
|
+
0
|
42
|
+
end
|
43
|
+
without_receiver = node.loc.expression.source[receiver_length..-1]
|
44
|
+
|
45
|
+
# Escape question mark if any.
|
46
|
+
method_regexp = Regexp.escape(method_name)
|
47
|
+
|
48
|
+
match = without_receiver.match(/^\s*\.?\s*#{method_regexp}(\s+)\(/)
|
49
|
+
match ? match.captures[0].length : 0
|
50
|
+
end
|
44
51
|
end
|
45
52
|
end
|
46
53
|
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module Rubocop
|
4
|
+
module Cop
|
5
|
+
module Rails
|
6
|
+
# This cop checks for the use of output calls like puts and print
|
7
|
+
class Output < Cop
|
8
|
+
MSG = 'Do not write to stdout. Use Rails\' logger if you want to log.'
|
9
|
+
|
10
|
+
BLACKLIST = [:puts,
|
11
|
+
:print,
|
12
|
+
:p,
|
13
|
+
:pp,
|
14
|
+
:pretty_print]
|
15
|
+
|
16
|
+
def on_send(node)
|
17
|
+
return if matches_blacklist?(processed_source)
|
18
|
+
receiver, method_name, *_args = *node
|
19
|
+
|
20
|
+
if receiver.nil? && BLACKLIST.include?(method_name)
|
21
|
+
convention(node, :selector)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def matches_blacklist?(source)
|
26
|
+
ignore_paths.any? { |regex| source.buffer.name =~ /#{regex}/ }
|
27
|
+
end
|
28
|
+
|
29
|
+
def ignore_paths
|
30
|
+
cop_config['Ignore']
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -6,9 +6,8 @@ module Rubocop
|
|
6
6
|
# A couple of checks related to the use method visibility modifiers.
|
7
7
|
# Modifiers should be indented as deeps are method definitions and
|
8
8
|
# surrounded by blank lines.
|
9
|
-
class
|
10
|
-
|
11
|
-
BLANK_MSG = 'Keep a blank line before and after %s.'
|
9
|
+
class AccessModifierIndentation < Cop
|
10
|
+
MSG = '%s access modifiers like %s.'
|
12
11
|
|
13
12
|
PRIVATE_NODE = s(:send, nil, :private)
|
14
13
|
PROTECTED_NODE = s(:send, nil, :protected)
|
@@ -30,19 +29,9 @@ module Rubocop
|
|
30
29
|
on_node(:send, node, [:class, :module, :sclass]) do |send_node|
|
31
30
|
if modifier_node?(send_node)
|
32
31
|
send_start_col = send_node.loc.expression.column
|
33
|
-
selector = send_node.loc.selector.source
|
34
32
|
|
35
|
-
if send_start_col
|
36
|
-
convention(send_node, :expression
|
37
|
-
format(INDENT_MSG, selector))
|
38
|
-
end
|
39
|
-
|
40
|
-
send_line = send_node.loc.line
|
41
|
-
|
42
|
-
unless processed_source[send_line].chomp.empty? &&
|
43
|
-
processed_source[send_line - 2].chomp.empty?
|
44
|
-
convention(send_node, :expression,
|
45
|
-
format(BLANK_MSG, selector))
|
33
|
+
if send_start_col != class_start_col + expected_indent_offset
|
34
|
+
convention(send_node, :expression)
|
46
35
|
end
|
47
36
|
end
|
48
37
|
end
|
@@ -52,6 +41,12 @@ module Rubocop
|
|
52
41
|
|
53
42
|
private
|
54
43
|
|
44
|
+
def message(node)
|
45
|
+
format(MSG,
|
46
|
+
cop_config['EnforcedStyle'].capitalize,
|
47
|
+
node.loc.selector.source)
|
48
|
+
end
|
49
|
+
|
55
50
|
def class_constructor?(block_node)
|
56
51
|
send_node = block_node.children.first
|
57
52
|
receiver_node, method_name, *_ = *send_node
|
@@ -59,6 +54,14 @@ module Rubocop
|
|
59
54
|
%w(Class Module).include?(Util.const_name(receiver_node))
|
60
55
|
end
|
61
56
|
|
57
|
+
def expected_indent_offset
|
58
|
+
case cop_config['EnforcedStyle'].downcase
|
59
|
+
when 'outdent' then 0
|
60
|
+
when 'indent' then 2
|
61
|
+
else fail 'Unknown EnforcedStyle specified'
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
62
65
|
def modifier_node?(node)
|
63
66
|
[PRIVATE_NODE, PROTECTED_NODE, PUBLIC_NODE].include?(node)
|
64
67
|
end
|
@@ -8,9 +8,21 @@ module Rubocop
|
|
8
8
|
class Alias < Cop
|
9
9
|
MSG = 'Use alias_method instead of alias.'
|
10
10
|
|
11
|
-
|
12
|
-
|
11
|
+
def on_block(node)
|
12
|
+
method, _args, body = *node
|
13
|
+
|
14
|
+
_receiver, method_name = *method
|
15
|
+
|
16
|
+
# using alias is the only option in certain scenarios
|
17
|
+
# in such scenarios we don't want to report an offence
|
18
|
+
if method_name == :instance_exec
|
19
|
+
on_node(:alias, body) { |n| ignore_node(n) }
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
13
23
|
def on_alias(node)
|
24
|
+
return if ignored_node?(node)
|
25
|
+
|
14
26
|
# alias_method can't be used with global variables
|
15
27
|
new, old = *node
|
16
28
|
|
@@ -6,154 +6,219 @@ module Rubocop
|
|
6
6
|
# Here we check if the keys, separators, and values of a multi-line hash
|
7
7
|
# literal are aligned.
|
8
8
|
class AlignHash < Cop
|
9
|
-
|
10
|
-
|
9
|
+
# Handles calculation of deltas (deviations from correct alignment)
|
10
|
+
# when the enforced style is 'key'.
|
11
|
+
class KeyAlignment
|
12
|
+
def checkable_layout(_node)
|
13
|
+
true
|
14
|
+
end
|
11
15
|
|
12
|
-
|
13
|
-
|
16
|
+
def deltas_for_first_pair(*_)
|
17
|
+
{} # The first pair is always considered correct.
|
18
|
+
end
|
19
|
+
|
20
|
+
def deltas(first_pair, prev_pair, current_pair)
|
21
|
+
if current_pair.loc.line == prev_pair.loc.line
|
22
|
+
{}
|
23
|
+
else
|
24
|
+
{ key: first_pair.loc.column - current_pair.loc.column }
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
14
28
|
|
15
|
-
|
16
|
-
|
29
|
+
# Common functionality for the styles where not only keys, but also
|
30
|
+
# values are aligned.
|
31
|
+
class AlignmentOfValues
|
32
|
+
def checkable_layout(node)
|
33
|
+
!any_pairs_on_the_same_line?(node) && all_have_same_sparator?(node)
|
34
|
+
end
|
35
|
+
|
36
|
+
def deltas(first_pair, prev_pair, current_pair)
|
37
|
+
key_delta = key_delta(first_pair, current_pair)
|
38
|
+
current_separator = current_pair.loc.operator
|
39
|
+
separator_delta = separator_delta(first_pair, current_separator,
|
40
|
+
key_delta)
|
41
|
+
value_delta = value_delta(first_pair, current_pair) -
|
42
|
+
key_delta - separator_delta
|
43
|
+
|
44
|
+
{ key: key_delta, separator: separator_delta, value: value_delta }
|
45
|
+
end
|
46
|
+
|
47
|
+
private
|
17
48
|
|
18
|
-
|
19
|
-
|
49
|
+
def any_pairs_on_the_same_line?(node)
|
50
|
+
lines_of_the_children = node.children.map do |pair|
|
51
|
+
key, _value = *pair
|
52
|
+
key.loc.line
|
53
|
+
end
|
54
|
+
lines_of_the_children.uniq.size < lines_of_the_children.size
|
55
|
+
end
|
56
|
+
|
57
|
+
def all_have_same_sparator?(node)
|
58
|
+
first_separator = node.children.first.loc.operator.source
|
59
|
+
node.children[1..-1].all? do |pair|
|
60
|
+
pair.loc.operator.is?(first_separator)
|
61
|
+
end
|
20
62
|
end
|
63
|
+
end
|
21
64
|
|
22
|
-
|
65
|
+
# Handles calculation of deltas when the enforced style is 'table'.
|
66
|
+
class TableAlignment < AlignmentOfValues
|
67
|
+
# The table style is the only one where the first key-value pair can
|
68
|
+
# be considered to have bad alignment.
|
69
|
+
def deltas_for_first_pair(first_pair, node)
|
23
70
|
key_widths = node.children.map do |pair|
|
24
71
|
key, _value = *pair
|
25
72
|
key.loc.expression.source.length
|
26
73
|
end
|
27
74
|
@max_key_width = key_widths.max
|
28
|
-
|
29
|
-
|
30
|
-
|
75
|
+
|
76
|
+
separator_delta = separator_delta(first_pair,
|
77
|
+
first_pair.loc.operator, 0)
|
78
|
+
{
|
79
|
+
separator: separator_delta,
|
80
|
+
value: value_delta(first_pair, first_pair) - separator_delta
|
81
|
+
}
|
82
|
+
end
|
83
|
+
|
84
|
+
private
|
85
|
+
|
86
|
+
def key_delta(first_pair, current_pair)
|
87
|
+
first_pair.loc.column - current_pair.loc.column
|
88
|
+
end
|
89
|
+
|
90
|
+
def separator_delta(first_pair, current_separator, key_delta)
|
91
|
+
if current_separator.is?(':')
|
92
|
+
0 # Colon follows directly after key
|
93
|
+
else
|
94
|
+
first_pair.loc.column + @max_key_width + 1 -
|
95
|
+
current_separator.column - key_delta
|
31
96
|
end
|
32
97
|
end
|
33
98
|
|
34
|
-
|
35
|
-
|
36
|
-
|
99
|
+
def value_delta(first_pair, current_pair)
|
100
|
+
first_key, _ = *first_pair
|
101
|
+
_, current_value = *current_pair
|
102
|
+
correct_value_column = first_key.loc.column +
|
103
|
+
spaced_separator(current_pair).length + @max_key_width
|
104
|
+
correct_value_column - current_value.loc.column
|
37
105
|
end
|
38
|
-
end
|
39
106
|
|
40
|
-
|
41
|
-
|
42
|
-
key, _value = *pair
|
43
|
-
key.loc.line
|
107
|
+
def spaced_separator(node)
|
108
|
+
node.loc.operator.is?('=>') ? ' => ' : ': '
|
44
109
|
end
|
45
|
-
lines_of_the_children.uniq.size < lines_of_the_children.size
|
46
110
|
end
|
47
111
|
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
key_delta = @column_deltas[:key] || 0
|
112
|
+
# Handles calculation of deltas when the enforced style is 'separator'.
|
113
|
+
class SeparatorAlignment < AlignmentOfValues
|
114
|
+
def deltas_for_first_pair(first_pair, node)
|
115
|
+
{} # The first pair is always considered correct.
|
116
|
+
end
|
54
117
|
|
55
|
-
|
118
|
+
private
|
56
119
|
|
57
|
-
|
58
|
-
|
59
|
-
b = expr.begin_pos
|
60
|
-
b -= key_delta.abs if key_delta < 0
|
61
|
-
range = Parser::Source::Range.new(expr.source_buffer, b,
|
62
|
-
expr.end_pos)
|
63
|
-
source = ' ' * [key_delta, 0].max +
|
64
|
-
if enforced_style(node) == 'key'
|
65
|
-
expr.source
|
66
|
-
else
|
67
|
-
key_source = key.loc.expression.source
|
68
|
-
padded_separator = case enforced_style(node)
|
69
|
-
when 'separator'
|
70
|
-
spaced_separator(node)
|
71
|
-
when 'table'
|
72
|
-
space = ' ' * (max_key_width -
|
73
|
-
key_source.length)
|
74
|
-
if node.loc.operator.is?('=>')
|
75
|
-
space + spaced_separator(node)
|
76
|
-
else
|
77
|
-
spaced_separator(node) + space
|
78
|
-
end
|
79
|
-
end
|
80
|
-
key_source + padded_separator + value.loc.expression.source
|
81
|
-
end
|
82
|
-
corrector.replace(range, source)
|
120
|
+
def key_delta(first_pair, current_pair)
|
121
|
+
key_end_column(first_pair) - key_end_column(current_pair)
|
83
122
|
end
|
84
|
-
end
|
85
123
|
|
86
|
-
|
124
|
+
def key_end_column(pair)
|
125
|
+
key, _value = *pair
|
126
|
+
key.loc.column + key.loc.expression.source.length
|
127
|
+
end
|
87
128
|
|
88
|
-
|
89
|
-
|
129
|
+
def separator_delta(first_pair, current_separator, key_delta)
|
130
|
+
if current_separator.is?(':')
|
131
|
+
0 # Colon follows directly after key
|
132
|
+
else
|
133
|
+
first_pair.loc.operator.column - current_separator.column -
|
134
|
+
key_delta
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
def value_delta(first_pair, current_pair)
|
139
|
+
_, first_value = *first_pair
|
140
|
+
_, current_value = *current_pair
|
141
|
+
first_value.loc.column - current_value.loc.column
|
142
|
+
end
|
90
143
|
end
|
91
144
|
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
145
|
+
MSG = 'Align the elements of a hash literal if they span more than ' +
|
146
|
+
'one line.'
|
147
|
+
|
148
|
+
def on_hash(node)
|
149
|
+
return if node.children.empty?
|
150
|
+
|
151
|
+
@alignment_for_hash_rockets ||=
|
152
|
+
new_alignment('EnforcedHashRocketStyle')
|
153
|
+
@alignment_for_colons ||= new_alignment('EnforcedColonStyle')
|
154
|
+
|
155
|
+
first_pair = node.children.first
|
156
|
+
|
157
|
+
unless @alignment_for_hash_rockets.checkable_layout(node) &&
|
158
|
+
@alignment_for_colons.checkable_layout(node)
|
159
|
+
return
|
96
160
|
end
|
97
161
|
|
98
|
-
|
162
|
+
@column_deltas = alignment_for(first_pair)
|
163
|
+
.deltas_for_first_pair(first_pair, node)
|
164
|
+
convention(first_pair, :expression) unless good_alignment?
|
99
165
|
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
else
|
105
|
-
{
|
106
|
-
key: if enforced_style == 'table'
|
107
|
-
key_left_alignment_delta
|
108
|
-
else
|
109
|
-
key_end_column(first_pair) - key_end_column(current_pair)
|
110
|
-
end,
|
111
|
-
separator: if current_pair.loc.operator.is?(':') &&
|
112
|
-
enforced_style == 'table'
|
113
|
-
# Colon follows directly after key
|
114
|
-
(key_end_column(current_pair) -
|
115
|
-
current_pair.loc.operator.column)
|
116
|
-
else
|
117
|
-
# Aligned separator
|
118
|
-
(first_pair.loc.operator.column -
|
119
|
-
current_pair.loc.operator.column)
|
120
|
-
end,
|
121
|
-
value: value_delta(first_pair, current_pair, max_key_width)
|
122
|
-
}
|
166
|
+
node.children.each_cons(2) do |prev, current|
|
167
|
+
@column_deltas = alignment_for(current).deltas(first_pair, prev,
|
168
|
+
current)
|
169
|
+
convention(current, :expression) unless good_alignment?
|
123
170
|
end
|
124
171
|
end
|
125
172
|
|
126
|
-
|
127
|
-
|
128
|
-
|
173
|
+
private
|
174
|
+
|
175
|
+
def alignment_for(pair)
|
176
|
+
if pair.loc.operator.is?('=>')
|
177
|
+
@alignment_for_hash_rockets
|
178
|
+
else
|
179
|
+
@alignment_for_colons
|
180
|
+
end
|
129
181
|
end
|
130
182
|
|
131
|
-
def
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
183
|
+
def autocorrect(node)
|
184
|
+
# We can't use the instance variable inside the lambda. That would
|
185
|
+
# just give each lambda the same reference and they would all get the
|
186
|
+
# last value of each. Some local variables fix the problem.
|
187
|
+
key_delta = @column_deltas[:key] || 0
|
188
|
+
separator_delta = @column_deltas[:separator] || 0
|
189
|
+
value_delta = @column_deltas[:value] || 0
|
190
|
+
|
191
|
+
key, value = *node
|
192
|
+
|
193
|
+
@corrections << lambda do |corrector|
|
194
|
+
adjust(corrector, key_delta, key.loc.expression)
|
195
|
+
adjust(corrector, separator_delta, node.loc.operator)
|
196
|
+
adjust(corrector, value_delta, value.loc.expression)
|
197
|
+
end
|
144
198
|
end
|
145
199
|
|
146
|
-
def
|
147
|
-
|
200
|
+
def new_alignment(key)
|
201
|
+
case cop_config[key]
|
202
|
+
when 'key' then KeyAlignment.new
|
203
|
+
when 'table' then TableAlignment.new
|
204
|
+
when 'separator' then SeparatorAlignment.new
|
205
|
+
else fail "Unknown #{key}: #{cop_config[key]}"
|
206
|
+
end
|
148
207
|
end
|
149
208
|
|
150
|
-
def
|
151
|
-
|
209
|
+
def adjust(corrector, delta, range)
|
210
|
+
if delta > 0
|
211
|
+
corrector.insert_before(range, ' ' * delta)
|
212
|
+
elsif delta < 0
|
213
|
+
range = Parser::Source::Range.new(range.source_buffer,
|
214
|
+
range.begin_pos - delta.abs,
|
215
|
+
range.begin_pos)
|
216
|
+
corrector.remove(range)
|
217
|
+
end
|
152
218
|
end
|
153
219
|
|
154
|
-
def
|
155
|
-
|
156
|
-
"Enforced#{separator}Style"
|
220
|
+
def good_alignment?
|
221
|
+
@column_deltas.values.compact.none? { |v| v != 0 }
|
157
222
|
end
|
158
223
|
end
|
159
224
|
end
|