rubocop 0.33.0 → 0.34.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 +62 -1
- data/README.md +65 -6
- data/config/default.yml +30 -0
- data/config/disabled.yml +5 -0
- data/config/enabled.yml +19 -3
- data/lib/rubocop.rb +7 -2
- data/lib/rubocop/cli.rb +1 -1
- data/lib/rubocop/config.rb +11 -6
- data/lib/rubocop/config_loader.rb +7 -3
- data/lib/rubocop/cop/commissioner.rb +6 -11
- data/lib/rubocop/cop/cop.rb +7 -3
- data/lib/rubocop/cop/lint/deprecated_class_methods.rb +10 -8
- data/lib/rubocop/cop/lint/duplicated_key.rb +37 -0
- data/lib/rubocop/cop/lint/end_alignment.rb +6 -6
- data/lib/rubocop/cop/lint/format_parameter_mismatch.rb +57 -14
- data/lib/rubocop/cop/metrics/method_length.rb +1 -3
- data/lib/rubocop/cop/mixin/annotation_comment.rb +1 -2
- data/lib/rubocop/cop/mixin/autocorrect_alignment.rb +11 -1
- data/lib/rubocop/cop/mixin/configurable_naming.rb +14 -3
- data/lib/rubocop/cop/mixin/empty_lines_around_body.rb +1 -3
- data/lib/rubocop/cop/mixin/end_keyword_alignment.rb +9 -0
- data/lib/rubocop/cop/mixin/method_preference.rb +28 -0
- data/lib/rubocop/cop/mixin/safe_assignment.rb +2 -2
- data/lib/rubocop/cop/performance/case_when_splat.rb +132 -0
- data/lib/rubocop/cop/performance/string_replacement.rb +45 -28
- data/lib/rubocop/cop/rails/action_filter.rb +31 -5
- data/lib/rubocop/cop/rails/date.rb +6 -5
- data/lib/rubocop/cop/rails/read_write_attribute.rb +1 -1
- data/lib/rubocop/cop/rails/time_zone.rb +12 -1
- data/lib/rubocop/cop/style/alias.rb +1 -0
- data/lib/rubocop/cop/style/block_delimiters.rb +6 -5
- data/lib/rubocop/cop/style/collection_methods.rb +2 -20
- data/lib/rubocop/cop/style/else_alignment.rb +2 -1
- data/lib/rubocop/cop/style/empty_line_between_defs.rb +42 -13
- data/lib/rubocop/cop/style/extra_spacing.rb +17 -3
- data/lib/rubocop/cop/style/first_parameter_indentation.rb +1 -1
- data/lib/rubocop/cop/style/hash_syntax.rb +5 -0
- data/lib/rubocop/cop/style/indentation_width.rb +7 -1
- data/lib/rubocop/cop/style/initial_indentation.rb +5 -0
- data/lib/rubocop/cop/style/multiline_operation_indentation.rb +1 -1
- data/lib/rubocop/cop/style/mutable_constant.rb +35 -0
- data/lib/rubocop/cop/style/next.rb +31 -14
- data/lib/rubocop/cop/style/option_hash.rb +9 -1
- data/lib/rubocop/cop/style/parallel_assignment.rb +21 -44
- data/lib/rubocop/cop/style/redundant_freeze.rb +37 -0
- data/lib/rubocop/cop/style/rescue_ensure_alignment.rb +2 -1
- data/lib/rubocop/cop/style/rescue_modifier.rb +35 -3
- data/lib/rubocop/cop/style/space_inside_string_interpolation.rb +1 -0
- data/lib/rubocop/cop/style/string_methods.rb +32 -0
- data/lib/rubocop/cop/style/symbol_proc.rb +54 -12
- data/lib/rubocop/cop/style/trailing_blank_lines.rb +1 -1
- data/lib/rubocop/cop/team.rb +2 -2
- data/lib/rubocop/cop/util.rb +2 -2
- data/lib/rubocop/cop/variable_force.rb +10 -10
- data/lib/rubocop/cop/variable_force/locatable.rb +5 -5
- data/lib/rubocop/formatter/formatter_set.rb +1 -0
- data/lib/rubocop/options.rb +24 -1
- data/lib/rubocop/result_cache.rb +121 -0
- data/lib/rubocop/runner.rb +55 -15
- data/lib/rubocop/target_finder.rb +1 -1
- data/lib/rubocop/version.rb +1 -1
- data/relnotes/v0.34.0.md +182 -0
- data/rubocop.gemspec +1 -1
- metadata +12 -4
@@ -0,0 +1,132 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Performance
|
6
|
+
# Place `when` conditions that use splat at the end
|
7
|
+
# of the list of `when` branches.
|
8
|
+
#
|
9
|
+
# Ruby has to allocate memory for the splat expansion every time
|
10
|
+
# that the `case` `when` statement is run. Since Ruby does not support
|
11
|
+
# fall through inside of `case` `when`, like some other languages do,
|
12
|
+
# the order of the `when` branches does not matter. By placing any
|
13
|
+
# splat expansions at the end of the list of `when` branches we will
|
14
|
+
# reduce the number of times that memory has to be allocated for
|
15
|
+
# the expansion.
|
16
|
+
#
|
17
|
+
# This is not a guaranteed performance improvement. If the data being
|
18
|
+
# processed by the `case` condition is normalized in a manner that favors
|
19
|
+
# hitting a condition in the splat expansion, it is possible that
|
20
|
+
# moving the splat condition to the end will use more memory,
|
21
|
+
# and run slightly slower.
|
22
|
+
#
|
23
|
+
# @example
|
24
|
+
# # bad
|
25
|
+
# case foo
|
26
|
+
# when *condition
|
27
|
+
# bar
|
28
|
+
# when baz
|
29
|
+
# foobar
|
30
|
+
# end
|
31
|
+
#
|
32
|
+
# case foo
|
33
|
+
# when *[1, 2, 3, 4]
|
34
|
+
# bar
|
35
|
+
# when 5
|
36
|
+
# baz
|
37
|
+
# end
|
38
|
+
#
|
39
|
+
# # good
|
40
|
+
# case foo
|
41
|
+
# when baz
|
42
|
+
# foobar
|
43
|
+
# when *condition
|
44
|
+
# bar
|
45
|
+
# end
|
46
|
+
#
|
47
|
+
# case foo
|
48
|
+
# when 1, 2, 3, 4
|
49
|
+
# bar
|
50
|
+
# when 5
|
51
|
+
# baz
|
52
|
+
# end
|
53
|
+
class CaseWhenSplat < Cop
|
54
|
+
include AutocorrectAlignment
|
55
|
+
|
56
|
+
MSG = 'Place `when` conditions with a splat ' \
|
57
|
+
'at the end of the `when` branches.'.freeze
|
58
|
+
ARRAY_MSG = 'Do not expand array literals in `when` conditions.'.freeze
|
59
|
+
|
60
|
+
def on_case(node)
|
61
|
+
_case_branch, *when_branches, _else_branch = *node
|
62
|
+
when_conditions =
|
63
|
+
when_branches.each_with_object([]) do |branch, conditions|
|
64
|
+
condition, = *branch
|
65
|
+
conditions << condition
|
66
|
+
end
|
67
|
+
|
68
|
+
splat_offenses(when_conditions).reverse_each do |condition|
|
69
|
+
range = condition.parent.loc.keyword.join(condition.loc.expression)
|
70
|
+
variable, = *condition
|
71
|
+
message = variable.array_type? ? ARRAY_MSG : MSG
|
72
|
+
add_offense(condition.parent, range, message)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def autocorrect(node)
|
77
|
+
condition, = *node
|
78
|
+
variable, = *condition
|
79
|
+
if variable.array_type?
|
80
|
+
correct_array_literal(condition, variable)
|
81
|
+
else
|
82
|
+
reorder_splat_condition(node)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
private
|
87
|
+
|
88
|
+
def splat_offenses(when_conditions)
|
89
|
+
found_non_splat = false
|
90
|
+
when_conditions.reverse.each_with_object([]) do |condition, result|
|
91
|
+
found_non_splat ||= true if error_condition?(condition)
|
92
|
+
|
93
|
+
next unless condition.splat_type?
|
94
|
+
result << condition if found_non_splat
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
def error_condition?(condition)
|
99
|
+
variable, = *condition
|
100
|
+
|
101
|
+
(condition.splat_type? && variable.array_type?) ||
|
102
|
+
!condition.splat_type?
|
103
|
+
end
|
104
|
+
|
105
|
+
def correct_array_literal(condition, variable)
|
106
|
+
lambda do |corrector|
|
107
|
+
corrector.remove(condition.loc.operator)
|
108
|
+
corrector.remove(variable.loc.begin)
|
109
|
+
corrector.remove(variable.loc.end)
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
def reorder_splat_condition(node)
|
114
|
+
_case_branch, *when_branches, _else_branch = *node.parent
|
115
|
+
current_index = when_branches.index { |branch| branch == node }
|
116
|
+
next_branch = when_branches[current_index + 1]
|
117
|
+
correction = "\n#{offset(node)}#{node.loc.expression.source}"
|
118
|
+
range =
|
119
|
+
Parser::Source::Range.new(node.parent,
|
120
|
+
node.loc.expression.begin_pos,
|
121
|
+
next_branch.loc.expression.begin_pos)
|
122
|
+
|
123
|
+
lambda do |corrector|
|
124
|
+
corrector.remove(range)
|
125
|
+
corrector.insert_after(when_branches.last.loc.expression,
|
126
|
+
correction)
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
@@ -20,10 +20,15 @@ module RuboCop
|
|
20
20
|
# 'a b c'.delete(' ')
|
21
21
|
class StringReplacement < Cop
|
22
22
|
MSG = 'Use `%s` instead of `%s`.'
|
23
|
-
DETERMINISTIC_REGEX = /^[\w\s\-,."']
|
24
|
-
REGEXP_CONSTRUCTOR_METHODS = [:new, :compile]
|
25
|
-
GSUB_METHODS = [:gsub, :gsub!]
|
26
|
-
DETERMINISTIC_TYPES = [:regexp, :str, :send]
|
23
|
+
DETERMINISTIC_REGEX = /^[\w\s\-,."']+$/.freeze
|
24
|
+
REGEXP_CONSTRUCTOR_METHODS = [:new, :compile].freeze
|
25
|
+
GSUB_METHODS = [:gsub, :gsub!].freeze
|
26
|
+
DETERMINISTIC_TYPES = [:regexp, :str, :send].freeze
|
27
|
+
DELETE = 'delete'.freeze
|
28
|
+
TR = 'tr'.freeze
|
29
|
+
BANG = '!'.freeze
|
30
|
+
SINGLE_QUOTE = "'".freeze
|
31
|
+
CLOSING_PAREN = ')'.freeze
|
27
32
|
|
28
33
|
def on_send(node)
|
29
34
|
_string, method, first_param, second_param = *node
|
@@ -51,19 +56,20 @@ module RuboCop
|
|
51
56
|
_string, method, first_param, second_param = *node
|
52
57
|
first_source = first_source(first_param)
|
53
58
|
second_source, = *second_param
|
54
|
-
replacement_method = replacement_method(
|
59
|
+
replacement_method = replacement_method(method,
|
60
|
+
first_source,
|
61
|
+
second_source)
|
55
62
|
|
56
63
|
lambda do |corrector|
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
corrector.replace(range(node), replacement)
|
64
|
+
corrector.replace(node.loc.selector, replacement_method)
|
65
|
+
unless first_param.str_type?
|
66
|
+
corrector.replace(first_param.loc.expression,
|
67
|
+
escape(first_source))
|
68
|
+
end
|
69
|
+
|
70
|
+
if second_source.empty? && first_source.length == 1
|
71
|
+
remove_second_param(corrector, node, first_param)
|
72
|
+
end
|
67
73
|
end
|
68
74
|
end
|
69
75
|
|
@@ -123,24 +129,26 @@ module RuboCop
|
|
123
129
|
node.loc.expression.end_pos)
|
124
130
|
end
|
125
131
|
|
126
|
-
def replacement_method(first_source, second_source)
|
127
|
-
if second_source.empty? && first_source.length == 1
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
+
def replacement_method(method, first_source, second_source)
|
133
|
+
replacement = if second_source.empty? && first_source.length == 1
|
134
|
+
DELETE
|
135
|
+
else
|
136
|
+
TR
|
137
|
+
end
|
138
|
+
|
139
|
+
"#{replacement}#{BANG if bang_method?(method)}"
|
132
140
|
end
|
133
141
|
|
134
142
|
def message(method, first_source, second_source)
|
135
|
-
replacement_method = replacement_method(
|
143
|
+
replacement_method = replacement_method(method,
|
144
|
+
first_source,
|
145
|
+
second_source)
|
136
146
|
|
137
|
-
format(MSG,
|
138
|
-
"#{replacement_method}#{'!' if bang_method?(method)}",
|
139
|
-
method)
|
147
|
+
format(MSG, replacement_method, method)
|
140
148
|
end
|
141
149
|
|
142
150
|
def bang_method?(method)
|
143
|
-
method.to_s.end_with?(
|
151
|
+
method.to_s.end_with?(BANG)
|
144
152
|
end
|
145
153
|
|
146
154
|
def escape(string)
|
@@ -152,8 +160,17 @@ module RuboCop
|
|
152
160
|
end
|
153
161
|
|
154
162
|
def require_double_quotes?(string)
|
155
|
-
|
156
|
-
StringHelp::ESCAPED_CHAR_REGEXP =~ string
|
163
|
+
string.inspect.include?(SINGLE_QUOTE) ||
|
164
|
+
StringHelp::ESCAPED_CHAR_REGEXP =~ string
|
165
|
+
end
|
166
|
+
|
167
|
+
def remove_second_param(corrector, node, first_param)
|
168
|
+
end_range =
|
169
|
+
Parser::Source::Range.new(node.loc.expression.source_buffer,
|
170
|
+
first_param.loc.expression.end_pos,
|
171
|
+
node.loc.expression.end_pos)
|
172
|
+
|
173
|
+
corrector.replace(end_range, CLOSING_PAREN)
|
157
174
|
end
|
158
175
|
end
|
159
176
|
end
|
@@ -12,11 +12,37 @@ module RuboCop
|
|
12
12
|
|
13
13
|
MSG = 'Prefer `%s` over `%s`.'
|
14
14
|
|
15
|
-
FILTER_METHODS = [
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
15
|
+
FILTER_METHODS = [
|
16
|
+
:after_filter,
|
17
|
+
:append_after_filter,
|
18
|
+
:append_around_filter,
|
19
|
+
:append_before_filter,
|
20
|
+
:around_filter,
|
21
|
+
:before_filter,
|
22
|
+
:prepend_after_filter,
|
23
|
+
:prepend_around_filter,
|
24
|
+
:prepend_before_filter,
|
25
|
+
:skip_after_filter,
|
26
|
+
:skip_around_filter,
|
27
|
+
:skip_before_filter,
|
28
|
+
:skip_filter
|
29
|
+
]
|
30
|
+
|
31
|
+
ACTION_METHODS = [
|
32
|
+
:after_action,
|
33
|
+
:append_after_action,
|
34
|
+
:append_around_action,
|
35
|
+
:append_before_action,
|
36
|
+
:around_action,
|
37
|
+
:before_action,
|
38
|
+
:prepend_after_action,
|
39
|
+
:prepend_around_action,
|
40
|
+
:prepend_before_action,
|
41
|
+
:skip_after_action,
|
42
|
+
:skip_around_action,
|
43
|
+
:skip_before_action,
|
44
|
+
:skip_action_callback
|
45
|
+
]
|
20
46
|
|
21
47
|
def on_block(node)
|
22
48
|
method, _args, _body = *node
|
@@ -33,15 +33,15 @@ module RuboCop
|
|
33
33
|
# Date.today
|
34
34
|
# date.to_time
|
35
35
|
#
|
36
|
-
# # reports offense only when style is '
|
36
|
+
# # reports offense only when style is 'strict'
|
37
37
|
# date.to_time_in_current_zone
|
38
38
|
class Date < Cop
|
39
39
|
include ConfigurableEnforcedStyle
|
40
40
|
|
41
41
|
MSG = 'Do not use `%s` without zone. Use `%s` instead.'
|
42
42
|
|
43
|
-
MSG_SEND = 'Do not use `%s` on Date objects,' \
|
44
|
-
'because
|
43
|
+
MSG_SEND = 'Do not use `%s` on Date objects, ' \
|
44
|
+
'because they know nothing about the time zone in use.'
|
45
45
|
|
46
46
|
BAD_DAYS = [:today, :current, :yesterday, :tomorrow]
|
47
47
|
|
@@ -54,8 +54,9 @@ module RuboCop
|
|
54
54
|
end
|
55
55
|
|
56
56
|
def on_send(node)
|
57
|
-
receiver, method_name, *
|
57
|
+
receiver, method_name, *args = *node
|
58
58
|
return unless receiver && bad_methods.include?(method_name)
|
59
|
+
return if method_name == :to_time && args.length == 1
|
59
60
|
|
60
61
|
add_offense(node, :selector,
|
61
62
|
format(MSG_SEND,
|
@@ -96,7 +97,7 @@ module RuboCop
|
|
96
97
|
# checks that parent node of send_type
|
97
98
|
# and receiver is the given node
|
98
99
|
def method_send?(node)
|
99
|
-
return false unless node.parent.send_type?
|
100
|
+
return false unless node.parent && node.parent.send_type?
|
100
101
|
|
101
102
|
receiver, _method_name, *_args = *node.parent
|
102
103
|
|
@@ -33,7 +33,7 @@ module RuboCop
|
|
33
33
|
if method_name == :read_attribute
|
34
34
|
format(MSG, 'self[:attr]', 'read_attribute(:attr)')
|
35
35
|
else
|
36
|
-
format(MSG, 'self[:attr] = val', 'write_attribute(:attr,
|
36
|
+
format(MSG, 'self[:attr] = val', 'write_attribute(:attr, val)')
|
37
37
|
end
|
38
38
|
end
|
39
39
|
|
@@ -66,6 +66,8 @@ module RuboCop
|
|
66
66
|
|
67
67
|
method_name = (chain & DANGEROUS_METHODS).join('.')
|
68
68
|
|
69
|
+
return if offset_provided?(node)
|
70
|
+
|
69
71
|
message = build_message(klass, method_name, node)
|
70
72
|
|
71
73
|
add_offense(node, :selector, message)
|
@@ -107,7 +109,7 @@ module RuboCop
|
|
107
109
|
# checks that parent node of send_type
|
108
110
|
# and receiver is the given node
|
109
111
|
def method_send?(node)
|
110
|
-
return false unless node.parent.send_type?
|
112
|
+
return false unless node.parent && node.parent.send_type?
|
111
113
|
|
112
114
|
receiver, _method_name, *_args = *node.parent
|
113
115
|
|
@@ -163,6 +165,15 @@ module RuboCop
|
|
163
165
|
|
164
166
|
acceptable
|
165
167
|
end
|
168
|
+
|
169
|
+
# Time.new can be called with a time zone offset
|
170
|
+
# When it is, that should be considered safe
|
171
|
+
# Example:
|
172
|
+
# Time.new(1988, 3, 15, 3, 0, 0, "-05:00")
|
173
|
+
def offset_provided?(node)
|
174
|
+
_, _, *args = *node
|
175
|
+
args.length >= 7
|
176
|
+
end
|
166
177
|
end
|
167
178
|
end
|
168
179
|
end
|
@@ -59,11 +59,8 @@ module RuboCop
|
|
59
59
|
b = node.loc.begin
|
60
60
|
e = node.loc.end
|
61
61
|
if b.is?('{')
|
62
|
-
|
63
|
-
|
64
|
-
if b.source_buffer.source[b.begin_pos - 1, 1] =~ /\S/
|
65
|
-
corrector.insert_before(b, ' ')
|
66
|
-
end
|
62
|
+
corrector.insert_before(b, ' ') unless whitespace_before?(b)
|
63
|
+
corrector.insert_before(e, ' ') unless whitespace_before?(e)
|
67
64
|
corrector.replace(b, 'do')
|
68
65
|
corrector.replace(e, 'end')
|
69
66
|
else
|
@@ -73,6 +70,10 @@ module RuboCop
|
|
73
70
|
end
|
74
71
|
end
|
75
72
|
|
73
|
+
def whitespace_before?(node)
|
74
|
+
node.source_buffer.source[node.begin_pos - 1, 1] =~ /\s/
|
75
|
+
end
|
76
|
+
|
76
77
|
def get_block(node)
|
77
78
|
case node.type
|
78
79
|
when :block
|
@@ -10,6 +10,8 @@ module RuboCop
|
|
10
10
|
# Enumerable or not (static analysis limitation), so this cop
|
11
11
|
# can yield some false positives.
|
12
12
|
class CollectionMethods < Cop
|
13
|
+
include MethodPreference
|
14
|
+
|
13
15
|
MSG = 'Prefer `%s` over `%s`.'
|
14
16
|
|
15
17
|
def on_block(node)
|
@@ -44,26 +46,6 @@ module RuboCop
|
|
44
46
|
method_name)
|
45
47
|
)
|
46
48
|
end
|
47
|
-
|
48
|
-
def preferred_method(method)
|
49
|
-
preferred_methods[method.to_sym]
|
50
|
-
end
|
51
|
-
|
52
|
-
def preferred_methods
|
53
|
-
@preferred_methods ||=
|
54
|
-
begin
|
55
|
-
# Make sure default configuration 'foo' => 'bar' is removed from
|
56
|
-
# the total configuration if there is a 'bar' => 'foo' override.
|
57
|
-
default = default_cop_config['PreferredMethods']
|
58
|
-
merged = cop_config['PreferredMethods']
|
59
|
-
overrides = merged.values - default.values
|
60
|
-
merged.reject { |key, _| overrides.include?(key) }.symbolize_keys
|
61
|
-
end
|
62
|
-
end
|
63
|
-
|
64
|
-
def default_cop_config
|
65
|
-
ConfigLoader.default_configuration[cop_name]
|
66
|
-
end
|
67
49
|
end
|
68
50
|
end
|
69
51
|
end
|
@@ -8,6 +8,7 @@ module RuboCop
|
|
8
8
|
# are special cases when they should follow the same rules as the
|
9
9
|
# alignment of end.
|
10
10
|
class ElseAlignment < Cop
|
11
|
+
include EndKeywordAlignment
|
11
12
|
include AutocorrectAlignment
|
12
13
|
include CheckAssignment
|
13
14
|
|
@@ -86,7 +87,7 @@ module RuboCop
|
|
86
87
|
|
87
88
|
end_config = config.for_cop('Lint/EndAlignment')
|
88
89
|
style = end_config['Enabled'] ? end_config['AlignWith'] : 'keyword'
|
89
|
-
base =
|
90
|
+
base = variable_alignment?(node.loc, rhs, style.to_sym) ? node : rhs
|
90
91
|
|
91
92
|
return if rhs.type != :if
|
92
93
|
|