rubocop 0.57.2 → 0.58.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +12 -9
- data/bin/setup +7 -0
- data/config/default.yml +18 -2
- data/config/disabled.yml +4 -0
- data/lib/rubocop.rb +1 -0
- data/lib/rubocop/ast/node.rb +5 -0
- data/lib/rubocop/ast/node/str_node.rb +2 -0
- data/lib/rubocop/cli.rb +4 -7
- data/lib/rubocop/config.rb +4 -4
- data/lib/rubocop/config_loader.rb +4 -8
- data/lib/rubocop/cop/corrector.rb +25 -0
- data/lib/rubocop/cop/layout/closing_heredoc_indentation.rb +3 -7
- data/lib/rubocop/cop/layout/end_alignment.rb +1 -1
- data/lib/rubocop/cop/layout/indentation_width.rb +9 -1
- data/lib/rubocop/cop/layout/leading_blank_lines.rb +1 -1
- data/lib/rubocop/cop/lint/ineffective_access_modifier.rb +28 -51
- data/lib/rubocop/cop/lint/redundant_with_object.rb +1 -1
- data/lib/rubocop/cop/lint/shadowed_argument.rb +7 -3
- data/lib/rubocop/cop/lint/unneeded_splat_expansion.rb +1 -1
- data/lib/rubocop/cop/lint/useless_access_modifier.rb +17 -4
- data/lib/rubocop/cop/metrics/line_length.rb +28 -6
- data/lib/rubocop/cop/mixin/check_assignment.rb +0 -2
- data/lib/rubocop/cop/mixin/statement_modifier.rb +6 -1
- data/lib/rubocop/cop/naming/memoized_instance_variable_name.rb +79 -4
- data/lib/rubocop/cop/performance/inefficient_hash_search.rb +9 -5
- data/lib/rubocop/cop/performance/range_include.rb +9 -3
- data/lib/rubocop/cop/performance/sample.rb +6 -4
- data/lib/rubocop/cop/rails/bulk_change_table.rb +11 -7
- data/lib/rubocop/cop/rails/create_table_with_timestamps.rb +3 -1
- data/lib/rubocop/cop/registry.rb +11 -2
- data/lib/rubocop/cop/style/encoding.rb +5 -0
- data/lib/rubocop/cop/style/end_block.rb +8 -0
- data/lib/rubocop/cop/style/if_unless_modifier.rb +2 -1
- data/lib/rubocop/cop/style/ip_addresses.rb +76 -0
- data/lib/rubocop/cop/style/multiple_comparison.rb +16 -2
- data/lib/rubocop/cop/style/symbol_proc.rb +4 -2
- data/lib/rubocop/cop/style/unneeded_condition.rb +19 -2
- data/lib/rubocop/formatter/disabled_config_formatter.rb +3 -3
- data/lib/rubocop/options.rb +20 -12
- data/lib/rubocop/processed_source.rb +2 -5
- data/lib/rubocop/rspec/cop_helper.rb +0 -4
- data/lib/rubocop/rspec/shared_contexts.rb +0 -4
- data/lib/rubocop/rspec/shared_examples.rb +0 -23
- data/lib/rubocop/version.rb +1 -1
- metadata +7 -11
@@ -77,9 +77,7 @@ module RuboCop
|
|
77
77
|
next if references.any? do |reference|
|
78
78
|
next true if !reference.explicit? && ignore_implicit_references?
|
79
79
|
|
80
|
-
reference_pos
|
81
|
-
|
82
|
-
reference_pos <= assignment_without_usage_pos
|
80
|
+
reference_pos(reference.node) <= assignment_without_usage_pos
|
83
81
|
end
|
84
82
|
|
85
83
|
yield location_known ? node : argument.declaration_node
|
@@ -115,6 +113,12 @@ module RuboCop
|
|
115
113
|
end
|
116
114
|
end
|
117
115
|
|
116
|
+
def reference_pos(node)
|
117
|
+
node = node.parent.masgn_type? ? node.parent : node
|
118
|
+
|
119
|
+
node.source_range.begin_pos
|
120
|
+
end
|
121
|
+
|
118
122
|
# Check whether the given node is nested into block or conditional.
|
119
123
|
#
|
120
124
|
def node_within_block_or_conditional?(node, stop_search_node)
|
@@ -134,11 +134,16 @@ module RuboCop
|
|
134
134
|
|
135
135
|
if node.begin_type?
|
136
136
|
check_scope(node)
|
137
|
-
elsif node.send_type? && node
|
137
|
+
elsif node.send_type? && access_modifier?(node)
|
138
138
|
add_offense(node, message: format(MSG, current: node.method_name))
|
139
139
|
end
|
140
140
|
end
|
141
141
|
|
142
|
+
def access_modifier?(node)
|
143
|
+
node.bare_access_modifier? ||
|
144
|
+
node.method_name == :private_class_method
|
145
|
+
end
|
146
|
+
|
142
147
|
def check_scope(node)
|
143
148
|
cur_vis, unused = check_child_nodes(node, nil, :public)
|
144
149
|
|
@@ -147,9 +152,8 @@ module RuboCop
|
|
147
152
|
|
148
153
|
def check_child_nodes(node, unused, cur_vis)
|
149
154
|
node.child_nodes.each do |child|
|
150
|
-
if child.send_type? && child
|
151
|
-
cur_vis, unused =
|
152
|
-
check_new_visibility(child, unused, child.method_name, cur_vis)
|
155
|
+
if child.send_type? && access_modifier?(child)
|
156
|
+
cur_vis, unused = check_send_node(child, cur_vis, unused)
|
153
157
|
elsif method_definition?(child)
|
154
158
|
unused = nil
|
155
159
|
elsif start_of_new_scope?(child)
|
@@ -162,6 +166,15 @@ module RuboCop
|
|
162
166
|
[cur_vis, unused]
|
163
167
|
end
|
164
168
|
|
169
|
+
def check_send_node(node, cur_vis, unused)
|
170
|
+
if node.bare_access_modifier?
|
171
|
+
check_new_visibility(node, unused, node.method_name, cur_vis)
|
172
|
+
elsif node.method_name == :private_class_method && !node.arguments?
|
173
|
+
add_offense(node, message: format(MSG, current: node.method_name))
|
174
|
+
[cur_vis, unused]
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
165
178
|
def check_new_visibility(node, unused, new_vis, cur_vis)
|
166
179
|
# does this modifier just repeat the existing visibility?
|
167
180
|
if new_vis == cur_vis
|
@@ -7,6 +7,8 @@ module RuboCop
|
|
7
7
|
module Metrics
|
8
8
|
# This cop checks the length of lines in the source code.
|
9
9
|
# The maximum length is configurable.
|
10
|
+
# The tab size is configured in the `IndentationWidth`
|
11
|
+
# of the `Layout/Tab` cop.
|
10
12
|
class LineLength < Cop
|
11
13
|
include ConfigurableMax
|
12
14
|
include IgnoredPattern
|
@@ -23,8 +25,24 @@ module RuboCop
|
|
23
25
|
|
24
26
|
private
|
25
27
|
|
28
|
+
def tab_indentation_width
|
29
|
+
config.for_cop('Layout/Tab')['IndentationWidth']
|
30
|
+
end
|
31
|
+
|
32
|
+
def line_length(line)
|
33
|
+
if tab_indentation_width
|
34
|
+
line = line.gsub("\t", ' ' * tab_indentation_width)
|
35
|
+
end
|
36
|
+
line.length
|
37
|
+
end
|
38
|
+
|
39
|
+
def highligh_start(line)
|
40
|
+
return max unless tab_indentation_width
|
41
|
+
max - (tab_indentation_width - 1) * line.count("\t")
|
42
|
+
end
|
43
|
+
|
26
44
|
def check_line(line, index, heredocs)
|
27
|
-
return if line
|
45
|
+
return if line_length(line) <= max
|
28
46
|
return if ignored_line?(line, index, heredocs)
|
29
47
|
|
30
48
|
if ignore_cop_directives? && directive_on_source_line?(index)
|
@@ -33,7 +51,10 @@ module RuboCop
|
|
33
51
|
return check_uri_line(line, index) if allow_uri?
|
34
52
|
|
35
53
|
register_offense(
|
36
|
-
source_range(
|
54
|
+
source_range(
|
55
|
+
processed_source.buffer, index,
|
56
|
+
highligh_start(line)...line_length(line)
|
57
|
+
),
|
37
58
|
line
|
38
59
|
)
|
39
60
|
end
|
@@ -44,10 +65,10 @@ module RuboCop
|
|
44
65
|
end
|
45
66
|
|
46
67
|
def register_offense(loc, line)
|
47
|
-
message = format(MSG, length: line
|
68
|
+
message = format(MSG, length: line_length(line), max: max)
|
48
69
|
|
49
70
|
add_offense(nil, location: loc, message: message) do
|
50
|
-
self.max = line
|
71
|
+
self.max = line_length(line)
|
51
72
|
end
|
52
73
|
end
|
53
74
|
|
@@ -59,7 +80,7 @@ module RuboCop
|
|
59
80
|
end
|
60
81
|
|
61
82
|
source_range(processed_source.buffer, index + 1,
|
62
|
-
excessive_position...(line
|
83
|
+
excessive_position...(line_length(line)))
|
63
84
|
end
|
64
85
|
|
65
86
|
def max
|
@@ -100,7 +121,8 @@ module RuboCop
|
|
100
121
|
|
101
122
|
def allowed_uri_position?(line, uri_range)
|
102
123
|
uri_range.begin < max &&
|
103
|
-
(uri_range.end == line
|
124
|
+
(uri_range.end == line_length(line) ||
|
125
|
+
uri_range.end == line_length(line) - 1)
|
104
126
|
end
|
105
127
|
|
106
128
|
def find_excessive_uri_range(line)
|
@@ -39,7 +39,7 @@ module RuboCop
|
|
39
39
|
end
|
40
40
|
|
41
41
|
def length_in_modifier_form(node, cond, body_length)
|
42
|
-
indentation = node.loc.keyword.column
|
42
|
+
indentation = node.loc.keyword.column * indentation_multiplier
|
43
43
|
kw_length = node.loc.keyword.size
|
44
44
|
cond_length = cond.source_range.size
|
45
45
|
space = 1
|
@@ -49,6 +49,11 @@ module RuboCop
|
|
49
49
|
def max_line_length
|
50
50
|
config.for_cop('Metrics/LineLength')['Max']
|
51
51
|
end
|
52
|
+
|
53
|
+
def indentation_multiplier
|
54
|
+
return 1 if config.for_cop('Layout/Tab')['Enabled']
|
55
|
+
config.for_cop('Layout/Tab')['IndentationWidth']
|
56
|
+
end
|
52
57
|
end
|
53
58
|
end
|
54
59
|
end
|
@@ -6,7 +6,13 @@ module RuboCop
|
|
6
6
|
# This cop checks for memoized methods whose instance variable name
|
7
7
|
# does not match the method name.
|
8
8
|
#
|
9
|
-
#
|
9
|
+
# This cop can be configured with the EnforcedStyleForLeadingUnderscores
|
10
|
+
# directive. It can be configured to allow for memoized instance variables
|
11
|
+
# prefixed with an underscore. Prefixing ivars with an undersscore is a
|
12
|
+
# convention that is used to implicitly indicate that an ivar should not
|
13
|
+
# be set or referencd outside of the memoization method.
|
14
|
+
#
|
15
|
+
# @example EnforcedStyleForLeadingUnderscores: disallowed (default)
|
10
16
|
# # bad
|
11
17
|
# # Method foo is memoized using an instance variable that is
|
12
18
|
# # not `@foo`. This can cause confusion and bugs.
|
@@ -32,9 +38,44 @@ module RuboCop
|
|
32
38
|
# @foo ||= calculate_expensive_thing(helper_variable)
|
33
39
|
# end
|
34
40
|
#
|
41
|
+
# @example EnforcedStyleForLeadingUnderscores :required
|
42
|
+
# # bad
|
43
|
+
# def foo
|
44
|
+
# @something ||= calculate_expensive_thing
|
45
|
+
# end
|
46
|
+
#
|
47
|
+
# # bad
|
48
|
+
# def foo
|
49
|
+
# @foo ||= calculate_expensive_thing
|
50
|
+
# end
|
51
|
+
#
|
52
|
+
# # good
|
53
|
+
# def foo
|
54
|
+
# @_foo ||= calculate_expensive_thing
|
55
|
+
# end
|
56
|
+
#
|
57
|
+
# @example EnforcedStyleForLeadingUnderscores :optional
|
58
|
+
# # bad
|
59
|
+
# def foo
|
60
|
+
# @something ||= calculate_expensive_thing
|
61
|
+
# end
|
62
|
+
#
|
63
|
+
# # good
|
64
|
+
# def foo
|
65
|
+
# @foo ||= calculate_expensive_thing
|
66
|
+
# end
|
67
|
+
#
|
68
|
+
# # good
|
69
|
+
# def foo
|
70
|
+
# @_foo ||= calculate_expensive_thing
|
71
|
+
# end
|
35
72
|
class MemoizedInstanceVariableName < Cop
|
73
|
+
include ConfigurableEnforcedStyle
|
74
|
+
|
36
75
|
MSG = 'Memoized variable `%<var>s` does not match ' \
|
37
76
|
'method name `%<method>s`. Use `@%<suggested_var>s` instead.'.freeze
|
77
|
+
UNDERSCORE_REQUIRED = 'Memoized variable `%<var>s` does not start ' \
|
78
|
+
'with `_`. Use `@%<suggested_var>s` instead.'.freeze
|
38
79
|
|
39
80
|
def self.node_pattern
|
40
81
|
memo_assign = '(or_asgn $(ivasgn _) _)'
|
@@ -52,10 +93,11 @@ module RuboCop
|
|
52
93
|
def on_def(node)
|
53
94
|
(method_name, ivar_assign) = memoized?(node)
|
54
95
|
return if matches?(method_name, ivar_assign)
|
96
|
+
|
55
97
|
msg = format(
|
56
|
-
|
98
|
+
message(ivar_assign.children.first.to_s),
|
57
99
|
var: ivar_assign.children.first.to_s,
|
58
|
-
suggested_var: method_name
|
100
|
+
suggested_var: suggested_var(method_name),
|
59
101
|
method: method_name
|
60
102
|
)
|
61
103
|
add_offense(node, location: ivar_assign.source_range, message: msg)
|
@@ -64,12 +106,45 @@ module RuboCop
|
|
64
106
|
|
65
107
|
private
|
66
108
|
|
109
|
+
def style_parameter_name
|
110
|
+
'EnforcedStyleForLeadingUnderscores'
|
111
|
+
end
|
112
|
+
|
67
113
|
def matches?(method_name, ivar_assign)
|
68
114
|
return true if ivar_assign.nil? || method_name == :initialize
|
69
115
|
method_name = method_name.to_s.delete('!?')
|
70
116
|
variable = ivar_assign.children.first
|
71
117
|
variable_name = variable.to_s.sub('@', '')
|
72
|
-
|
118
|
+
|
119
|
+
return false unless valid_leading_underscore?(variable_name)
|
120
|
+
|
121
|
+
variable_name.sub(/\A_/, '') == method_name
|
122
|
+
end
|
123
|
+
|
124
|
+
def message(variable)
|
125
|
+
variable_name = variable.to_s.sub('@', '')
|
126
|
+
|
127
|
+
return UNDERSCORE_REQUIRED if style == :required &&
|
128
|
+
!variable_name.start_with?('_')
|
129
|
+
|
130
|
+
MSG
|
131
|
+
end
|
132
|
+
|
133
|
+
def suggested_var(method_name)
|
134
|
+
suggestion = method_name.to_s.delete('!?')
|
135
|
+
|
136
|
+
style == :required ? "_#{suggestion}" : suggestion
|
137
|
+
end
|
138
|
+
|
139
|
+
def valid_leading_underscore?(variable_name)
|
140
|
+
case style
|
141
|
+
when :required
|
142
|
+
variable_name.start_with?('_')
|
143
|
+
when :disallowed
|
144
|
+
!variable_name.start_with?('_')
|
145
|
+
else
|
146
|
+
true
|
147
|
+
end
|
73
148
|
end
|
74
149
|
end
|
75
150
|
end
|
@@ -38,11 +38,15 @@ module RuboCop
|
|
38
38
|
#
|
39
39
|
class InefficientHashSearch < Cop
|
40
40
|
def_node_matcher :inefficient_include?, <<-PATTERN
|
41
|
-
(send
|
41
|
+
(send (send $_ {:keys :values}) :include? _)
|
42
42
|
PATTERN
|
43
43
|
|
44
44
|
def on_send(node)
|
45
|
-
|
45
|
+
inefficient_include?(node) do |receiver|
|
46
|
+
return if receiver.nil?
|
47
|
+
|
48
|
+
add_offense(node)
|
49
|
+
end
|
46
50
|
end
|
47
51
|
|
48
52
|
def autocorrect(node)
|
@@ -59,7 +63,7 @@ module RuboCop
|
|
59
63
|
|
60
64
|
private
|
61
65
|
|
62
|
-
def
|
66
|
+
def message(node)
|
63
67
|
"Use `##{autocorrect_method(node)}` instead of "\
|
64
68
|
"`##{current_method(node)}.include?`."
|
65
69
|
end
|
@@ -72,7 +76,7 @@ module RuboCop
|
|
72
76
|
end
|
73
77
|
|
74
78
|
def current_method(node)
|
75
|
-
node.
|
79
|
+
node.receiver.method_name
|
76
80
|
end
|
77
81
|
|
78
82
|
def use_long_method
|
@@ -87,7 +91,7 @@ module RuboCop
|
|
87
91
|
end
|
88
92
|
|
89
93
|
def autocorrect_hash_expression(node)
|
90
|
-
node.
|
94
|
+
node.receiver.receiver.source
|
91
95
|
end
|
92
96
|
end
|
93
97
|
end
|
@@ -9,11 +9,17 @@ module RuboCop
|
|
9
9
|
# end points of the `Range`. In a great majority of cases, this is what
|
10
10
|
# is wanted.
|
11
11
|
#
|
12
|
-
#
|
13
|
-
#
|
12
|
+
# @example
|
13
|
+
# # bad
|
14
|
+
# ('a'..'z').include?('b') # => true
|
14
15
|
#
|
15
|
-
#
|
16
|
+
# # good
|
17
|
+
# ('a'..'z').cover?('b') # => true
|
16
18
|
#
|
19
|
+
# # Example of a case where `Range#cover?` may not provide
|
20
|
+
# # the desired result:
|
21
|
+
#
|
22
|
+
# ('a'..'z').cover?('yellow') # => true
|
17
23
|
class RangeInclude < Cop
|
18
24
|
MSG = 'Use `Range#cover?` instead of `Range#include?`.'.freeze
|
19
25
|
|
@@ -11,6 +11,8 @@ module RuboCop
|
|
11
11
|
# [1, 2, 3].shuffle.first
|
12
12
|
# [1, 2, 3].shuffle.first(2)
|
13
13
|
# [1, 2, 3].shuffle.last
|
14
|
+
# [2, 1, 3].shuffle.at(0)
|
15
|
+
# [2, 1, 3].shuffle.slice(0)
|
14
16
|
# [1, 2, 3].shuffle[2]
|
15
17
|
# [1, 2, 3].shuffle[0, 2] # sample(2) will do the same
|
16
18
|
# [1, 2, 3].shuffle[0..2] # sample(3) will do the same
|
@@ -28,7 +30,7 @@ module RuboCop
|
|
28
30
|
MSG = 'Use `%<correct>s` instead of `%<incorrect>s`.'.freeze
|
29
31
|
|
30
32
|
def_node_matcher :sample_candidate?, <<-PATTERN
|
31
|
-
(send $(send _ :shuffle $...) ${:first :last :[]} $...)
|
33
|
+
(send $(send _ :shuffle $...) ${:first :last :[] :at :slice} $...)
|
32
34
|
PATTERN
|
33
35
|
|
34
36
|
def on_send(node)
|
@@ -57,7 +59,7 @@ module RuboCop
|
|
57
59
|
case method
|
58
60
|
when :first, :last
|
59
61
|
true
|
60
|
-
when :[]
|
62
|
+
when :[], :at, :slice
|
61
63
|
sample_size(method_args) != :unknown
|
62
64
|
else
|
63
65
|
false
|
@@ -78,7 +80,7 @@ module RuboCop
|
|
78
80
|
when :erange, :irange
|
79
81
|
range_size(arg)
|
80
82
|
when :int
|
81
|
-
arg.to_a.first
|
83
|
+
[0, -1].include?(arg.to_a.first) ? nil : :unknown
|
82
84
|
else
|
83
85
|
:unknown
|
84
86
|
end
|
@@ -126,7 +128,7 @@ module RuboCop
|
|
126
128
|
case method
|
127
129
|
when :first, :last
|
128
130
|
extract_source(method_args)
|
129
|
-
when :[]
|
131
|
+
when :[], :slice
|
130
132
|
sample_size(method_args)
|
131
133
|
end
|
132
134
|
end
|
@@ -76,7 +76,7 @@ module RuboCop
|
|
76
76
|
MYSQL = 'mysql'.freeze
|
77
77
|
POSTGRESQL = 'postgresql'.freeze
|
78
78
|
|
79
|
-
|
79
|
+
MIGRATION_METHODS = %i[change up down].freeze
|
80
80
|
|
81
81
|
COMBINABLE_TRANSFORMATIONS = %i[
|
82
82
|
primary_key
|
@@ -134,7 +134,7 @@ module RuboCop
|
|
134
134
|
|
135
135
|
def on_def(node)
|
136
136
|
return unless support_bulk_alter?
|
137
|
-
return unless
|
137
|
+
return unless MIGRATION_METHODS.include?(node.method_name)
|
138
138
|
return unless node.body
|
139
139
|
|
140
140
|
recorder = AlterMethodsRecorder.new
|
@@ -168,7 +168,7 @@ module RuboCop
|
|
168
168
|
|
169
169
|
# @param node [RuboCop::AST::SendNode] (send nil? :change_table ...)
|
170
170
|
def include_bulk_options?(node)
|
171
|
-
# arguments: [(sym :table) (hash (pair (sym :bulk) _))]
|
171
|
+
# arguments: [{(sym :table)(str "table")} (hash (pair (sym :bulk) _))]
|
172
172
|
options = node.arguments[1]
|
173
173
|
return false unless options
|
174
174
|
options.hash_type? &&
|
@@ -196,6 +196,8 @@ module RuboCop
|
|
196
196
|
config = yaml['development']
|
197
197
|
return nil unless config.is_a?(Hash)
|
198
198
|
config
|
199
|
+
rescue Psych::SyntaxError
|
200
|
+
nil
|
199
201
|
end
|
200
202
|
|
201
203
|
def support_bulk_alter?
|
@@ -231,7 +233,7 @@ module RuboCop
|
|
231
233
|
|
232
234
|
# @param node [RuboCop::AST::SendNode]
|
233
235
|
def add_offense_for_alter_methods(node)
|
234
|
-
# arguments: [(sym :table) ...]
|
236
|
+
# arguments: [{(sym :table)(str "table")} ...]
|
235
237
|
table_name = node.arguments[0].value
|
236
238
|
message = format(MSG_FOR_ALTER_METHODS, table: table_name)
|
237
239
|
add_offense(node, message: message)
|
@@ -251,9 +253,11 @@ module RuboCop
|
|
251
253
|
|
252
254
|
# @param new_node [RuboCop::AST::SendNode]
|
253
255
|
def process(new_node)
|
254
|
-
# arguments: [(sym :table) ...]
|
255
|
-
table_name = new_node.arguments[0]
|
256
|
-
flush unless @nodes.all?
|
256
|
+
# arguments: [{(sym :table)(str "table")} ...]
|
257
|
+
table_name = new_node.arguments[0].value.to_s
|
258
|
+
flush unless @nodes.all? do |node|
|
259
|
+
node.arguments[0].value.to_s == table_name
|
260
|
+
end
|
257
261
|
@nodes << new_node
|
258
262
|
end
|
259
263
|
|