rubocop 0.79.0 → 0.80.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (44) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE.txt +1 -1
  3. data/README.md +3 -3
  4. data/config/default.yml +33 -19
  5. data/lib/rubocop.rb +5 -1
  6. data/lib/rubocop/ast/node.rb +0 -12
  7. data/lib/rubocop/ast/node/regexp_node.rb +2 -4
  8. data/lib/rubocop/ast/traversal.rb +9 -0
  9. data/lib/rubocop/comment_config.rb +6 -1
  10. data/lib/rubocop/config_obsoletion.rb +2 -1
  11. data/lib/rubocop/cop/layout/empty_line_between_defs.rb +2 -1
  12. data/lib/rubocop/cop/layout/leading_comment_space.rb +33 -2
  13. data/lib/rubocop/cop/layout/line_length.rb +30 -1
  14. data/lib/rubocop/cop/layout/multiline_hash_brace_layout.rb +0 -4
  15. data/lib/rubocop/cop/layout/space_around_operators.rb +18 -0
  16. data/lib/rubocop/cop/layout/space_before_first_arg.rb +8 -0
  17. data/lib/rubocop/cop/layout/space_inside_hash_literal_braces.rb +2 -9
  18. data/lib/rubocop/cop/lint/debugger.rb +1 -1
  19. data/lib/rubocop/cop/lint/redundant_cop_enable_directive.rb +12 -7
  20. data/lib/rubocop/cop/lint/useless_setter_call.rb +4 -0
  21. data/lib/rubocop/cop/migration/department_name.rb +14 -1
  22. data/lib/rubocop/cop/mixin/configurable_enforced_style.rb +4 -0
  23. data/lib/rubocop/cop/mixin/frozen_string_literal.rb +6 -0
  24. data/lib/rubocop/cop/mixin/hash_transform_method.rb +172 -0
  25. data/lib/rubocop/cop/mixin/trailing_comma.rb +2 -9
  26. data/lib/rubocop/cop/naming/memoized_instance_variable_name.rb +1 -1
  27. data/lib/rubocop/cop/style/block_delimiters.rb +60 -1
  28. data/lib/rubocop/cop/style/frozen_string_literal_comment.rb +89 -11
  29. data/lib/rubocop/cop/style/hash_each_methods.rb +87 -0
  30. data/lib/rubocop/cop/style/hash_transform_keys.rb +79 -0
  31. data/lib/rubocop/cop/style/hash_transform_values.rb +79 -0
  32. data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +5 -0
  33. data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +5 -4
  34. data/lib/rubocop/cop/style/or_assignment.rb +3 -2
  35. data/lib/rubocop/cop/style/symbol_array.rb +2 -2
  36. data/lib/rubocop/cop/style/ternary_parentheses.rb +1 -1
  37. data/lib/rubocop/cop/style/trailing_comma_in_arguments.rb +0 -22
  38. data/lib/rubocop/cop/variable_force.rb +4 -1
  39. data/lib/rubocop/formatter/formatter_set.rb +1 -0
  40. data/lib/rubocop/formatter/junit_formatter.rb +63 -0
  41. data/lib/rubocop/node_pattern.rb +96 -10
  42. data/lib/rubocop/version.rb +1 -1
  43. metadata +21 -3
  44. 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
- MSG = 'Missing magic comment `# frozen_string_literal: true`.'
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
- if frozen_string_literal_comment_exists?
67
- check_for_no_comment(processed_source)
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
- check_for_comment(processed_source)
98
+ ensure_comment(processed_source)
70
99
  end
71
100
  end
72
101
 
73
102
  def autocorrect(node)
74
103
  lambda do |corrector|
75
- if style == :never
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 check_for_no_comment(processed_source)
86
- unnecessary_comment_offense(processed_source) if style == :never
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 check_for_comment(processed_source)
90
- offense(processed_source) unless style == :never
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 offense(processed_source)
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, location: range)
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
- (logical_operator?(node.parent) ||
79
- node.parent.send_type? &&
80
- node.parent.arguments.any?(&method(:logical_operator?)))
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