rubocop 0.79.0 → 0.80.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/LICENSE.txt +1 -1
- data/README.md +3 -3
- data/config/default.yml +33 -19
- data/lib/rubocop.rb +5 -1
- data/lib/rubocop/ast/node.rb +0 -12
- data/lib/rubocop/ast/node/regexp_node.rb +2 -4
- data/lib/rubocop/ast/traversal.rb +9 -0
- data/lib/rubocop/comment_config.rb +6 -1
- data/lib/rubocop/config_obsoletion.rb +2 -1
- data/lib/rubocop/cop/layout/empty_line_between_defs.rb +2 -1
- data/lib/rubocop/cop/layout/leading_comment_space.rb +33 -2
- data/lib/rubocop/cop/layout/line_length.rb +30 -1
- data/lib/rubocop/cop/layout/multiline_hash_brace_layout.rb +0 -4
- data/lib/rubocop/cop/layout/space_around_operators.rb +18 -0
- data/lib/rubocop/cop/layout/space_before_first_arg.rb +8 -0
- data/lib/rubocop/cop/layout/space_inside_hash_literal_braces.rb +2 -9
- data/lib/rubocop/cop/lint/debugger.rb +1 -1
- data/lib/rubocop/cop/lint/redundant_cop_enable_directive.rb +12 -7
- data/lib/rubocop/cop/lint/useless_setter_call.rb +4 -0
- data/lib/rubocop/cop/migration/department_name.rb +14 -1
- data/lib/rubocop/cop/mixin/configurable_enforced_style.rb +4 -0
- data/lib/rubocop/cop/mixin/frozen_string_literal.rb +6 -0
- data/lib/rubocop/cop/mixin/hash_transform_method.rb +172 -0
- data/lib/rubocop/cop/mixin/trailing_comma.rb +2 -9
- data/lib/rubocop/cop/naming/memoized_instance_variable_name.rb +1 -1
- data/lib/rubocop/cop/style/block_delimiters.rb +60 -1
- data/lib/rubocop/cop/style/frozen_string_literal_comment.rb +89 -11
- data/lib/rubocop/cop/style/hash_each_methods.rb +87 -0
- data/lib/rubocop/cop/style/hash_transform_keys.rb +79 -0
- data/lib/rubocop/cop/style/hash_transform_values.rb +79 -0
- data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +5 -0
- data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +5 -4
- data/lib/rubocop/cop/style/or_assignment.rb +3 -2
- data/lib/rubocop/cop/style/symbol_array.rb +2 -2
- data/lib/rubocop/cop/style/ternary_parentheses.rb +1 -1
- data/lib/rubocop/cop/style/trailing_comma_in_arguments.rb +0 -22
- data/lib/rubocop/cop/variable_force.rb +4 -1
- data/lib/rubocop/formatter/formatter_set.rb +1 -0
- data/lib/rubocop/formatter/junit_formatter.rb +63 -0
- data/lib/rubocop/node_pattern.rb +96 -10
- data/lib/rubocop/version.rb +1 -1
- metadata +21 -3
- data/lib/rubocop/cop/style/braces_around_hash_parameters.rb +0 -209
@@ -51,29 +51,65 @@ module RuboCop
|
|
51
51
|
# module Baz
|
52
52
|
# # ...
|
53
53
|
# end
|
54
|
+
#
|
55
|
+
# @example EnforcedStyle: always_true
|
56
|
+
# # The `always_true` style enforces that the frozen string literal
|
57
|
+
# # comment is set to `true`. This is a stricter option than `always`
|
58
|
+
# # and forces projects to use frozen string literals.
|
59
|
+
# # bad
|
60
|
+
# # frozen_string_literal: false
|
61
|
+
#
|
62
|
+
# module Baz
|
63
|
+
# # ...
|
64
|
+
# end
|
65
|
+
#
|
66
|
+
# # bad
|
67
|
+
# module Baz
|
68
|
+
# # ...
|
69
|
+
# end
|
70
|
+
#
|
71
|
+
# # good
|
72
|
+
# # frozen_string_literal: true
|
73
|
+
#
|
74
|
+
# module Bar
|
75
|
+
# # ...
|
76
|
+
# end
|
54
77
|
class FrozenStringLiteralComment < Cop
|
55
78
|
include ConfigurableEnforcedStyle
|
56
79
|
include FrozenStringLiteral
|
57
80
|
include RangeHelp
|
58
81
|
|
59
|
-
|
82
|
+
MSG_MISSING_TRUE = 'Missing magic comment `# frozen_string_literal: '\
|
83
|
+
'true`.'
|
84
|
+
MSG_MISSING = 'Missing frozen string literal comment.'
|
60
85
|
MSG_UNNECESSARY = 'Unnecessary frozen string literal comment.'
|
86
|
+
MSG_DISABLED = 'Frozen string literal comment must be set to `true`.'
|
61
87
|
SHEBANG = '#!'
|
62
88
|
|
63
89
|
def investigate(processed_source)
|
64
90
|
return if processed_source.tokens.empty?
|
65
91
|
|
66
|
-
|
67
|
-
|
92
|
+
case style
|
93
|
+
when :never
|
94
|
+
ensure_no_comment(processed_source)
|
95
|
+
when :always_true
|
96
|
+
ensure_enabled_comment(processed_source)
|
68
97
|
else
|
69
|
-
|
98
|
+
ensure_comment(processed_source)
|
70
99
|
end
|
71
100
|
end
|
72
101
|
|
73
102
|
def autocorrect(node)
|
74
103
|
lambda do |corrector|
|
75
|
-
|
104
|
+
case style
|
105
|
+
when :never
|
76
106
|
remove_comment(corrector, node)
|
107
|
+
when :always_true
|
108
|
+
if frozen_string_literal_specified?
|
109
|
+
enable_comment(corrector)
|
110
|
+
else
|
111
|
+
insert_comment(corrector)
|
112
|
+
end
|
77
113
|
else
|
78
114
|
insert_comment(corrector)
|
79
115
|
end
|
@@ -82,12 +118,27 @@ module RuboCop
|
|
82
118
|
|
83
119
|
private
|
84
120
|
|
85
|
-
def
|
86
|
-
|
121
|
+
def ensure_no_comment(processed_source)
|
122
|
+
return unless frozen_string_literal_comment_exists?
|
123
|
+
|
124
|
+
unnecessary_comment_offense(processed_source)
|
87
125
|
end
|
88
126
|
|
89
|
-
def
|
90
|
-
|
127
|
+
def ensure_comment(processed_source)
|
128
|
+
return if frozen_string_literal_comment_exists?
|
129
|
+
|
130
|
+
missing_offense(processed_source)
|
131
|
+
end
|
132
|
+
|
133
|
+
def ensure_enabled_comment(processed_source)
|
134
|
+
if frozen_string_literal_specified?
|
135
|
+
return if frozen_string_literals_enabled?
|
136
|
+
|
137
|
+
# The comment exists, but is not enabled.
|
138
|
+
disabled_offense(processed_source)
|
139
|
+
else # The comment doesn't exist at all.
|
140
|
+
missing_true_offense(processed_source)
|
141
|
+
end
|
91
142
|
end
|
92
143
|
|
93
144
|
def last_special_comment(processed_source)
|
@@ -111,11 +162,22 @@ module RuboCop
|
|
111
162
|
end
|
112
163
|
end
|
113
164
|
|
114
|
-
def
|
165
|
+
def missing_offense(processed_source)
|
166
|
+
last_special_comment = last_special_comment(processed_source)
|
167
|
+
range = source_range(processed_source.buffer, 0, 0)
|
168
|
+
|
169
|
+
add_offense(last_special_comment,
|
170
|
+
location: range,
|
171
|
+
message: MSG_MISSING)
|
172
|
+
end
|
173
|
+
|
174
|
+
def missing_true_offense(processed_source)
|
115
175
|
last_special_comment = last_special_comment(processed_source)
|
116
176
|
range = source_range(processed_source.buffer, 0, 0)
|
117
177
|
|
118
|
-
add_offense(last_special_comment,
|
178
|
+
add_offense(last_special_comment,
|
179
|
+
location: range,
|
180
|
+
message: MSG_MISSING_TRUE)
|
119
181
|
end
|
120
182
|
|
121
183
|
def unnecessary_comment_offense(processed_source)
|
@@ -127,11 +189,27 @@ module RuboCop
|
|
127
189
|
message: MSG_UNNECESSARY)
|
128
190
|
end
|
129
191
|
|
192
|
+
def disabled_offense(processed_source)
|
193
|
+
frozen_string_literal_comment =
|
194
|
+
frozen_string_literal_comment(processed_source)
|
195
|
+
|
196
|
+
add_offense(frozen_string_literal_comment,
|
197
|
+
location: frozen_string_literal_comment.pos,
|
198
|
+
message: MSG_DISABLED)
|
199
|
+
end
|
200
|
+
|
130
201
|
def remove_comment(corrector, node)
|
131
202
|
corrector.remove(range_with_surrounding_space(range: node.pos,
|
132
203
|
side: :right))
|
133
204
|
end
|
134
205
|
|
206
|
+
def enable_comment(corrector)
|
207
|
+
comment = frozen_string_literal_comment(processed_source)
|
208
|
+
|
209
|
+
corrector.replace(line_range(comment.line),
|
210
|
+
FROZEN_STRING_LITERAL_ENABLED)
|
211
|
+
end
|
212
|
+
|
135
213
|
def insert_comment(corrector)
|
136
214
|
comment = last_special_comment(processed_source)
|
137
215
|
|
@@ -0,0 +1,87 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Style
|
6
|
+
# This cop checks for uses of `each_key` and `each_value` Hash methods.
|
7
|
+
#
|
8
|
+
# Note: If you have an array of two-element arrays, you can put
|
9
|
+
# parentheses around the block arguments to indicate that you're not
|
10
|
+
# working with a hash, and suppress RuboCop offenses.
|
11
|
+
#
|
12
|
+
# @example
|
13
|
+
# # bad
|
14
|
+
# hash.keys.each { |k| p k }
|
15
|
+
# hash.values.each { |v| p v }
|
16
|
+
#
|
17
|
+
# # good
|
18
|
+
# hash.each_key { |k| p k }
|
19
|
+
# hash.each_value { |v| p v }
|
20
|
+
class HashEachMethods < Cop
|
21
|
+
include Lint::UnusedArgument
|
22
|
+
|
23
|
+
MSG = 'Use `%<prefer>s` instead of `%<current>s`.'
|
24
|
+
|
25
|
+
def_node_matcher :kv_each, <<~PATTERN
|
26
|
+
(block $(send (send _ ${:keys :values}) :each) ...)
|
27
|
+
PATTERN
|
28
|
+
|
29
|
+
def on_block(node)
|
30
|
+
register_kv_offense(node)
|
31
|
+
end
|
32
|
+
|
33
|
+
def autocorrect(node)
|
34
|
+
lambda do |corrector|
|
35
|
+
correct_key_value_each(node, corrector)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
def register_kv_offense(node)
|
42
|
+
kv_each(node) do |target, method|
|
43
|
+
msg = format(message, prefer: "each_#{method[0..-2]}",
|
44
|
+
current: "#{method}.each")
|
45
|
+
|
46
|
+
add_offense(target, location: kv_range(target), message: msg)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def check_argument(variable)
|
51
|
+
return unless variable.block_argument?
|
52
|
+
|
53
|
+
(@block_args ||= []).push(variable)
|
54
|
+
end
|
55
|
+
|
56
|
+
def used?(arg)
|
57
|
+
@block_args.find { |var| var.declaration_node.loc == arg.loc }.used?
|
58
|
+
end
|
59
|
+
|
60
|
+
def correct_implicit(node, corrector, method_name)
|
61
|
+
corrector.replace(node.loc.expression, method_name)
|
62
|
+
correct_args(node, corrector)
|
63
|
+
end
|
64
|
+
|
65
|
+
def correct_key_value_each(node, corrector)
|
66
|
+
receiver = node.receiver.receiver
|
67
|
+
name = "each_#{node.receiver.method_name.to_s.chop}"
|
68
|
+
return correct_implicit(node, corrector, name) unless receiver
|
69
|
+
|
70
|
+
new_source = receiver.source + ".#{name}"
|
71
|
+
corrector.replace(node.loc.expression, new_source)
|
72
|
+
end
|
73
|
+
|
74
|
+
def correct_args(node, corrector)
|
75
|
+
args = node.parent.arguments
|
76
|
+
name, = *args.children.find { |arg| used?(arg) }
|
77
|
+
|
78
|
+
corrector.replace(args.source_range, "|#{name}|")
|
79
|
+
end
|
80
|
+
|
81
|
+
def kv_range(outer_node)
|
82
|
+
outer_node.receiver.loc.selector.join(outer_node.loc.selector)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Style
|
6
|
+
# This cop looks for uses of `_.each_with_object({}) {...}`,
|
7
|
+
# `_.map {...}.to_h`, and `Hash[_.map {...}]` that are actually just
|
8
|
+
# transforming the keys of a hash, and tries to use a simpler & faster
|
9
|
+
# call to `transform_keys` instead.
|
10
|
+
#
|
11
|
+
# This can produce false positives if we are transforming an enumerable
|
12
|
+
# of key-value-like pairs that isn't actually a hash, e.g.:
|
13
|
+
# `[[k1, v1], [k2, v2], ...]`
|
14
|
+
#
|
15
|
+
# This cop should only be enabled on Ruby version 2.5 or newer
|
16
|
+
# (`transform_keys` was added in Ruby 2.5.)
|
17
|
+
#
|
18
|
+
# @example
|
19
|
+
# # bad
|
20
|
+
# {a: 1, b: 2}.each_with_object({}) { |(k, v), h| h[foo(k)] = v }
|
21
|
+
# {a: 1, b: 2}.map { |k, v| [k.to_s, v] }
|
22
|
+
#
|
23
|
+
# # good
|
24
|
+
# {a: 1, b: 2}.transform_keys { |k| foo(k) }
|
25
|
+
# {a: 1, b: 2}.transform_keys { |k| k.to_s }
|
26
|
+
class HashTransformKeys < Cop
|
27
|
+
extend TargetRubyVersion
|
28
|
+
include HashTransformMethod
|
29
|
+
|
30
|
+
minimum_target_ruby_version 2.5
|
31
|
+
|
32
|
+
def_node_matcher :on_bad_each_with_object, <<~PATTERN
|
33
|
+
(block
|
34
|
+
({send csend} !(send _ :each_with_index) :each_with_object (hash))
|
35
|
+
(args
|
36
|
+
(mlhs
|
37
|
+
(arg $_)
|
38
|
+
(arg _val))
|
39
|
+
(arg _memo))
|
40
|
+
({send csend} (lvar _memo) :[]= $_ $(lvar _val)))
|
41
|
+
PATTERN
|
42
|
+
|
43
|
+
def_node_matcher :on_bad_hash_brackets_map, <<~PATTERN
|
44
|
+
(send
|
45
|
+
(const _ :Hash)
|
46
|
+
:[]
|
47
|
+
(block
|
48
|
+
({send csend} !(send _ :each_with_index) {:map :collect})
|
49
|
+
(args
|
50
|
+
(arg $_)
|
51
|
+
(arg _val))
|
52
|
+
(array $_ $(lvar _val))))
|
53
|
+
PATTERN
|
54
|
+
|
55
|
+
def_node_matcher :on_bad_map_to_h, <<~PATTERN
|
56
|
+
({send csend}
|
57
|
+
(block
|
58
|
+
({send csend} !(send _ :each_with_index) {:map :collect})
|
59
|
+
(args
|
60
|
+
(arg $_)
|
61
|
+
(arg _val))
|
62
|
+
(array $_ $(lvar _val)))
|
63
|
+
:to_h)
|
64
|
+
PATTERN
|
65
|
+
|
66
|
+
private
|
67
|
+
|
68
|
+
def extract_captures(match)
|
69
|
+
key_argname, key_body_expr, val_body_expr = *match
|
70
|
+
Captures.new(key_argname, key_body_expr, val_body_expr)
|
71
|
+
end
|
72
|
+
|
73
|
+
def new_method_name
|
74
|
+
'transform_keys'
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Style
|
6
|
+
# This cop looks for uses of `_.each_with_object({}) {...}`,
|
7
|
+
# `_.map {...}.to_h`, and `Hash[_.map {...}]` that are actually just
|
8
|
+
# transforming the values of a hash, and tries to use a simpler & faster
|
9
|
+
# call to `transform_values` instead.
|
10
|
+
#
|
11
|
+
# This can produce false positives if we are transforming an enumerable
|
12
|
+
# of key-value-like pairs that isn't actually a hash, e.g.:
|
13
|
+
# `[[k1, v1], [k2, v2], ...]`
|
14
|
+
#
|
15
|
+
# This cop should only be enabled on Ruby version 2.4 or newer
|
16
|
+
# (`transform_values` was added in Ruby 2.4.)
|
17
|
+
#
|
18
|
+
# @example
|
19
|
+
# # bad
|
20
|
+
# {a: 1, b: 2}.each_with_object({}) { |(k, v), h| h[k] = foo(v) }
|
21
|
+
# {a: 1, b: 2}.map { |k, v| [k, v * v] }
|
22
|
+
#
|
23
|
+
# # good
|
24
|
+
# {a: 1, b: 2}.transform_values { |v| foo(v) }
|
25
|
+
# {a: 1, b: 2}.transform_values { |v| v * v }
|
26
|
+
class HashTransformValues < Cop
|
27
|
+
extend TargetRubyVersion
|
28
|
+
include HashTransformMethod
|
29
|
+
|
30
|
+
minimum_target_ruby_version 2.4
|
31
|
+
|
32
|
+
def_node_matcher :on_bad_each_with_object, <<~PATTERN
|
33
|
+
(block
|
34
|
+
({send csend} !(send _ :each_with_index) :each_with_object (hash))
|
35
|
+
(args
|
36
|
+
(mlhs
|
37
|
+
(arg _key)
|
38
|
+
(arg $_))
|
39
|
+
(arg _memo))
|
40
|
+
({send csend} (lvar _memo) :[]= $(lvar _key) $_))
|
41
|
+
PATTERN
|
42
|
+
|
43
|
+
def_node_matcher :on_bad_hash_brackets_map, <<~PATTERN
|
44
|
+
(send
|
45
|
+
(const _ :Hash)
|
46
|
+
:[]
|
47
|
+
(block
|
48
|
+
({send csend} !(send _ :each_with_index) {:map :collect})
|
49
|
+
(args
|
50
|
+
(arg _key)
|
51
|
+
(arg $_))
|
52
|
+
(array $(lvar _key) $_)))
|
53
|
+
PATTERN
|
54
|
+
|
55
|
+
def_node_matcher :on_bad_map_to_h, <<~PATTERN
|
56
|
+
({send csend}
|
57
|
+
(block
|
58
|
+
({send csend} !(send _ :each_with_index) {:map :collect})
|
59
|
+
(args
|
60
|
+
(arg _key)
|
61
|
+
(arg $_))
|
62
|
+
(array $(lvar _key) $_))
|
63
|
+
:to_h)
|
64
|
+
PATTERN
|
65
|
+
|
66
|
+
private
|
67
|
+
|
68
|
+
def extract_captures(match)
|
69
|
+
val_argname, key_body_expr, val_body_expr = *match
|
70
|
+
Captures.new(val_argname, val_body_expr, key_body_expr)
|
71
|
+
end
|
72
|
+
|
73
|
+
def new_method_name
|
74
|
+
'transform_values'
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
@@ -150,6 +150,8 @@ module RuboCop
|
|
150
150
|
|
151
151
|
def initialize(*)
|
152
152
|
super
|
153
|
+
return unless style_configured?
|
154
|
+
|
153
155
|
case style
|
154
156
|
when :require_parentheses
|
155
157
|
extend RequireParentheses
|
@@ -158,6 +160,9 @@ module RuboCop
|
|
158
160
|
end
|
159
161
|
end
|
160
162
|
|
163
|
+
# @abstract Overridden in style modules
|
164
|
+
def autocorrect(_node); end
|
165
|
+
|
161
166
|
private
|
162
167
|
|
163
168
|
def args_begin(node)
|
@@ -74,10 +74,11 @@ module RuboCop
|
|
74
74
|
end
|
75
75
|
|
76
76
|
def call_in_logical_operators?(node)
|
77
|
-
node.parent
|
78
|
-
|
79
|
-
|
80
|
-
|
77
|
+
parent = node.parent&.block_type? ? node.parent.parent : node.parent
|
78
|
+
parent &&
|
79
|
+
(logical_operator?(parent) ||
|
80
|
+
parent.send_type? &&
|
81
|
+
parent.arguments.any?(&method(:logical_operator?)))
|
81
82
|
end
|
82
83
|
|
83
84
|
def call_in_optional_arguments?(node)
|
@@ -34,7 +34,7 @@ module RuboCop
|
|
34
34
|
(if
|
35
35
|
({lvar ivar cvar gvar} _var)
|
36
36
|
({lvar ivar cvar gvar} _var)
|
37
|
-
_))
|
37
|
+
$_))
|
38
38
|
PATTERN
|
39
39
|
|
40
40
|
def_node_matcher :unless_assignment?, <<~PATTERN
|
@@ -51,7 +51,8 @@ module RuboCop
|
|
51
51
|
end
|
52
52
|
|
53
53
|
def on_lvasgn(node)
|
54
|
-
return unless ternary_assignment?(node)
|
54
|
+
return unless (else_branch = ternary_assignment?(node))
|
55
|
+
return if else_branch.if_type?
|
55
56
|
|
56
57
|
add_offense(node)
|
57
58
|
end
|