rubocop 0.70.0 → 0.72.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (102) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +5 -10
  3. data/config/default.yml +50 -491
  4. data/lib/rubocop.rb +5 -53
  5. data/lib/rubocop/ast/builder.rb +2 -0
  6. data/lib/rubocop/ast/node.rb +1 -1
  7. data/lib/rubocop/ast/node/float_node.rb +12 -0
  8. data/lib/rubocop/ast/node/int_node.rb +12 -0
  9. data/lib/rubocop/ast/node/mixin/numeric_node.rb +21 -0
  10. data/lib/rubocop/ast/node/resbody_node.rb +1 -6
  11. data/lib/rubocop/cached_data.rb +1 -1
  12. data/lib/rubocop/config.rb +35 -6
  13. data/lib/rubocop/config_loader.rb +2 -2
  14. data/lib/rubocop/config_loader_resolver.rb +0 -6
  15. data/lib/rubocop/cop/cop.rb +0 -4
  16. data/lib/rubocop/cop/gemspec/ruby_version_globals_usage.rb +55 -0
  17. data/lib/rubocop/cop/layout/class_structure.rb +1 -1
  18. data/lib/rubocop/cop/layout/empty_lines_around_block_body.rb +3 -1
  19. data/lib/rubocop/cop/layout/heredoc_argument_closing_parenthesis.rb +4 -0
  20. data/lib/rubocop/cop/layout/indent_first_argument.rb +6 -2
  21. data/lib/rubocop/cop/layout/indent_first_parameter.rb +7 -3
  22. data/lib/rubocop/cop/layout/indent_heredoc.rb +0 -1
  23. data/lib/rubocop/cop/layout/indentation_consistency.rb +13 -12
  24. data/lib/rubocop/cop/layout/indentation_width.rb +8 -4
  25. data/lib/rubocop/cop/layout/multiline_method_argument_line_breaks.rb +2 -0
  26. data/lib/rubocop/cop/lint/number_conversion.rb +1 -1
  27. data/lib/rubocop/cop/mixin/hash_alignment.rb +4 -0
  28. data/lib/rubocop/cop/naming/rescued_exceptions_variable_name.rb +20 -22
  29. data/lib/rubocop/cop/style/commented_keyword.rb +1 -1
  30. data/lib/rubocop/cop/style/conditional_assignment.rb +2 -1
  31. data/lib/rubocop/cop/style/float_division.rb +94 -0
  32. data/lib/rubocop/cop/style/format_string.rb +7 -3
  33. data/lib/rubocop/cop/style/if_inside_else.rb +42 -0
  34. data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +7 -1
  35. data/lib/rubocop/cop/style/safe_navigation.rb +1 -1
  36. data/lib/rubocop/cop/style/ternary_parentheses.rb +12 -2
  37. data/lib/rubocop/cop/style/trailing_comma_in_arguments.rb +4 -0
  38. data/lib/rubocop/cop/style/word_array.rb +2 -2
  39. data/lib/rubocop/cop/style/zero_length_predicate.rb +1 -1
  40. data/lib/rubocop/node_pattern.rb +84 -5
  41. data/lib/rubocop/options.rb +0 -2
  42. data/lib/rubocop/processed_source.rb +5 -1
  43. data/lib/rubocop/rspec/cop_helper.rb +0 -1
  44. data/lib/rubocop/rspec/shared_contexts.rb +0 -17
  45. data/lib/rubocop/rspec/support.rb +0 -1
  46. data/lib/rubocop/runner.rb +6 -7
  47. data/lib/rubocop/version.rb +1 -1
  48. data/lib/rubocop/yaml_duplication_checker.rb +8 -2
  49. metadata +7 -69
  50. data/lib/rubocop/cop/mixin/target_rails_version.rb +0 -16
  51. data/lib/rubocop/cop/rails/action_filter.rb +0 -117
  52. data/lib/rubocop/cop/rails/active_record_aliases.rb +0 -48
  53. data/lib/rubocop/cop/rails/active_record_override.rb +0 -82
  54. data/lib/rubocop/cop/rails/active_support_aliases.rb +0 -69
  55. data/lib/rubocop/cop/rails/application_job.rb +0 -40
  56. data/lib/rubocop/cop/rails/application_record.rb +0 -40
  57. data/lib/rubocop/cop/rails/assert_not.rb +0 -44
  58. data/lib/rubocop/cop/rails/belongs_to.rb +0 -102
  59. data/lib/rubocop/cop/rails/blank.rb +0 -164
  60. data/lib/rubocop/cop/rails/bulk_change_table.rb +0 -289
  61. data/lib/rubocop/cop/rails/create_table_with_timestamps.rb +0 -91
  62. data/lib/rubocop/cop/rails/date.rb +0 -161
  63. data/lib/rubocop/cop/rails/delegate.rb +0 -132
  64. data/lib/rubocop/cop/rails/delegate_allow_blank.rb +0 -37
  65. data/lib/rubocop/cop/rails/dynamic_find_by.rb +0 -91
  66. data/lib/rubocop/cop/rails/enum_uniqueness.rb +0 -45
  67. data/lib/rubocop/cop/rails/environment_comparison.rb +0 -68
  68. data/lib/rubocop/cop/rails/exit.rb +0 -67
  69. data/lib/rubocop/cop/rails/file_path.rb +0 -108
  70. data/lib/rubocop/cop/rails/find_by.rb +0 -55
  71. data/lib/rubocop/cop/rails/find_each.rb +0 -51
  72. data/lib/rubocop/cop/rails/has_and_belongs_to_many.rb +0 -25
  73. data/lib/rubocop/cop/rails/has_many_or_has_one_dependent.rb +0 -106
  74. data/lib/rubocop/cop/rails/http_positional_arguments.rb +0 -117
  75. data/lib/rubocop/cop/rails/http_status.rb +0 -179
  76. data/lib/rubocop/cop/rails/ignored_skip_action_filter_option.rb +0 -94
  77. data/lib/rubocop/cop/rails/inverse_of.rb +0 -246
  78. data/lib/rubocop/cop/rails/lexically_scoped_action_filter.rb +0 -175
  79. data/lib/rubocop/cop/rails/link_to_blank.rb +0 -98
  80. data/lib/rubocop/cop/rails/not_null_column.rb +0 -67
  81. data/lib/rubocop/cop/rails/output.rb +0 -49
  82. data/lib/rubocop/cop/rails/output_safety.rb +0 -99
  83. data/lib/rubocop/cop/rails/pluralization_grammar.rb +0 -107
  84. data/lib/rubocop/cop/rails/presence.rb +0 -124
  85. data/lib/rubocop/cop/rails/present.rb +0 -153
  86. data/lib/rubocop/cop/rails/read_write_attribute.rb +0 -74
  87. data/lib/rubocop/cop/rails/redundant_allow_nil.rb +0 -111
  88. data/lib/rubocop/cop/rails/redundant_receiver_in_with_options.rb +0 -136
  89. data/lib/rubocop/cop/rails/reflection_class_name.rb +0 -37
  90. data/lib/rubocop/cop/rails/refute_methods.rb +0 -76
  91. data/lib/rubocop/cop/rails/relative_date_constant.rb +0 -93
  92. data/lib/rubocop/cop/rails/request_referer.rb +0 -56
  93. data/lib/rubocop/cop/rails/reversible_migration.rb +0 -286
  94. data/lib/rubocop/cop/rails/safe_navigation.rb +0 -87
  95. data/lib/rubocop/cop/rails/save_bang.rb +0 -316
  96. data/lib/rubocop/cop/rails/scope_args.rb +0 -29
  97. data/lib/rubocop/cop/rails/skips_model_validations.rb +0 -87
  98. data/lib/rubocop/cop/rails/time_zone.rb +0 -238
  99. data/lib/rubocop/cop/rails/uniq_before_pluck.rb +0 -105
  100. data/lib/rubocop/cop/rails/unknown_env.rb +0 -63
  101. data/lib/rubocop/cop/rails/validation.rb +0 -109
  102. data/lib/rubocop/rspec/shared_examples.rb +0 -59
@@ -1,87 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module RuboCop
4
- module Cop
5
- module Rails
6
- # This cop converts usages of `try!` to `&.`. It can also be configured
7
- # to convert `try`. It will convert code to use safe navigation.
8
- #
9
- # @example
10
- # # ConvertTry: false
11
- # # bad
12
- # foo.try!(:bar)
13
- # foo.try!(:bar, baz)
14
- # foo.try!(:bar) { |e| e.baz }
15
- #
16
- # foo.try!(:[], 0)
17
- #
18
- # # good
19
- # foo.try(:bar)
20
- # foo.try(:bar, baz)
21
- # foo.try(:bar) { |e| e.baz }
22
- #
23
- # foo&.bar
24
- # foo&.bar(baz)
25
- # foo&.bar { |e| e.baz }
26
- #
27
- #
28
- # # ConvertTry: true
29
- # # bad
30
- # foo.try!(:bar)
31
- # foo.try!(:bar, baz)
32
- # foo.try!(:bar) { |e| e.baz }
33
- # foo.try(:bar)
34
- # foo.try(:bar, baz)
35
- # foo.try(:bar) { |e| e.baz }
36
- #
37
- # # good
38
- # foo&.bar
39
- # foo&.bar(baz)
40
- # foo&.bar { |e| e.baz }
41
- class SafeNavigation < Cop
42
- include RangeHelp
43
-
44
- MSG = 'Use safe navigation (`&.`) instead of `%<try>s`.'
45
-
46
- def_node_matcher :try_call, <<-PATTERN
47
- (send !nil? ${:try :try!} $_ ...)
48
- PATTERN
49
-
50
- def on_send(node)
51
- try_call(node) do |try_method, dispatch|
52
- return if try_method == :try && !cop_config['ConvertTry']
53
- return unless dispatch.sym_type? && dispatch.value =~ /\w+[=!?]?/
54
-
55
- add_offense(node, message: format(MSG, try: try_method))
56
- end
57
- end
58
-
59
- def autocorrect(node)
60
- method_node, *params = *node.arguments
61
- method = method_node.source[1..-1]
62
-
63
- range = range_between(node.loc.dot.begin_pos,
64
- node.loc.expression.end_pos)
65
-
66
- lambda do |corrector|
67
- corrector.replace(range, replacement(method, params))
68
- end
69
- end
70
-
71
- private
72
-
73
- def replacement(method, params)
74
- new_params = params.map(&:source).join(', ')
75
-
76
- if method.end_with?('=')
77
- "&.#{method[0...-1]} = #{new_params}"
78
- elsif params.empty?
79
- "&.#{method}"
80
- else
81
- "&.#{method}(#{new_params})"
82
- end
83
- end
84
- end
85
- end
86
- end
87
- end
@@ -1,316 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module RuboCop
4
- module Cop
5
- module Rails
6
- # This cop identifies possible cases where Active Record save! or related
7
- # should be used instead of save because the model might have failed to
8
- # save and an exception is better than unhandled failure.
9
- #
10
- # This will allow:
11
- # - update or save calls, assigned to a variable,
12
- # or used as a condition in an if/unless/case statement.
13
- # - create calls, assigned to a variable that then has a
14
- # call to `persisted?`.
15
- # - calls if the result is explicitly returned from methods and blocks,
16
- # or provided as arguments.
17
- # - calls whose signature doesn't look like an ActiveRecord
18
- # persistence method.
19
- #
20
- # By default it will also allow implicit returns from methods and blocks.
21
- # that behavior can be turned off with `AllowImplicitReturn: false`.
22
- #
23
- # You can permit receivers that are giving false positives with
24
- # `AllowedReceivers: []`
25
- #
26
- # @example
27
- #
28
- # # bad
29
- # user.save
30
- # user.update(name: 'Joe')
31
- # user.find_or_create_by(name: 'Joe')
32
- # user.destroy
33
- #
34
- # # good
35
- # unless user.save
36
- # # ...
37
- # end
38
- # user.save!
39
- # user.update!(name: 'Joe')
40
- # user.find_or_create_by!(name: 'Joe')
41
- # user.destroy!
42
- #
43
- # user = User.find_or_create_by(name: 'Joe')
44
- # unless user.persisted?
45
- # # ...
46
- # end
47
- #
48
- # def save_user
49
- # return user.save
50
- # end
51
- #
52
- # @example AllowImplicitReturn: true (default)
53
- #
54
- # # good
55
- # users.each { |u| u.save }
56
- #
57
- # def save_user
58
- # user.save
59
- # end
60
- #
61
- # @example AllowImplicitReturn: false
62
- #
63
- # # bad
64
- # users.each { |u| u.save }
65
- # def save_user
66
- # user.save
67
- # end
68
- #
69
- # # good
70
- # users.each { |u| u.save! }
71
- #
72
- # def save_user
73
- # user.save!
74
- # end
75
- #
76
- # def save_user
77
- # return user.save
78
- # end
79
- #
80
- # @example AllowedReceivers: ['merchant.customers', 'Service::Mailer']
81
- #
82
- # # bad
83
- # merchant.create
84
- # customers.builder.save
85
- # Mailer.create
86
- #
87
- # module Service::Mailer
88
- # self.create
89
- # end
90
- #
91
- # # good
92
- # merchant.customers.create
93
- # MerchantService.merchant.customers.destroy
94
- # Service::Mailer.update(message: 'Message')
95
- # ::Service::Mailer.update
96
- # Services::Service::Mailer.update(message: 'Message')
97
- # Service::Mailer::update
98
- #
99
- class SaveBang < Cop
100
- include NegativeConditional
101
-
102
- MSG = 'Use `%<prefer>s` instead of `%<current>s` if the return ' \
103
- 'value is not checked.'
104
- CREATE_MSG = (MSG +
105
- ' Or check `persisted?` on model returned from ' \
106
- '`%<current>s`.').freeze
107
- CREATE_CONDITIONAL_MSG = '`%<current>s` returns a model which is ' \
108
- 'always truthy.'
109
-
110
- CREATE_PERSIST_METHODS = %i[create
111
- first_or_create find_or_create_by].freeze
112
- MODIFY_PERSIST_METHODS = %i[save
113
- update update_attributes destroy].freeze
114
- PERSIST_METHODS = (CREATE_PERSIST_METHODS +
115
- MODIFY_PERSIST_METHODS).freeze
116
-
117
- def join_force?(force_class)
118
- force_class == VariableForce
119
- end
120
-
121
- def after_leaving_scope(scope, _variable_table)
122
- scope.variables.each_value do |variable|
123
- variable.assignments.each do |assignment|
124
- check_assignment(assignment)
125
- end
126
- end
127
- end
128
-
129
- def check_assignment(assignment)
130
- node = right_assignment_node(assignment)
131
-
132
- return unless node&.send_type?
133
- return unless persist_method?(node, CREATE_PERSIST_METHODS)
134
- return if persisted_referenced?(assignment)
135
-
136
- add_offense_for_node(node, CREATE_MSG)
137
- end
138
-
139
- def on_send(node) # rubocop:disable Metrics/CyclomaticComplexity
140
- return unless persist_method?(node)
141
- return if return_value_assigned?(node)
142
- return if check_used_in_conditional(node)
143
- return if argument?(node)
144
- return if implicit_return?(node)
145
- return if explicit_return?(node)
146
-
147
- add_offense_for_node(node)
148
- end
149
- alias on_csend on_send
150
-
151
- def autocorrect(node)
152
- save_loc = node.loc.selector
153
- new_method = "#{node.method_name}!"
154
-
155
- ->(corrector) { corrector.replace(save_loc, new_method) }
156
- end
157
-
158
- private
159
-
160
- def add_offense_for_node(node, msg = MSG)
161
- name = node.method_name
162
- full_message = format(msg, prefer: "#{name}!", current: name.to_s)
163
-
164
- add_offense(node, location: :selector, message: full_message)
165
- end
166
-
167
- def right_assignment_node(assignment)
168
- node = assignment.node.child_nodes.first
169
-
170
- return node unless node&.block_type?
171
-
172
- node.send_node
173
- end
174
-
175
- def persisted_referenced?(assignment)
176
- return unless assignment.referenced?
177
-
178
- assignment.variable.references.any? do |reference|
179
- call_to_persisted?(reference.node.parent)
180
- end
181
- end
182
-
183
- def call_to_persisted?(node)
184
- node.send_type? && node.method?(:persisted?)
185
- end
186
-
187
- def assignable_node(node)
188
- assignable = node.block_node || node
189
- while node
190
- node = hash_parent(node) || array_parent(node)
191
- assignable = node if node
192
- end
193
- assignable
194
- end
195
-
196
- def hash_parent(node)
197
- pair = node.parent
198
- return unless pair&.pair_type?
199
-
200
- hash = pair.parent
201
- return unless hash&.hash_type?
202
-
203
- hash
204
- end
205
-
206
- def array_parent(node)
207
- array = node.parent
208
- return unless array&.array_type?
209
-
210
- array
211
- end
212
-
213
- def check_used_in_conditional(node)
214
- return false unless conditional?(node)
215
-
216
- unless MODIFY_PERSIST_METHODS.include?(node.method_name)
217
- add_offense_for_node(node, CREATE_CONDITIONAL_MSG)
218
- end
219
-
220
- true
221
- end
222
-
223
- def conditional?(node) # rubocop:disable Metrics/CyclomaticComplexity
224
- node = node.block_node || node
225
-
226
- condition = node.parent
227
- return false unless condition
228
-
229
- condition.if_type? || condition.case_type? ||
230
- condition.or_type? || condition.and_type? ||
231
- single_negative?(condition)
232
- end
233
-
234
- def allowed_receiver?(node)
235
- return false unless node.receiver
236
- return false unless cop_config['AllowedReceivers']
237
-
238
- cop_config['AllowedReceivers'].any? do |allowed_receiver|
239
- receiver_chain_matches?(node, allowed_receiver)
240
- end
241
- end
242
-
243
- def receiver_chain_matches?(node, allowed_receiver)
244
- allowed_receiver.split('.').reverse.all? do |receiver_part|
245
- node = node.receiver
246
- return false unless node
247
-
248
- if node.variable?
249
- node.node_parts.first == receiver_part.to_sym
250
- elsif node.send_type?
251
- node.method_name == receiver_part.to_sym
252
- elsif node.const_type?
253
- const_matches?(node.const_name, receiver_part)
254
- end
255
- end
256
- end
257
-
258
- # Const == Const
259
- # ::Const == ::Const
260
- # ::Const == Const
261
- # Const == ::Const
262
- # NameSpace::Const == Const
263
- # NameSpace::Const == NameSpace::Const
264
- # NameSpace::Const != ::Const
265
- # Const != NameSpace::Const
266
- def const_matches?(const, allowed_const)
267
- parts = allowed_const.split('::').reverse.zip(
268
- const.split('::').reverse
269
- )
270
- parts.all? do |(allowed_part, const_part)|
271
- allowed_part == const_part.to_s
272
- end
273
- end
274
-
275
- def implicit_return?(node)
276
- return false unless cop_config['AllowImplicitReturn']
277
-
278
- node = assignable_node(node)
279
- method = node.parent
280
- return unless method && (method.def_type? || method.block_type?)
281
-
282
- method.children.size == node.sibling_index + 1
283
- end
284
-
285
- def argument?(node)
286
- assignable_node(node).argument?
287
- end
288
-
289
- def explicit_return?(node)
290
- ret = assignable_node(node).parent
291
- ret && (ret.return_type? || ret.next_type?)
292
- end
293
-
294
- def return_value_assigned?(node)
295
- assignment = assignable_node(node).parent
296
- assignment&.lvasgn_type?
297
- end
298
-
299
- def persist_method?(node, methods = PERSIST_METHODS)
300
- methods.include?(node.method_name) &&
301
- expected_signature?(node) &&
302
- !allowed_receiver?(node)
303
- end
304
-
305
- # Check argument signature as no arguments or one hash
306
- def expected_signature?(node)
307
- !node.arguments? ||
308
- (node.arguments.one? &&
309
- node.method_name != :destroy &&
310
- (node.first_argument.hash_type? ||
311
- !node.first_argument.literal?))
312
- end
313
- end
314
- end
315
- end
316
- end
@@ -1,29 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module RuboCop
4
- module Cop
5
- module Rails
6
- # This cop checks for scope calls where it was passed
7
- # a method (usually a scope) instead of a lambda/proc.
8
- #
9
- # @example
10
- #
11
- # # bad
12
- # scope :something, where(something: true)
13
- #
14
- # # good
15
- # scope :something, -> { where(something: true) }
16
- class ScopeArgs < Cop
17
- MSG = 'Use `lambda`/`proc` instead of a plain method call.'
18
-
19
- def_node_matcher :scope?, '(send nil? :scope _ $send)'
20
-
21
- def on_send(node)
22
- scope?(node) do |second_arg|
23
- add_offense(second_arg)
24
- end
25
- end
26
- end
27
- end
28
- end
29
- end
@@ -1,87 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module RuboCop
4
- module Cop
5
- module Rails
6
- # This cop checks for the use of methods which skip
7
- # validations which are listed in
8
- # https://guides.rubyonrails.org/active_record_validations.html#skipping-validations
9
- #
10
- # Methods may be ignored from this rule by configuring a `Whitelist`.
11
- #
12
- # @example
13
- # # bad
14
- # Article.first.decrement!(:view_count)
15
- # DiscussionBoard.decrement_counter(:post_count, 5)
16
- # Article.first.increment!(:view_count)
17
- # DiscussionBoard.increment_counter(:post_count, 5)
18
- # person.toggle :active
19
- # product.touch
20
- # Billing.update_all("category = 'authorized', author = 'David'")
21
- # user.update_attribute(:website, 'example.com')
22
- # user.update_columns(last_request_at: Time.current)
23
- # Post.update_counters 5, comment_count: -1, action_count: 1
24
- #
25
- # # good
26
- # user.update(website: 'example.com')
27
- # FileUtils.touch('file')
28
- #
29
- # @example Whitelist: ["touch"]
30
- # # bad
31
- # DiscussionBoard.decrement_counter(:post_count, 5)
32
- # DiscussionBoard.increment_counter(:post_count, 5)
33
- # person.toggle :active
34
- #
35
- # # good
36
- # user.touch
37
- #
38
- class SkipsModelValidations < Cop
39
- MSG = 'Avoid using `%<method>s` because it skips validations.'
40
-
41
- METHODS_WITH_ARGUMENTS = %w[decrement!
42
- decrement_counter
43
- increment!
44
- increment_counter
45
- toggle!
46
- update_all
47
- update_attribute
48
- update_column
49
- update_columns
50
- update_counters].freeze
51
-
52
- def_node_matcher :good_touch?, <<-PATTERN
53
- (send (const nil? :FileUtils) :touch ...)
54
- PATTERN
55
-
56
- def on_send(node)
57
- return if whitelist.include?(node.method_name.to_s)
58
- return unless blacklist.include?(node.method_name.to_s)
59
- return if allowed_method?(node)
60
- return if good_touch?(node)
61
-
62
- add_offense(node, location: :selector)
63
- end
64
- alias on_csend on_send
65
-
66
- private
67
-
68
- def message(node)
69
- format(MSG, method: node.method_name)
70
- end
71
-
72
- def allowed_method?(node)
73
- METHODS_WITH_ARGUMENTS.include?(node.method_name.to_s) &&
74
- !node.arguments?
75
- end
76
-
77
- def blacklist
78
- cop_config['Blacklist'] || []
79
- end
80
-
81
- def whitelist
82
- cop_config['Whitelist'] || []
83
- end
84
- end
85
- end
86
- end
87
- end