rubocop 0.32.1 → 0.33.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/CHANGELOG.md +58 -0
- data/README.md +22 -4
- data/config/default.yml +29 -10
- data/config/disabled.yml +8 -4
- data/config/enabled.yml +40 -1
- data/lib/rubocop.rb +8 -0
- data/lib/rubocop/cli.rb +1 -0
- data/lib/rubocop/config_loader.rb +23 -2
- data/lib/rubocop/cop/lint/block_alignment.rb +1 -1
- data/lib/rubocop/cop/lint/circular_argument_reference.rb +38 -0
- data/lib/rubocop/cop/lint/def_end_alignment.rb +8 -4
- data/lib/rubocop/cop/lint/deprecated_class_methods.rb +38 -21
- data/lib/rubocop/cop/lint/duplicate_methods.rb +1 -1
- data/lib/rubocop/cop/lint/format_parameter_mismatch.rb +95 -0
- data/lib/rubocop/cop/mixin/end_keyword_alignment.rb +1 -1
- data/lib/rubocop/cop/mixin/on_method_def.rb +4 -5
- data/lib/rubocop/cop/mixin/string_literals_help.rb +1 -1
- data/lib/rubocop/cop/performance/count.rb +2 -0
- data/lib/rubocop/cop/performance/detect.rb +11 -2
- data/lib/rubocop/cop/performance/flat_map.rb +3 -3
- data/lib/rubocop/cop/performance/string_replacement.rb +161 -0
- data/lib/rubocop/cop/rails/date.rb +8 -8
- data/lib/rubocop/cop/rails/time_zone.rb +22 -13
- data/lib/rubocop/cop/style/block_delimiters.rb +6 -1
- data/lib/rubocop/cop/style/documentation.rb +1 -1
- data/lib/rubocop/cop/style/extra_spacing.rb +84 -5
- data/lib/rubocop/cop/style/first_parameter_indentation.rb +2 -0
- data/lib/rubocop/cop/style/indentation_width.rb +28 -4
- data/lib/rubocop/cop/style/initial_indentation.rb +32 -0
- data/lib/rubocop/cop/style/method_call_parentheses.rb +20 -1
- data/lib/rubocop/cop/style/one_line_conditional.rb +8 -4
- data/lib/rubocop/cop/style/option_hash.rb +56 -0
- data/lib/rubocop/cop/style/optional_arguments.rb +49 -0
- data/lib/rubocop/cop/style/parallel_assignment.rb +3 -0
- data/lib/rubocop/cop/style/percent_literal_delimiters.rb +3 -66
- data/lib/rubocop/cop/style/redundant_return.rb +20 -3
- data/lib/rubocop/cop/style/rescue_ensure_alignment.rb +77 -0
- data/lib/rubocop/cop/style/rescue_modifier.rb +4 -28
- data/lib/rubocop/cop/style/send.rb +18 -0
- data/lib/rubocop/cop/style/space_inside_string_interpolation.rb +32 -13
- data/lib/rubocop/cop/style/symbol_literal.rb +1 -1
- data/lib/rubocop/cop/style/trivial_accessors.rb +10 -1
- data/lib/rubocop/cop/style/while_until_do.rb +1 -1
- data/lib/rubocop/cop/style/word_array.rb +13 -1
- data/lib/rubocop/formatter/disabled_config_formatter.rb +54 -5
- data/lib/rubocop/options.rb +81 -55
- data/lib/rubocop/version.rb +1 -1
- data/relnotes/v0.33.0.md +157 -0
- metadata +11 -2
@@ -0,0 +1,56 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Style
|
6
|
+
# This cop checks for options hashes and discourages them if the
|
7
|
+
# current Ruby version supports keyword arguments.
|
8
|
+
#
|
9
|
+
# @example
|
10
|
+
# Instead of:
|
11
|
+
#
|
12
|
+
# def fry(options = {})
|
13
|
+
# temperature = options.fetch(:temperature, 300)
|
14
|
+
# ...
|
15
|
+
# end
|
16
|
+
#
|
17
|
+
# Prefer:
|
18
|
+
#
|
19
|
+
# def fry(temperature: 300)
|
20
|
+
# ...
|
21
|
+
# end
|
22
|
+
class OptionHash < Cop
|
23
|
+
MSG = 'Prefer keyword arguments to options hashes.'
|
24
|
+
|
25
|
+
def on_args(node)
|
26
|
+
return unless supports_keyword_arguments?
|
27
|
+
|
28
|
+
*_but_last, last_arg = *node
|
29
|
+
|
30
|
+
# asserting that there was an argument at all
|
31
|
+
return unless last_arg
|
32
|
+
|
33
|
+
# asserting last argument is an optional argument
|
34
|
+
return unless last_arg.optarg_type?
|
35
|
+
|
36
|
+
_, default_value = *last_arg
|
37
|
+
|
38
|
+
# asserting default value is a hash
|
39
|
+
return unless default_value.hash_type?
|
40
|
+
|
41
|
+
# asserting default value is empty hash
|
42
|
+
*key_value_pairs = *default_value
|
43
|
+
return unless key_value_pairs.empty?
|
44
|
+
|
45
|
+
add_offense(last_arg, :expression, MSG)
|
46
|
+
end
|
47
|
+
|
48
|
+
private
|
49
|
+
|
50
|
+
def supports_keyword_arguments?
|
51
|
+
RUBY_VERSION >= '2.0.0'
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Style
|
6
|
+
# This cop checks for optional arguments to methods
|
7
|
+
# that do not come at the end of the argument list
|
8
|
+
#
|
9
|
+
# @example
|
10
|
+
# # bad
|
11
|
+
# def foo(a = 1, b, c)
|
12
|
+
# end
|
13
|
+
#
|
14
|
+
# # good
|
15
|
+
# def baz(a, b, c = 1)
|
16
|
+
# end
|
17
|
+
#
|
18
|
+
# def foobar(a = 1, b = 2, c = 3)
|
19
|
+
# end
|
20
|
+
class OptionalArguments < Cop
|
21
|
+
MSG =
|
22
|
+
'Optional arguments should appear at the end of the argument list.'
|
23
|
+
|
24
|
+
def on_def(node)
|
25
|
+
_method, arguments, = *node
|
26
|
+
arguments = *arguments
|
27
|
+
optarg_positions = []
|
28
|
+
arg_positions = []
|
29
|
+
|
30
|
+
arguments.each_with_index do |argument, index|
|
31
|
+
optarg_positions << index if argument.optarg_type?
|
32
|
+
arg_positions << index if argument.arg_type?
|
33
|
+
end
|
34
|
+
|
35
|
+
return if optarg_positions.empty? || arg_positions.empty?
|
36
|
+
|
37
|
+
optarg_positions.each do |optarg_position|
|
38
|
+
# there can only be one group of optional arguments
|
39
|
+
break if optarg_position > arg_positions.max
|
40
|
+
argument = arguments[optarg_position]
|
41
|
+
arg, = *argument
|
42
|
+
|
43
|
+
add_offense(argument, :expression, format(MSG, arg))
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -37,6 +37,9 @@ module RuboCop
|
|
37
37
|
# account for edge cases using one variable with a comma
|
38
38
|
return if left_elements.size == 1
|
39
39
|
|
40
|
+
# account for edge case of Constant::CONSTANT
|
41
|
+
return unless right.array_type?
|
42
|
+
|
40
43
|
# allow mass assignment as the return of a method call
|
41
44
|
return if right.block_type? || right.send_type?
|
42
45
|
|
@@ -33,7 +33,7 @@ module RuboCop
|
|
33
33
|
delimiters = preferred_delimiters(type)
|
34
34
|
|
35
35
|
"`#{type}`-literals should be delimited by " \
|
36
|
-
"`#{delimiters[0]}` and `#{delimiters[1]}
|
36
|
+
"`#{delimiters[0]}` and `#{delimiters[1]}`."
|
37
37
|
end
|
38
38
|
|
39
39
|
private
|
@@ -43,20 +43,9 @@ module RuboCop
|
|
43
43
|
|
44
44
|
opening_delimiter, closing_delimiter = preferred_delimiters(type)
|
45
45
|
|
46
|
-
first_child, *_middle, last_child = *node
|
47
|
-
opening_newline = new_line(node.loc.begin, first_child)
|
48
|
-
expression_indentation = leading_whitespace(first_child, :expression)
|
49
|
-
closing_newline = new_line(node.loc.end, last_child)
|
50
|
-
closing_indentation = leading_whitespace(node, :end)
|
51
|
-
expression, reg_opt = *contents(node)
|
52
|
-
|
53
|
-
corrected_source =
|
54
|
-
type + opening_delimiter + opening_newline +
|
55
|
-
expression_indentation + expression + closing_newline +
|
56
|
-
closing_indentation + closing_delimiter + reg_opt
|
57
|
-
|
58
46
|
lambda do |corrector|
|
59
|
-
corrector.replace(node.loc.
|
47
|
+
corrector.replace(node.loc.begin, "#{type}#{opening_delimiter}")
|
48
|
+
corrector.replace(node.loc.end, closing_delimiter)
|
60
49
|
end
|
61
50
|
end
|
62
51
|
|
@@ -72,49 +61,6 @@ module RuboCop
|
|
72
61
|
cop_config['PreferredDelimiters'][type].split(//)
|
73
62
|
end
|
74
63
|
|
75
|
-
def leading_whitespace(object, part)
|
76
|
-
case object
|
77
|
-
when String
|
78
|
-
''
|
79
|
-
when NilClass
|
80
|
-
''
|
81
|
-
when Parser::AST::Node
|
82
|
-
part_range = object.loc.send(part)
|
83
|
-
left_of_part = part_range.source_line[0...part_range.column]
|
84
|
-
/^(\s*)$/.match(left_of_part) ? left_of_part : ''
|
85
|
-
else
|
86
|
-
fail "Unsupported object #{object}"
|
87
|
-
end
|
88
|
-
end
|
89
|
-
|
90
|
-
def contents(node)
|
91
|
-
first_child, *middle, last_child = *node
|
92
|
-
last_child ||= first_child
|
93
|
-
if node.type == :regexp
|
94
|
-
*_, next_to_last_child = *middle
|
95
|
-
next_to_last_child ||= first_child
|
96
|
-
expression = source(node, first_child, next_to_last_child)
|
97
|
-
reg_opt = last_child.loc.expression.source
|
98
|
-
else
|
99
|
-
expression = if first_child.is_a?(Parser::AST::Node)
|
100
|
-
source(node, first_child, last_child)
|
101
|
-
else
|
102
|
-
first_child.to_s
|
103
|
-
end
|
104
|
-
reg_opt = ''
|
105
|
-
end
|
106
|
-
|
107
|
-
[expression, reg_opt]
|
108
|
-
end
|
109
|
-
|
110
|
-
def source(node, begin_node, end_node)
|
111
|
-
Parser::Source::Range.new(
|
112
|
-
node.loc.expression.source_buffer,
|
113
|
-
begin_node.loc.expression.begin_pos,
|
114
|
-
end_node.loc.expression.end_pos
|
115
|
-
).source
|
116
|
-
end
|
117
|
-
|
118
64
|
def uses_preferred_delimiter?(node, type)
|
119
65
|
preferred_delimiters(type)[0] == begin_source(node)[-1]
|
120
66
|
end
|
@@ -133,15 +79,6 @@ module RuboCop
|
|
133
79
|
node.loc.expression.source
|
134
80
|
end
|
135
81
|
end
|
136
|
-
|
137
|
-
def new_line(range, child_node)
|
138
|
-
same_line?(range, child_node) ? '' : "\n"
|
139
|
-
end
|
140
|
-
|
141
|
-
def same_line?(range, child_node)
|
142
|
-
!child_node.is_a?(Parser::AST::Node) ||
|
143
|
-
range.begin.line == child_node.loc.line
|
144
|
-
end
|
145
82
|
end
|
146
83
|
end
|
147
84
|
end
|
@@ -34,16 +34,33 @@ module RuboCop
|
|
34
34
|
next
|
35
35
|
end
|
36
36
|
|
37
|
+
return_value, = *node
|
37
38
|
if node.children.size > 1
|
38
|
-
|
39
|
-
|
40
|
-
corrector
|
39
|
+
add_brackets(corrector, node)
|
40
|
+
elsif return_value.hash_type?
|
41
|
+
add_braces(corrector, return_value) unless braces?(return_value)
|
41
42
|
end
|
42
43
|
return_kw = range_with_surrounding_space(node.loc.keyword, :right)
|
43
44
|
corrector.remove(return_kw)
|
44
45
|
end
|
45
46
|
end
|
46
47
|
|
48
|
+
def braces?(arg)
|
49
|
+
arg.loc.begin
|
50
|
+
end
|
51
|
+
|
52
|
+
def add_brackets(corrector, node)
|
53
|
+
kids = node.children.map { |child| child.loc.expression }
|
54
|
+
corrector.insert_before(kids.first, '[')
|
55
|
+
corrector.insert_after(kids.last, ']')
|
56
|
+
end
|
57
|
+
|
58
|
+
def add_braces(corrector, node)
|
59
|
+
kids = node.children.map { |child| child.loc.expression }
|
60
|
+
corrector.insert_before(kids.first, '{')
|
61
|
+
corrector.insert_after(kids.last, '}')
|
62
|
+
end
|
63
|
+
|
47
64
|
def arguments?(args)
|
48
65
|
return false if args.empty?
|
49
66
|
return true if args.size > 1
|
@@ -0,0 +1,77 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Style
|
6
|
+
# This cop checks whether the rescue and ensure keywords are aligned
|
7
|
+
# properly.
|
8
|
+
#
|
9
|
+
# @example
|
10
|
+
#
|
11
|
+
# # bad
|
12
|
+
# begin
|
13
|
+
# something
|
14
|
+
# rescue
|
15
|
+
# puts 'error'
|
16
|
+
# end
|
17
|
+
#
|
18
|
+
# # good
|
19
|
+
# begin
|
20
|
+
# something
|
21
|
+
# rescue
|
22
|
+
# puts 'error'
|
23
|
+
# end
|
24
|
+
class RescueEnsureAlignment < Cop
|
25
|
+
MSG = '`%s` at %d, %d is not aligned with `end` at %d, %d.'
|
26
|
+
|
27
|
+
def on_resbody(node)
|
28
|
+
check(node) unless modifier?(node)
|
29
|
+
end
|
30
|
+
|
31
|
+
def on_ensure(node)
|
32
|
+
check(node)
|
33
|
+
end
|
34
|
+
|
35
|
+
def investigate(processed_source)
|
36
|
+
@modifier_locations = processed_source.tokens
|
37
|
+
.select { |t| t.type == :kRESCUE_MOD }
|
38
|
+
.map(&:pos)
|
39
|
+
end
|
40
|
+
|
41
|
+
def autocorrect(node)
|
42
|
+
source_buffer = node.loc.keyword.source_buffer
|
43
|
+
begin_pos = node.loc.keyword.begin_pos
|
44
|
+
current_column = node.loc.keyword.column
|
45
|
+
whitespace = Parser::Source::Range.new(source_buffer,
|
46
|
+
begin_pos - current_column,
|
47
|
+
begin_pos)
|
48
|
+
return false unless whitespace.source.strip.empty?
|
49
|
+
|
50
|
+
new_column = ancestor_node(node).loc.end.column
|
51
|
+
->(corrector) { corrector.replace(whitespace, ' ' * new_column) }
|
52
|
+
end
|
53
|
+
|
54
|
+
private
|
55
|
+
|
56
|
+
def check(node)
|
57
|
+
end_loc = ancestor_node(node).loc.end
|
58
|
+
return if end_loc.column == node.loc.keyword.column
|
59
|
+
|
60
|
+
kw_loc = node.loc.keyword
|
61
|
+
|
62
|
+
add_offense(node, kw_loc,
|
63
|
+
format(MSG, kw_loc.source, kw_loc.line, kw_loc.column,
|
64
|
+
end_loc.line, end_loc.column))
|
65
|
+
end
|
66
|
+
|
67
|
+
def modifier?(node)
|
68
|
+
@modifier_locations.include? node.loc.keyword
|
69
|
+
end
|
70
|
+
|
71
|
+
def ancestor_node(node)
|
72
|
+
node.each_ancestor(:kwbegin, :def, :defs).first
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
@@ -5,36 +5,12 @@ module RuboCop
|
|
5
5
|
module Style
|
6
6
|
# This cop checks for uses of rescue in its modifier form.
|
7
7
|
class RescueModifier < Cop
|
8
|
-
include OnMethodDef
|
9
|
-
|
10
8
|
MSG = 'Avoid using `rescue` in its modifier form.'
|
11
9
|
|
12
|
-
def
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
end
|
17
|
-
|
18
|
-
def on_kwbegin(node)
|
19
|
-
body, *_ = *node
|
20
|
-
check(body)
|
21
|
-
end
|
22
|
-
|
23
|
-
def on_method_def(_node, _method_name, _args, body)
|
24
|
-
check(body)
|
25
|
-
end
|
26
|
-
|
27
|
-
def check(body)
|
28
|
-
return unless body
|
29
|
-
|
30
|
-
case body.type
|
31
|
-
when :rescue
|
32
|
-
ignore_node(body)
|
33
|
-
when :ensure
|
34
|
-
first_child = body.children.first
|
35
|
-
if first_child && first_child.type == :rescue
|
36
|
-
ignore_node(first_child)
|
37
|
-
end
|
10
|
+
def investigate(processed_source)
|
11
|
+
processed_source.tokens.each do |t|
|
12
|
+
next unless t.type == :kRESCUE_MOD
|
13
|
+
add_offense(nil, t.pos)
|
38
14
|
end
|
39
15
|
end
|
40
16
|
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Style
|
6
|
+
# This cop checks for the use of the send method.
|
7
|
+
class Send < Cop
|
8
|
+
MSG = 'Prefer `Object#__send__` or `Object#public_send` to `send`.'
|
9
|
+
|
10
|
+
def on_send(node)
|
11
|
+
_receiver, method_name, *args = *node
|
12
|
+
return unless method_name == :send && args.length > 0
|
13
|
+
add_offense(node, :selector)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -5,22 +5,32 @@ module RuboCop
|
|
5
5
|
module Style
|
6
6
|
# This cop checks for whitespace within string interpolations.
|
7
7
|
#
|
8
|
-
#
|
9
|
-
#
|
10
|
-
#
|
11
|
-
# Bad:
|
12
|
-
# var = "This is the #{ bad } example"
|
8
|
+
# @example
|
9
|
+
# # Good if EnforcedStyle is no_space, bad if space.
|
10
|
+
# var = "This is the #{no_space} example"
|
13
11
|
#
|
12
|
+
# # Good if EnforceStyle is space, bad if no_space.
|
13
|
+
# var = "This is the #{ space } example"
|
14
14
|
class SpaceInsideStringInterpolation < Cop
|
15
|
-
|
15
|
+
include ConfigurableEnforcedStyle
|
16
|
+
|
17
|
+
NO_SPACE_MSG = 'Space inside string interpolation detected.'
|
18
|
+
SPACE_MSG = 'Missing space around string interpolation detected.'
|
16
19
|
|
17
20
|
def on_dstr(node)
|
18
21
|
node.children.select { |n| n.type == :begin }.each do |begin_node|
|
19
22
|
final_node = begin_node.children.last
|
20
23
|
|
21
24
|
interp = final_node.loc.expression
|
22
|
-
|
23
|
-
|
25
|
+
interp_with_surrounding_space = range_with_surrounding_space(interp)
|
26
|
+
if style == :no_space
|
27
|
+
if interp_with_surrounding_space != interp
|
28
|
+
add_offense(final_node, :expression, NO_SPACE_MSG)
|
29
|
+
end
|
30
|
+
elsif style == :space
|
31
|
+
if interp_with_surrounding_space.source != " #{interp.source} "
|
32
|
+
add_offense(final_node, :expression, SPACE_MSG)
|
33
|
+
end
|
24
34
|
end
|
25
35
|
end
|
26
36
|
end
|
@@ -28,11 +38,20 @@ module RuboCop
|
|
28
38
|
private
|
29
39
|
|
30
40
|
def autocorrect(node)
|
31
|
-
|
32
|
-
corrector
|
33
|
-
|
34
|
-
|
35
|
-
|
41
|
+
if style == :no_space
|
42
|
+
lambda do |corrector|
|
43
|
+
corrector.replace(
|
44
|
+
range_with_surrounding_space(node.loc.expression),
|
45
|
+
node.loc.expression.source
|
46
|
+
)
|
47
|
+
end
|
48
|
+
elsif style == :space
|
49
|
+
lambda do |corrector|
|
50
|
+
corrector.replace(
|
51
|
+
range_with_surrounding_space(node.loc.expression),
|
52
|
+
" #{node.loc.expression.source} "
|
53
|
+
)
|
54
|
+
end
|
36
55
|
end
|
37
56
|
end
|
38
57
|
end
|