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
@@ -0,0 +1,35 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
# rubocop:disable SymbolName
|
4
|
+
|
5
|
+
module Rubocop
|
6
|
+
module Cop
|
7
|
+
module Style
|
8
|
+
# Common functionality for checking for spaces inside various
|
9
|
+
# kinds of parentheses.
|
10
|
+
module SpaceInside
|
11
|
+
include SurroundingSpace
|
12
|
+
MSG = 'Space inside %s detected.'
|
13
|
+
|
14
|
+
def investigate(processed_source)
|
15
|
+
@processed_source = processed_source
|
16
|
+
left, right, kind = specifics
|
17
|
+
processed_source.tokens.each_cons(2) do |t1, t2|
|
18
|
+
if t1.type == left || t2.type == right
|
19
|
+
if t2.pos.line == t1.pos.line && space_between?(t1, t2)
|
20
|
+
range = Parser::Source::Range.new(processed_source.buffer,
|
21
|
+
t1.pos.end_pos,
|
22
|
+
t2.pos.begin_pos)
|
23
|
+
convention(range, range, format(MSG, kind))
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def autocorrect(range)
|
30
|
+
@corrections << ->(corrector) { corrector.remove(range) }
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
# rubocop:disable SymbolName
|
4
|
+
|
5
|
+
module Rubocop
|
6
|
+
module Cop
|
7
|
+
module Style
|
8
|
+
# Checks for spaces inside square brackets.
|
9
|
+
class SpaceInsideBrackets < Cop
|
10
|
+
include SpaceInside
|
11
|
+
|
12
|
+
def specifics
|
13
|
+
[:tLBRACK, :tRBRACK, 'square brackets']
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,99 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
# rubocop:disable SymbolName
|
4
|
+
|
5
|
+
module Rubocop
|
6
|
+
module Cop
|
7
|
+
module Style
|
8
|
+
# Checks that braces used for hash literals have or don't have
|
9
|
+
# surrounding space depending on configuration.
|
10
|
+
class SpaceInsideHashLiteralBraces < Cop
|
11
|
+
include SurroundingSpace
|
12
|
+
MSG = 'Space inside %s.'
|
13
|
+
|
14
|
+
def investigate(processed_source)
|
15
|
+
return unless processed_source.ast
|
16
|
+
tokens = processed_source.tokens
|
17
|
+
|
18
|
+
on_node(:hash, processed_source.ast) do |hash|
|
19
|
+
b_ix = index_of_first_token(hash)
|
20
|
+
if tokens[b_ix].type == :tLBRACE # Hash literal with braces?
|
21
|
+
e_ix = index_of_last_token(hash)
|
22
|
+
check(tokens[b_ix], tokens[b_ix + 1])
|
23
|
+
check(tokens[e_ix - 1], tokens[e_ix]) unless b_ix == e_ix - 1
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
def check(t1, t2)
|
31
|
+
# No offence if line break inside.
|
32
|
+
return if t1.pos.line < t2.pos.line
|
33
|
+
|
34
|
+
is_empty_braces = t1.text == '{' && t2.text == '}'
|
35
|
+
expect_space = if is_empty_braces
|
36
|
+
cop_config['EnforcedStyleForEmptyBraces'] == 'space'
|
37
|
+
else
|
38
|
+
cop_config['EnforcedStyle'] == 'space'
|
39
|
+
end
|
40
|
+
if offence?(t1, t2, expect_space)
|
41
|
+
brace = (t1.text == '{' ? t1 : t2).pos
|
42
|
+
range = expect_space ? brace : space_range(brace)
|
43
|
+
convention(range, range,
|
44
|
+
message(brace, is_empty_braces, expect_space))
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def offence?(t1, t2, expect_space)
|
49
|
+
has_space = space_between?(t1, t2)
|
50
|
+
expect_space ? !has_space : has_space
|
51
|
+
end
|
52
|
+
|
53
|
+
def message(brace, is_empty_braces, expect_space)
|
54
|
+
inside_what = if is_empty_braces
|
55
|
+
'empty hash literal braces'
|
56
|
+
else
|
57
|
+
brace.source
|
58
|
+
end
|
59
|
+
problem = expect_space ? 'missing' : 'detected'
|
60
|
+
sprintf(MSG, "#{inside_what} #{problem}")
|
61
|
+
end
|
62
|
+
|
63
|
+
def autocorrect(range)
|
64
|
+
@corrections << lambda do |corrector|
|
65
|
+
case range.source
|
66
|
+
when /\s/ then corrector.remove(range)
|
67
|
+
when '{' then corrector.insert_after(range, ' ')
|
68
|
+
else corrector.insert_before(range, ' ')
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def space_range(token_range)
|
74
|
+
if token_range.source == '{'
|
75
|
+
range_of_space_to_the_right(token_range)
|
76
|
+
else
|
77
|
+
range_of_space_to_the_left(token_range)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def range_of_space_to_the_right(range)
|
82
|
+
src = range.source_buffer.source
|
83
|
+
end_pos = range.end_pos
|
84
|
+
end_pos += 1 while src[end_pos] =~ /[ \t]/
|
85
|
+
Parser::Source::Range.new(range.source_buffer,
|
86
|
+
range.begin_pos + 1, end_pos)
|
87
|
+
end
|
88
|
+
|
89
|
+
def range_of_space_to_the_left(range)
|
90
|
+
src = range.source_buffer.source
|
91
|
+
begin_pos = range.begin_pos
|
92
|
+
begin_pos -= 1 while src[begin_pos - 1] =~ /[ \t]/
|
93
|
+
Parser::Source::Range.new(range.source_buffer, begin_pos,
|
94
|
+
range.end_pos - 1)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
# rubocop:disable SymbolName
|
4
|
+
|
5
|
+
module Rubocop
|
6
|
+
module Cop
|
7
|
+
module Style
|
8
|
+
# Checks for spaces inside ordinary round parentheses.
|
9
|
+
class SpaceInsideParens < Cop
|
10
|
+
include SpaceInside
|
11
|
+
|
12
|
+
def specifics
|
13
|
+
[:tLPAREN2, :tRPAREN, 'parentheses']
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -5,33 +5,43 @@ module Rubocop
|
|
5
5
|
module Style
|
6
6
|
# This cop looks for uses of Perl-style global variables.
|
7
7
|
class SpecialGlobalVars < Cop
|
8
|
-
|
8
|
+
MSG_BOTH = 'Prefer %s from the English library, or %s over %s.'
|
9
|
+
MSG_ENGLISH = 'Prefer %s from the English library over %s.'
|
10
|
+
MSG_REGULAR = 'Prefer %s over %s.'
|
9
11
|
|
10
12
|
PREFERRED_VARS = {
|
11
|
-
'$:' => '$LOAD_PATH',
|
12
|
-
'$"' => '$LOADED_FEATURES',
|
13
|
-
'$0' => '$PROGRAM_NAME',
|
14
|
-
'$!' => '$ERROR_INFO
|
15
|
-
'$@' => '$ERROR_POSITION
|
16
|
-
'$;' => '$
|
17
|
-
'$,' => '$
|
18
|
-
'$/' => '$
|
19
|
-
'$\\' => '$
|
20
|
-
'$.' => '$
|
21
|
-
'$_' => '$LAST_READ_LINE
|
22
|
-
'$>' => '$DEFAULT_OUTPUT
|
23
|
-
'$<' => '$DEFAULT_INPUT
|
24
|
-
'$$' => '$
|
25
|
-
'$?' => '$CHILD_STATUS
|
26
|
-
'$~' => '$LAST_MATCH_INFO
|
27
|
-
'$=' => '$IGNORECASE
|
28
|
-
'$*' => '$ARGV
|
29
|
-
'$&' => '$MATCH
|
30
|
-
'$`' => '$PREMATCH
|
31
|
-
'$\'' => '$POSTMATCH
|
32
|
-
'$+' => '$LAST_PAREN_MATCH
|
13
|
+
'$:' => ['$LOAD_PATH'],
|
14
|
+
'$"' => ['$LOADED_FEATURES'],
|
15
|
+
'$0' => ['$PROGRAM_NAME'],
|
16
|
+
'$!' => ['$ERROR_INFO'],
|
17
|
+
'$@' => ['$ERROR_POSITION'],
|
18
|
+
'$;' => ['$FIELD_SEPARATOR', '$FS'],
|
19
|
+
'$,' => ['$OUTPUT_FIELD_SEPARATOR', '$OFS'],
|
20
|
+
'$/' => ['$INPUT_RECORD_SEPARATOR', '$RS'],
|
21
|
+
'$\\' => ['$OUTPUT_RECORD_SEPARATOR', '$ORS'],
|
22
|
+
'$.' => ['$INPUT_LINE_NUMBER', '$NR'],
|
23
|
+
'$_' => ['$LAST_READ_LINE'],
|
24
|
+
'$>' => ['$DEFAULT_OUTPUT'],
|
25
|
+
'$<' => ['$DEFAULT_INPUT'],
|
26
|
+
'$$' => ['$PROCESS_ID', '$PID'],
|
27
|
+
'$?' => ['$CHILD_STATUS'],
|
28
|
+
'$~' => ['$LAST_MATCH_INFO'],
|
29
|
+
'$=' => ['$IGNORECASE'],
|
30
|
+
'$*' => ['$ARGV', 'ARGV'],
|
31
|
+
'$&' => ['$MATCH'],
|
32
|
+
'$`' => ['$PREMATCH'],
|
33
|
+
'$\'' => ['$POSTMATCH'],
|
34
|
+
'$+' => ['$LAST_PAREN_MATCH']
|
33
35
|
}.symbolize_keys
|
34
36
|
|
37
|
+
# Anything *not* in this set is provided by the English library.
|
38
|
+
NON_ENGLISH_VARS = Set.new([
|
39
|
+
'$LOAD_PATH',
|
40
|
+
'$LOADED_FEATURES',
|
41
|
+
'$PROGRAM_NAME',
|
42
|
+
'ARGV'
|
43
|
+
])
|
44
|
+
|
35
45
|
def on_gvar(node)
|
36
46
|
global_var, = *node
|
37
47
|
|
@@ -40,7 +50,24 @@ module Rubocop
|
|
40
50
|
|
41
51
|
def message(node)
|
42
52
|
global_var, = *node
|
43
|
-
|
53
|
+
|
54
|
+
regular, english = PREFERRED_VARS[global_var].partition do |var|
|
55
|
+
NON_ENGLISH_VARS.include? var
|
56
|
+
end
|
57
|
+
|
58
|
+
# For now, we assume that lists are 2 items or less. Easy grammar!
|
59
|
+
regular_msg = regular.join(' or ')
|
60
|
+
english_msg = english.join(' or ')
|
61
|
+
|
62
|
+
if regular.length > 0 && english.length > 0
|
63
|
+
MSG_BOTH.format(english_msg, regular_msg, global_var)
|
64
|
+
elsif regular.length > 0
|
65
|
+
MSG_REGULAR.format(regular_msg, global_var)
|
66
|
+
elsif english.length > 0
|
67
|
+
MSG_ENGLISH.format(english_msg, global_var)
|
68
|
+
else
|
69
|
+
fail 'Bug in SpecialGlobalVars - global var w/o preferred vars!'
|
70
|
+
end
|
44
71
|
end
|
45
72
|
|
46
73
|
def autocorrect(node)
|
@@ -48,7 +75,7 @@ module Rubocop
|
|
48
75
|
global_var, = *node
|
49
76
|
|
50
77
|
corrector.replace(node.loc.expression,
|
51
|
-
PREFERRED_VARS[global_var])
|
78
|
+
PREFERRED_VARS[global_var].first)
|
52
79
|
end
|
53
80
|
end
|
54
81
|
end
|
@@ -21,7 +21,7 @@ module Rubocop
|
|
21
21
|
|
22
22
|
def offence?(node)
|
23
23
|
src = node.loc.expression.source
|
24
|
-
return false if src =~
|
24
|
+
return false if src =~ /^(%q|\?)/i
|
25
25
|
src !~ if single_quotes_preferred?
|
26
26
|
# regex matches IF there is a ' or there is a \\ in the
|
27
27
|
# string that is not preceeded/followed by another \\
|
@@ -15,7 +15,7 @@ module Rubocop
|
|
15
15
|
char_preceding_2nd_token =
|
16
16
|
@processed_source[t2.pos.line - 1][t2.pos.column - 2]
|
17
17
|
end
|
18
|
-
t2.pos.line > t1.pos.line || char_preceding_2nd_token
|
18
|
+
t2.pos.line > t1.pos.line || char_preceding_2nd_token =~ /[ \t]/
|
19
19
|
end
|
20
20
|
|
21
21
|
def index_of_first_token(node)
|
@@ -41,349 +41,6 @@ module Rubocop
|
|
41
41
|
end
|
42
42
|
end
|
43
43
|
end
|
44
|
-
|
45
|
-
# Checks that operators have space around them, except for **
|
46
|
-
# which should not have surrounding space.
|
47
|
-
class SpaceAroundOperators < Cop
|
48
|
-
include SurroundingSpace
|
49
|
-
MSG_MISSING = "Surrounding space missing for operator '%s'."
|
50
|
-
MSG_DETECTED = 'Space around operator ** detected.'
|
51
|
-
|
52
|
-
BINARY_OPERATORS =
|
53
|
-
[:tEQL, :tAMPER2, :tPIPE, :tCARET, :tPLUS, :tMINUS, :tSTAR2,
|
54
|
-
:tDIVIDE, :tPERCENT, :tEH, :tCOLON, :tANDOP, :tOROP, :tMATCH,
|
55
|
-
:tNMATCH, :tEQ, :tNEQ, :tGT, :tRSHFT, :tGEQ, :tLT,
|
56
|
-
:tLSHFT, :tLEQ, :tASSOC, :tEQQ, :tCMP, :tOP_ASGN]
|
57
|
-
|
58
|
-
def investigate(processed_source)
|
59
|
-
return unless processed_source.ast
|
60
|
-
@processed_source = processed_source
|
61
|
-
tokens = processed_source.tokens
|
62
|
-
tokens.each_cons(3) do |token_before, token, token_after|
|
63
|
-
next if token_before.type == :kDEF # TODO: remove?
|
64
|
-
next if token_before.type == :tDOT # Called as method.
|
65
|
-
next if positions_not_to_check.include?(token.pos)
|
66
|
-
|
67
|
-
case token.type
|
68
|
-
when :tPOW
|
69
|
-
if has_space?(token_before, token, token_after)
|
70
|
-
convention(nil, token.pos, MSG_DETECTED)
|
71
|
-
end
|
72
|
-
when *BINARY_OPERATORS
|
73
|
-
check_missing_space(token_before, token, token_after)
|
74
|
-
end
|
75
|
-
end
|
76
|
-
end
|
77
|
-
|
78
|
-
# Returns an array of positions marking the tokens that this cop
|
79
|
-
# should not check, either because the token is not an operator
|
80
|
-
# or because another cop does the check.
|
81
|
-
def positions_not_to_check
|
82
|
-
@positions_not_to_check ||= begin
|
83
|
-
positions = []
|
84
|
-
positions.concat(do_not_check_block_arg_pipes)
|
85
|
-
positions.concat(do_not_check_param_default)
|
86
|
-
positions.concat(do_not_check_class_lshift_self)
|
87
|
-
positions.concat(do_not_check_def_things)
|
88
|
-
positions.concat(do_not_check_singleton_operator_defs)
|
89
|
-
positions
|
90
|
-
end
|
91
|
-
end
|
92
|
-
|
93
|
-
def do_not_check_block_arg_pipes
|
94
|
-
# each { |a| }
|
95
|
-
# ^ ^
|
96
|
-
positions = []
|
97
|
-
on_node(:block, @processed_source.ast) do |b|
|
98
|
-
on_node(:args, b) do |a|
|
99
|
-
positions << a.loc.begin << a.loc.end if a.loc.begin
|
100
|
-
end
|
101
|
-
end
|
102
|
-
positions
|
103
|
-
end
|
104
|
-
|
105
|
-
def do_not_check_param_default
|
106
|
-
# func(a, b=nil)
|
107
|
-
# ^
|
108
|
-
positions = []
|
109
|
-
tokens = @processed_source.tokens
|
110
|
-
on_node(:optarg, @processed_source.ast) do |optarg|
|
111
|
-
_arg, equals, _value = tokens[index_of_first_token(optarg),
|
112
|
-
3]
|
113
|
-
positions << equals.pos
|
114
|
-
end
|
115
|
-
positions
|
116
|
-
end
|
117
|
-
|
118
|
-
def do_not_check_class_lshift_self
|
119
|
-
# class <<self
|
120
|
-
# ^
|
121
|
-
positions = []
|
122
|
-
tokens = @processed_source.tokens
|
123
|
-
on_node(:sclass, @processed_source.ast) do |sclass|
|
124
|
-
ix = index_of_first_token(sclass)
|
125
|
-
if tokens[ix, 2].map(&:type) == [:kCLASS, :tLSHFT]
|
126
|
-
positions << tokens[ix + 1].pos
|
127
|
-
end
|
128
|
-
end
|
129
|
-
positions
|
130
|
-
end
|
131
|
-
|
132
|
-
def do_not_check_def_things
|
133
|
-
# def +(other)
|
134
|
-
# ^
|
135
|
-
positions = []
|
136
|
-
tokens = @processed_source.tokens
|
137
|
-
on_node(:def, @processed_source.ast) do |def_node|
|
138
|
-
# def each &block
|
139
|
-
# ^
|
140
|
-
# def each *args
|
141
|
-
# ^
|
142
|
-
on_node([:blockarg, :restarg], def_node) do |arg_node|
|
143
|
-
positions << tokens[index_of_first_token(arg_node)].pos
|
144
|
-
end
|
145
|
-
positions << tokens[index_of_first_token(def_node) + 1].pos
|
146
|
-
end
|
147
|
-
positions
|
148
|
-
end
|
149
|
-
|
150
|
-
def do_not_check_singleton_operator_defs
|
151
|
-
# def self.===(other)
|
152
|
-
# ^
|
153
|
-
positions = []
|
154
|
-
tokens = @processed_source.tokens
|
155
|
-
on_node(:defs, @processed_source.ast) do |defs_node|
|
156
|
-
_receiver, name, _args = *defs_node
|
157
|
-
ix = index_of_first_token(defs_node)
|
158
|
-
name_token = tokens[ix..-1].find { |t| t.text == name.to_s }
|
159
|
-
positions << name_token.pos
|
160
|
-
end
|
161
|
-
positions
|
162
|
-
end
|
163
|
-
|
164
|
-
def check_missing_space(token_before, token, token_after)
|
165
|
-
unless has_space?(token_before, token, token_after)
|
166
|
-
text = token.text.to_s + (token.type == :tOP_ASGN ? '=' : '')
|
167
|
-
convention(nil, token.pos, MSG_MISSING.format(text))
|
168
|
-
end
|
169
|
-
end
|
170
|
-
|
171
|
-
def has_space?(token_before, token, token_after)
|
172
|
-
space_between?(token_before, token) && space_between?(token,
|
173
|
-
token_after)
|
174
|
-
end
|
175
|
-
end
|
176
|
-
|
177
|
-
# Checks that block braces have or don't have surrounding space depending
|
178
|
-
# on configuration. For blocks taking parameters, it checks that the left
|
179
|
-
# brace has or doesn't have trailing space depending on configuration.
|
180
|
-
class SpaceAroundBlockBraces < Cop
|
181
|
-
include SurroundingSpace
|
182
|
-
|
183
|
-
def investigate(processed_source)
|
184
|
-
return unless processed_source.ast
|
185
|
-
@processed_source = processed_source
|
186
|
-
|
187
|
-
processed_source.tokens.each_cons(2) do |t1, t2|
|
188
|
-
next if ([t1.pos, t2.pos] - positions_not_to_check).size < 2
|
189
|
-
|
190
|
-
type1, type2 = t1.type, t2.type
|
191
|
-
if [:tLCURLY, :tRCURLY].include?(type2)
|
192
|
-
check(t1, t2)
|
193
|
-
elsif type1 == :tLCURLY
|
194
|
-
if type2 == :tPIPE
|
195
|
-
check_pipe(t1, t2)
|
196
|
-
else
|
197
|
-
check(t1, t2)
|
198
|
-
end
|
199
|
-
end
|
200
|
-
end
|
201
|
-
end
|
202
|
-
|
203
|
-
def positions_not_to_check
|
204
|
-
@positions_not_to_check ||= begin
|
205
|
-
positions = []
|
206
|
-
ast = @processed_source.ast
|
207
|
-
tokens = @processed_source.tokens
|
208
|
-
|
209
|
-
on_node(:hash, ast) do |hash|
|
210
|
-
b_ix = index_of_first_token(hash)
|
211
|
-
e_ix = index_of_last_token(hash)
|
212
|
-
positions << tokens[b_ix].pos << tokens[e_ix].pos
|
213
|
-
end
|
214
|
-
|
215
|
-
# TODO: Check braces inside string/symbol/regexp/xstr
|
216
|
-
# interpolation.
|
217
|
-
on_node([:dstr, :dsym, :regexp, :xstr], ast) do |s|
|
218
|
-
b_ix = index_of_first_token(s)
|
219
|
-
e_ix = index_of_last_token(s)
|
220
|
-
tokens[b_ix..e_ix].each do |t|
|
221
|
-
positions << t.pos if t.type == :tRCURLY
|
222
|
-
end
|
223
|
-
end
|
224
|
-
|
225
|
-
positions
|
226
|
-
end
|
227
|
-
end
|
228
|
-
|
229
|
-
def check(t1, t2)
|
230
|
-
if cop_config['EnforcedStyle'] == 'space_inside_braces'
|
231
|
-
check_space_inside_braces(t1, t2)
|
232
|
-
else
|
233
|
-
check_no_space_inside_braces(t1, t2)
|
234
|
-
end
|
235
|
-
check_space_outside_left_brace(t1, t2)
|
236
|
-
end
|
237
|
-
|
238
|
-
def check_space_inside_braces(t1, t2)
|
239
|
-
unless space_between?(t1, t2)
|
240
|
-
if t1.text == '{'
|
241
|
-
convention(nil, t1.pos, 'Space missing inside {.')
|
242
|
-
elsif t2.text == '}'
|
243
|
-
convention(nil, t2.pos, 'Space missing inside }.')
|
244
|
-
end
|
245
|
-
end
|
246
|
-
end
|
247
|
-
|
248
|
-
def check_no_space_inside_braces(t1, t2)
|
249
|
-
if t1.text == '{' || t2.text == '}'
|
250
|
-
if space_between?(t1, t2)
|
251
|
-
if t1.text == '{'
|
252
|
-
convention(nil, space_range(t1), 'Space inside { detected.')
|
253
|
-
elsif t2.text == '}'
|
254
|
-
convention(nil, space_range(t2), 'Space inside } detected.')
|
255
|
-
end
|
256
|
-
end
|
257
|
-
end
|
258
|
-
end
|
259
|
-
|
260
|
-
def check_space_outside_left_brace(t1, t2)
|
261
|
-
if t2.text == '{' && !space_between?(t1, t2)
|
262
|
-
convention(nil, t2.pos, 'Space missing to the left of {.')
|
263
|
-
end
|
264
|
-
end
|
265
|
-
|
266
|
-
def check_pipe(t1, t2)
|
267
|
-
if cop_config['SpaceBeforeBlockParameters']
|
268
|
-
unless space_between?(t1, t2)
|
269
|
-
convention(nil, t1.pos, 'Space between { and | missing.')
|
270
|
-
end
|
271
|
-
elsif space_between?(t1, t2)
|
272
|
-
convention(nil, space_range(t1), 'Space between { and | detected.')
|
273
|
-
end
|
274
|
-
end
|
275
|
-
|
276
|
-
def space_range(token)
|
277
|
-
src = @processed_source.buffer.source
|
278
|
-
if token.text == '{'
|
279
|
-
b = token.pos.begin_pos + 1
|
280
|
-
e = b + 1
|
281
|
-
e += 1 while src[e] =~ /\s/
|
282
|
-
else
|
283
|
-
e = token.pos.begin_pos
|
284
|
-
b = e - 1
|
285
|
-
b -= 1 while src[b - 1] =~ /\s/
|
286
|
-
end
|
287
|
-
Parser::Source::Range.new(@processed_source.buffer, b, e)
|
288
|
-
end
|
289
|
-
end
|
290
|
-
|
291
|
-
# Common functionality for checking for spaces inside various
|
292
|
-
# kinds of parentheses.
|
293
|
-
module SpaceInside
|
294
|
-
include SurroundingSpace
|
295
|
-
MSG = 'Space inside %s detected.'
|
296
|
-
|
297
|
-
def investigate(processed_source)
|
298
|
-
@processed_source = processed_source
|
299
|
-
left, right, kind = specifics
|
300
|
-
processed_source.tokens.each_cons(2) do |t1, t2|
|
301
|
-
if t1.type == left || t2.type == right
|
302
|
-
if t2.pos.line == t1.pos.line && space_between?(t1, t2)
|
303
|
-
range = Parser::Source::Range.new(processed_source.buffer,
|
304
|
-
t1.pos.end_pos,
|
305
|
-
t2.pos.begin_pos)
|
306
|
-
convention(nil, range, format(MSG, kind))
|
307
|
-
end
|
308
|
-
end
|
309
|
-
end
|
310
|
-
end
|
311
|
-
end
|
312
|
-
|
313
|
-
# Checks for spaces inside ordinary round parentheses.
|
314
|
-
class SpaceInsideParens < Cop
|
315
|
-
include SpaceInside
|
316
|
-
|
317
|
-
def specifics
|
318
|
-
[:tLPAREN2, :tRPAREN, 'parentheses']
|
319
|
-
end
|
320
|
-
end
|
321
|
-
|
322
|
-
# Checks for spaces inside square brackets.
|
323
|
-
class SpaceInsideBrackets < Cop
|
324
|
-
include SpaceInside
|
325
|
-
|
326
|
-
def specifics
|
327
|
-
[:tLBRACK, :tRBRACK, 'square brackets']
|
328
|
-
end
|
329
|
-
end
|
330
|
-
|
331
|
-
# Checks that braces used for hash literals have or don't have
|
332
|
-
# surrounding space depending on configuration.
|
333
|
-
class SpaceInsideHashLiteralBraces < Cop
|
334
|
-
include SurroundingSpace
|
335
|
-
MSG = 'Space inside hash literal braces %s.'
|
336
|
-
|
337
|
-
def investigate(processed_source)
|
338
|
-
return unless processed_source.ast
|
339
|
-
@processed_source = processed_source
|
340
|
-
tokens = processed_source.tokens
|
341
|
-
|
342
|
-
on_node(:hash, processed_source.ast) do |hash|
|
343
|
-
b_ix = index_of_first_token(hash)
|
344
|
-
e_ix = index_of_last_token(hash)
|
345
|
-
if tokens[b_ix].type == :tLBRACE # Hash literal with braces?
|
346
|
-
check(tokens[b_ix], tokens[b_ix + 1])
|
347
|
-
check(tokens[e_ix - 1], tokens[e_ix])
|
348
|
-
end
|
349
|
-
end
|
350
|
-
end
|
351
|
-
|
352
|
-
def check(t1, t2)
|
353
|
-
types = [t1, t2].map(&:type)
|
354
|
-
braces = [:tLBRACE, :tRCURLY]
|
355
|
-
return if types == braces || (braces - types).size == 2
|
356
|
-
# No offence if line break inside.
|
357
|
-
return if t1.pos.line < t2.pos.line
|
358
|
-
has_space = space_between?(t1, t2)
|
359
|
-
is_offence, word = if cop_config['EnforcedStyleIsWithSpaces']
|
360
|
-
[!has_space, 'missing']
|
361
|
-
else
|
362
|
-
[has_space, 'detected']
|
363
|
-
end
|
364
|
-
brace_token = t1.text == '{' ? t1 : t2
|
365
|
-
convention(nil, brace_token.pos, sprintf(MSG, word)) if is_offence
|
366
|
-
end
|
367
|
-
end
|
368
|
-
|
369
|
-
# Checks that the equals signs in parameter default assignments
|
370
|
-
# have surrounding space.
|
371
|
-
class SpaceAroundEqualsInParameterDefault < Cop
|
372
|
-
include SurroundingSpace
|
373
|
-
MSG = 'Surrounding space missing in default value assignment.'
|
374
|
-
|
375
|
-
def investigate(processed_source)
|
376
|
-
return unless processed_source.ast
|
377
|
-
@processed_source = processed_source
|
378
|
-
on_node(:optarg, processed_source.ast) do |optarg|
|
379
|
-
index = index_of_first_token(optarg)
|
380
|
-
arg, equals, value = processed_source.tokens[index, 3]
|
381
|
-
unless space_between?(arg, equals) && space_between?(equals, value)
|
382
|
-
convention(nil, equals.pos)
|
383
|
-
end
|
384
|
-
end
|
385
|
-
end
|
386
|
-
end
|
387
44
|
end
|
388
45
|
end
|
389
46
|
end
|