rubocop 0.79.0 → 0.80.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/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
|