rubocop-rails 2.15.2 → 2.16.1
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/config/default.yml +81 -0
- data/config/obsoletion.yml +10 -0
- data/lib/rubocop/cop/mixin/active_record_helper.rb +1 -4
- data/lib/rubocop/cop/mixin/active_record_migrations_helper.rb +1 -3
- data/lib/rubocop/cop/mixin/index_method.rb +5 -15
- data/lib/rubocop/cop/rails/action_controller_flash_before_render.rb +98 -0
- data/lib/rubocop/cop/rails/action_filter.rb +1 -1
- data/lib/rubocop/cop/rails/active_record_aliases.rb +1 -4
- data/lib/rubocop/cop/rails/active_record_override.rb +2 -5
- data/lib/rubocop/cop/rails/active_support_on_load.rb +70 -0
- data/lib/rubocop/cop/rails/add_column_index.rb +1 -4
- data/lib/rubocop/cop/rails/blank.rb +1 -2
- data/lib/rubocop/cop/rails/bulk_change_table.rb +6 -20
- data/lib/rubocop/cop/rails/compact_blank.rb +5 -1
- data/lib/rubocop/cop/rails/content_tag.rb +1 -3
- data/lib/rubocop/cop/rails/date.rb +4 -9
- data/lib/rubocop/cop/rails/delegate.rb +2 -5
- data/lib/rubocop/cop/rails/deprecated_active_model_errors_methods.rb +17 -13
- data/lib/rubocop/cop/rails/dot_separated_keys.rb +1 -1
- data/lib/rubocop/cop/rails/dynamic_find_by.rb +2 -4
- data/lib/rubocop/cop/rails/enum_uniqueness.rb +2 -5
- data/lib/rubocop/cop/rails/environment_comparison.rb +1 -2
- data/lib/rubocop/cop/rails/file_path.rb +2 -4
- data/lib/rubocop/cop/rails/find_each.rb +8 -2
- data/lib/rubocop/cop/rails/freeze_time.rb +74 -0
- data/lib/rubocop/cop/rails/has_many_or_has_one_dependent.rb +1 -3
- data/lib/rubocop/cop/rails/http_positional_arguments.rb +4 -9
- data/lib/rubocop/cop/rails/http_status.rb +5 -10
- data/lib/rubocop/cop/rails/ignored_skip_action_filter_option.rb +3 -10
- data/lib/rubocop/cop/rails/inverse_of.rb +3 -6
- data/lib/rubocop/cop/rails/lexically_scoped_action_filter.rb +2 -6
- data/lib/rubocop/cop/rails/link_to_blank.rb +1 -4
- data/lib/rubocop/cop/rails/output.rb +2 -5
- data/lib/rubocop/cop/rails/pluralization_grammar.rb +1 -2
- data/lib/rubocop/cop/rails/presence.rb +1 -3
- data/lib/rubocop/cop/rails/present.rb +3 -6
- data/lib/rubocop/cop/rails/rake_environment.rb +1 -1
- data/lib/rubocop/cop/rails/redundant_allow_nil.rb +2 -4
- data/lib/rubocop/cop/rails/redundant_foreign_key.rb +1 -1
- data/lib/rubocop/cop/rails/redundant_presence_validation_on_belongs_to.rb +2 -2
- data/lib/rubocop/cop/rails/redundant_receiver_in_with_options.rb +28 -26
- data/lib/rubocop/cop/rails/reflection_class_name.rb +17 -0
- data/lib/rubocop/cop/rails/refute_methods.rb +1 -5
- data/lib/rubocop/cop/rails/relative_date_constant.rb +2 -5
- data/lib/rubocop/cop/rails/request_referer.rb +1 -2
- data/lib/rubocop/cop/rails/reversible_migration.rb +10 -33
- data/lib/rubocop/cop/rails/reversible_migration_method_definition.rb +1 -2
- data/lib/rubocop/cop/rails/root_pathname_methods.rb +214 -0
- data/lib/rubocop/cop/rails/safe_navigation_with_blank.rb +1 -3
- data/lib/rubocop/cop/rails/save_bang.rb +10 -22
- data/lib/rubocop/cop/rails/short_i18n.rb +1 -4
- data/lib/rubocop/cop/rails/skips_model_validations.rb +1 -2
- data/lib/rubocop/cop/rails/squished_sql_heredocs.rb +1 -5
- data/lib/rubocop/cop/rails/time_zone.rb +8 -19
- data/lib/rubocop/cop/rails/to_s_with_argument.rb +41 -0
- data/lib/rubocop/cop/rails/top_level_hash_with_indifferent_access.rb +49 -0
- data/lib/rubocop/cop/rails/uniq_before_pluck.rb +3 -6
- data/lib/rubocop/cop/rails/unique_validation_without_index.rb +1 -3
- data/lib/rubocop/cop/rails/unknown_env.rb +2 -4
- data/lib/rubocop/cop/rails/validation.rb +4 -12
- data/lib/rubocop/cop/rails/where_missing.rb +111 -0
- data/lib/rubocop/cop/rails_cops.rb +7 -0
- data/lib/rubocop/rails/version.rb +1 -1
- metadata +13 -8
- data/bin/console +0 -11
- data/bin/setup +0 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 531a7f7b4bc04b877c25047dc10ee38e10804ad233b5b2abd425b613d508f0b5
|
4
|
+
data.tar.gz: 135eaa3b4ab1c2393f8ab72cd961470c713552d2d6300bd2ea0f981831ea5cba
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ab99c18ad7f0684d03945b48393cadecd20f465ade8f27a9876b874210e2b930300ce5b08d7e6b8d654595bca67ae321b6afef88c05843ddd79ff47cf1b80708
|
7
|
+
data.tar.gz: 879fd14dfff79cd8afe60e9f6678d66f61eefe8b91cdbe36c92cbb31541f6735b59d5dc33a8c21f8330dac60f359c4e46ad59f43b259d81ea25c366d3f26ca50
|
data/config/default.yml
CHANGED
@@ -10,6 +10,9 @@ AllCops:
|
|
10
10
|
# Exclude db/schema.rb and db/[CONFIGURATION_NAMESPACE]_schema.rb by default.
|
11
11
|
# See: https://guides.rubyonrails.org/active_record_multiple_databases.html#setting-up-your-application
|
12
12
|
- db/*schema.rb
|
13
|
+
# Enable checking Active Support extensions.
|
14
|
+
# See: https://docs.rubocop.org/rubocop/configuration.html#enable-checking-active-support-extensions
|
15
|
+
ActiveSupportExtensionsEnabled: true
|
13
16
|
# What version of Rails is the inspected code using? If a value is specified
|
14
17
|
# for TargetRailsVersion then it is used. Acceptable values are specified
|
15
18
|
# as a float (i.e. 5.1); the patch version of Rails should not be included.
|
@@ -23,6 +26,24 @@ Lint/NumberConversion:
|
|
23
26
|
# Add Rails' duration methods to the ignore list for `Lint/NumberConversion`
|
24
27
|
# so that calling `to_i` on one of these does not register an offense.
|
25
28
|
# See: https://github.com/rubocop/rubocop/issues/8950
|
29
|
+
AllowedMethods:
|
30
|
+
- ago
|
31
|
+
- from_now
|
32
|
+
- second
|
33
|
+
- seconds
|
34
|
+
- minute
|
35
|
+
- minutes
|
36
|
+
- hour
|
37
|
+
- hours
|
38
|
+
- day
|
39
|
+
- days
|
40
|
+
- week
|
41
|
+
- weeks
|
42
|
+
- fortnight
|
43
|
+
- fortnights
|
44
|
+
- in_milliseconds
|
45
|
+
AllowedPatterns: []
|
46
|
+
# Deprecated.
|
26
47
|
IgnoredMethods:
|
27
48
|
- ago
|
28
49
|
- from_now
|
@@ -40,6 +61,18 @@ Lint/NumberConversion:
|
|
40
61
|
- fortnights
|
41
62
|
- in_milliseconds
|
42
63
|
|
64
|
+
Rails:
|
65
|
+
Enabled: true
|
66
|
+
DocumentationBaseURL: https://docs.rubocop.org/rubocop-rails
|
67
|
+
|
68
|
+
Rails/ActionControllerFlashBeforeRender:
|
69
|
+
Description: 'Use `flash.now` instead of `flash` before `render`.'
|
70
|
+
StyleGuide: 'https://rails.rubystyle.guide/#flash-before-render'
|
71
|
+
Reference: 'https://api.rubyonrails.org/classes/ActionController/FlashBeforeRender.html'
|
72
|
+
Enabled: 'pending'
|
73
|
+
SafeAutocorrect: false
|
74
|
+
VersionAdded: '2.16'
|
75
|
+
|
43
76
|
Rails/ActionControllerTestCase:
|
44
77
|
Description: 'Use `ActionDispatch::IntegrationTest` instead of `ActionController::TestCase`.'
|
45
78
|
StyleGuide: 'https://rails.rubystyle.guide/#integration-testing'
|
@@ -96,6 +129,15 @@ Rails/ActiveSupportAliases:
|
|
96
129
|
Enabled: true
|
97
130
|
VersionAdded: '0.48'
|
98
131
|
|
132
|
+
Rails/ActiveSupportOnLoad:
|
133
|
+
Description: 'Use `ActiveSupport.on_load(...)` to patch Rails framework classes.'
|
134
|
+
Enabled: 'pending'
|
135
|
+
Reference:
|
136
|
+
- 'https://api.rubyonrails.org/classes/ActiveSupport/LazyLoadHooks.html'
|
137
|
+
- 'https://guides.rubyonrails.org/engines.html#available-load-hooks'
|
138
|
+
SafeAutoCorrect: false
|
139
|
+
VersionAdded: '2.16'
|
140
|
+
|
99
141
|
Rails/AddColumnIndex:
|
100
142
|
Description: >-
|
101
143
|
Rails migrations don't make use of a given `index` key, but also
|
@@ -407,6 +449,14 @@ Rails/FindEach:
|
|
407
449
|
VersionChanged: '2.9'
|
408
450
|
Include:
|
409
451
|
- app/models/**/*.rb
|
452
|
+
AllowedMethods:
|
453
|
+
# Methods that don't work well with `find_each`.
|
454
|
+
- order
|
455
|
+
- limit
|
456
|
+
- select
|
457
|
+
- lock
|
458
|
+
AllowedPatterns: []
|
459
|
+
# Deprecated.
|
410
460
|
IgnoredMethods:
|
411
461
|
# Methods that don't work well with `find_each`.
|
412
462
|
- order
|
@@ -414,6 +464,13 @@ Rails/FindEach:
|
|
414
464
|
- select
|
415
465
|
- lock
|
416
466
|
|
467
|
+
Rails/FreezeTime:
|
468
|
+
Description: 'Prefer `freeze_time` over `travel_to` with an argument of the current time.'
|
469
|
+
StyleGuide: 'https://rails.rubystyle.guide/#freeze-time'
|
470
|
+
Enabled: pending
|
471
|
+
VersionAdded: '2.16'
|
472
|
+
SafeAutoCorrect: false
|
473
|
+
|
417
474
|
Rails/HasAndBelongsToMany:
|
418
475
|
Description: 'Prefer has_many :through to has_and_belongs_to_many.'
|
419
476
|
StyleGuide: 'https://rails.rubystyle.guide#has-many-through'
|
@@ -785,6 +842,12 @@ Rails/RootJoinChain:
|
|
785
842
|
Enabled: pending
|
786
843
|
VersionAdded: '2.13'
|
787
844
|
|
845
|
+
Rails/RootPathnameMethods:
|
846
|
+
Description: 'Use `Rails.root` IO methods instead of passing it to `File`.'
|
847
|
+
Enabled: pending
|
848
|
+
SafeAutocorrect: false
|
849
|
+
VersionAdded: '2.16'
|
850
|
+
|
788
851
|
Rails/RootPublicPath:
|
789
852
|
Description: "Favor `Rails.public_path` over `Rails.root` with `'public'`."
|
790
853
|
Enabled: pending
|
@@ -937,6 +1000,18 @@ Rails/ToFormattedS:
|
|
937
1000
|
- to_formatted_s
|
938
1001
|
VersionAdded: '2.15'
|
939
1002
|
|
1003
|
+
Rails/ToSWithArgument:
|
1004
|
+
Description: 'Identifies passing any argument to `#to_s`.'
|
1005
|
+
Enabled: pending
|
1006
|
+
Safe: false
|
1007
|
+
VersionAdded: '2.16'
|
1008
|
+
|
1009
|
+
Rails/TopLevelHashWithIndifferentAccess:
|
1010
|
+
Description: 'Identifies top-level `HashWithIndifferentAccess`.'
|
1011
|
+
Reference: 'https://guides.rubyonrails.org/upgrading_ruby_on_rails.html#top-level-hashwithindifferentaccess-is-soft-deprecated'
|
1012
|
+
Enabled: pending
|
1013
|
+
VersionAdded: '2.16'
|
1014
|
+
|
940
1015
|
Rails/TransactionExitStatement:
|
941
1016
|
Description: 'Avoid the usage of `return`, `break` and `throw` in transaction blocks.'
|
942
1017
|
Enabled: pending
|
@@ -1003,6 +1078,12 @@ Rails/WhereExists:
|
|
1003
1078
|
VersionAdded: '2.7'
|
1004
1079
|
VersionChanged: '2.10'
|
1005
1080
|
|
1081
|
+
Rails/WhereMissing:
|
1082
|
+
Description: 'Use `where.missing(...)` to find missing relationship records.'
|
1083
|
+
StyleGuide: 'https://rails.rubystyle.guide/#finding-missing-relationship-records'
|
1084
|
+
Enabled: pending
|
1085
|
+
VersionAdded: '2.16'
|
1086
|
+
|
1006
1087
|
Rails/WhereNot:
|
1007
1088
|
Description: 'Use `where.not(...)` instead of manually constructing negated SQL in `where`.'
|
1008
1089
|
StyleGuide: 'https://rails.rubystyle.guide/#hash-conditions'
|
data/config/obsoletion.yml
CHANGED
@@ -5,3 +5,13 @@
|
|
5
5
|
#
|
6
6
|
extracted:
|
7
7
|
Rails/*: ~
|
8
|
+
|
9
|
+
# Cop parameters that have been changed
|
10
|
+
# Can be treated as a warning instead of a failure with `severity: warning`
|
11
|
+
changed_parameters:
|
12
|
+
- cops: Rails/FindEach
|
13
|
+
parameters: IgnoredMethods
|
14
|
+
alternatives:
|
15
|
+
- AllowedMethods
|
16
|
+
- AllowedPatterns
|
17
|
+
severity: warning
|
@@ -48,10 +48,7 @@ module RuboCop
|
|
48
48
|
|
49
49
|
class_nodes = class_node.defined_module.each_node
|
50
50
|
namespaces = class_node.each_ancestor(:class, :module).map(&:identifier)
|
51
|
-
[*class_nodes, *namespaces]
|
52
|
-
.reverse
|
53
|
-
.map { |node| node.children[1] }.join('_')
|
54
|
-
.tableize
|
51
|
+
[*class_nodes, *namespaces].reverse.map { |node| node.children[1] }.join('_').tableize
|
55
52
|
end
|
56
53
|
|
57
54
|
# Resolve relation into column name.
|
@@ -10,9 +10,7 @@ module RuboCop
|
|
10
10
|
bigint binary boolean date datetime decimal float integer json string
|
11
11
|
text time timestamp virtual
|
12
12
|
].freeze
|
13
|
-
RAILS_ABSTRACT_SCHEMA_DEFINITIONS_HELPERS = %i[
|
14
|
-
column references belongs_to primary_key numeric
|
15
|
-
].freeze
|
13
|
+
RAILS_ABSTRACT_SCHEMA_DEFINITIONS_HELPERS = %i[column references belongs_to primary_key numeric].freeze
|
16
14
|
POSTGRES_SCHEMA_DEFINITIONS = %i[
|
17
15
|
bigserial bit bit_varying cidr citext daterange hstore inet interval
|
18
16
|
int4range int8range jsonb ltree macaddr money numrange oid point line
|
@@ -6,7 +6,7 @@ module RuboCop
|
|
6
6
|
module IndexMethod # rubocop:disable Metrics/ModuleLength
|
7
7
|
RESTRICT_ON_SEND = %i[each_with_object to_h map collect []].freeze
|
8
8
|
|
9
|
-
def on_block(node)
|
9
|
+
def on_block(node) # rubocop:todo InternalAffairs/NumblockHandler
|
10
10
|
on_bad_each_with_object(node) do |*match|
|
11
11
|
handle_possible_offense(node, match, 'each_with_object')
|
12
12
|
end
|
@@ -98,10 +98,7 @@ module RuboCop
|
|
98
98
|
|
99
99
|
captures = extract_captures(correction.match)
|
100
100
|
correction.set_new_arg_name(captures.transformed_argname, corrector)
|
101
|
-
correction.set_new_body_expression(
|
102
|
-
captures.transforming_body_expr,
|
103
|
-
corrector
|
104
|
-
)
|
101
|
+
correction.set_new_body_expression(captures.transforming_body_expr, corrector)
|
105
102
|
end
|
106
103
|
|
107
104
|
# Internal helper class to hold match data
|
@@ -110,8 +107,7 @@ module RuboCop
|
|
110
107
|
:transforming_body_expr
|
111
108
|
) do
|
112
109
|
def noop_transformation?
|
113
|
-
transforming_body_expr.lvar_type? &&
|
114
|
-
transforming_body_expr.children == [transformed_argname]
|
110
|
+
transforming_body_expr.lvar_type? && transforming_body_expr.children == [transformed_argname]
|
115
111
|
end
|
116
112
|
end
|
117
113
|
|
@@ -157,17 +153,11 @@ module RuboCop
|
|
157
153
|
end
|
158
154
|
|
159
155
|
def set_new_arg_name(transformed_argname, corrector)
|
160
|
-
corrector.replace(
|
161
|
-
block_node.arguments.loc.expression,
|
162
|
-
"|#{transformed_argname}|"
|
163
|
-
)
|
156
|
+
corrector.replace(block_node.arguments.loc.expression, "|#{transformed_argname}|")
|
164
157
|
end
|
165
158
|
|
166
159
|
def set_new_body_expression(transforming_body_expr, corrector)
|
167
|
-
corrector.replace(
|
168
|
-
block_node.body.loc.expression,
|
169
|
-
transforming_body_expr.loc.expression.source
|
170
|
-
)
|
160
|
+
corrector.replace(block_node.body.loc.expression, transforming_body_expr.loc.expression.source)
|
171
161
|
end
|
172
162
|
end
|
173
163
|
end
|
@@ -0,0 +1,98 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Rails
|
6
|
+
# Using `flash` assignment before `render` in Rails controllers will persist the message for too long.
|
7
|
+
# Check https://guides.rubyonrails.org/action_controller_overview.html#flash-now
|
8
|
+
#
|
9
|
+
# @safety
|
10
|
+
# This cop's autocorrection is unsafe because it replaces `flash` by `flash.now`.
|
11
|
+
# Even though it is usually a mistake, it might be used intentionally.
|
12
|
+
#
|
13
|
+
# @example
|
14
|
+
#
|
15
|
+
# # bad
|
16
|
+
# class HomeController < ApplicationController
|
17
|
+
# def create
|
18
|
+
# flash[:alert] = "msg"
|
19
|
+
# render :index
|
20
|
+
# end
|
21
|
+
# end
|
22
|
+
#
|
23
|
+
# # good
|
24
|
+
# class HomeController < ApplicationController
|
25
|
+
# def create
|
26
|
+
# flash.now[:alert] = "msg"
|
27
|
+
# render :index
|
28
|
+
# end
|
29
|
+
# end
|
30
|
+
#
|
31
|
+
class ActionControllerFlashBeforeRender < Base
|
32
|
+
extend AutoCorrector
|
33
|
+
|
34
|
+
MSG = 'Use `flash.now` before `render`.'
|
35
|
+
|
36
|
+
def_node_search :flash_assignment?, <<~PATTERN
|
37
|
+
^(send (send nil? :flash) :[]= ...)
|
38
|
+
PATTERN
|
39
|
+
|
40
|
+
def_node_search :render?, <<~PATTERN
|
41
|
+
(send nil? :render ...)
|
42
|
+
PATTERN
|
43
|
+
|
44
|
+
def_node_search :action_controller?, <<~PATTERN
|
45
|
+
{
|
46
|
+
(const nil? :ApplicationController)
|
47
|
+
(const (const nil? :ActionController) :Base)
|
48
|
+
}
|
49
|
+
PATTERN
|
50
|
+
|
51
|
+
RESTRICT_ON_SEND = [:flash].freeze
|
52
|
+
|
53
|
+
def on_send(flash_node)
|
54
|
+
return unless flash_assignment?(flash_node)
|
55
|
+
|
56
|
+
return unless followed_by_render?(flash_node)
|
57
|
+
|
58
|
+
return unless instance_method_or_block?(flash_node)
|
59
|
+
|
60
|
+
return unless inherit_action_controller_base?(flash_node)
|
61
|
+
|
62
|
+
add_offense(flash_node) do |corrector|
|
63
|
+
corrector.replace(flash_node, 'flash.now')
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
private
|
68
|
+
|
69
|
+
def followed_by_render?(flash_node)
|
70
|
+
flash_assigment_node = find_ancestor(flash_node, type: :send)
|
71
|
+
context = flash_assigment_node.parent
|
72
|
+
|
73
|
+
context.each_child_node.any? do |node|
|
74
|
+
render?(node)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def inherit_action_controller_base?(node)
|
79
|
+
class_node = find_ancestor(node, type: :class)
|
80
|
+
return unless class_node
|
81
|
+
|
82
|
+
action_controller?(class_node)
|
83
|
+
end
|
84
|
+
|
85
|
+
def instance_method_or_block?(node)
|
86
|
+
def_node = find_ancestor(node, type: :def)
|
87
|
+
block_node = find_ancestor(node, type: :block)
|
88
|
+
|
89
|
+
def_node || block_node
|
90
|
+
end
|
91
|
+
|
92
|
+
def find_ancestor(node, type:)
|
93
|
+
node.each_ancestor(type).first
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
@@ -21,10 +21,7 @@ module RuboCop
|
|
21
21
|
|
22
22
|
MSG = 'Use `%<prefer>s` instead of `%<current>s`.'
|
23
23
|
|
24
|
-
ALIASES = {
|
25
|
-
update_attributes: :update,
|
26
|
-
update_attributes!: :update!
|
27
|
-
}.freeze
|
24
|
+
ALIASES = { update_attributes: :update, update_attributes!: :update! }.freeze
|
28
25
|
|
29
26
|
RESTRICT_ON_SEND = ALIASES.keys.freeze
|
30
27
|
|
@@ -25,12 +25,9 @@ module RuboCop
|
|
25
25
|
# end
|
26
26
|
#
|
27
27
|
class ActiveRecordOverride < Base
|
28
|
-
MSG =
|
29
|
-
'Use %<prefer>s callbacks instead of overriding the Active Record ' \
|
30
|
-
'method `%<bad>s`.'
|
28
|
+
MSG = 'Use %<prefer>s callbacks instead of overriding the Active Record method `%<bad>s`.'
|
31
29
|
BAD_METHODS = %i[create destroy save update].freeze
|
32
|
-
ACTIVE_RECORD_CLASSES = %w[ApplicationRecord ActiveModel::Base
|
33
|
-
ActiveRecord::Base].freeze
|
30
|
+
ACTIVE_RECORD_CLASSES = %w[ApplicationRecord ActiveModel::Base ActiveRecord::Base].freeze
|
34
31
|
|
35
32
|
def on_def(node)
|
36
33
|
return unless BAD_METHODS.include?(node.method_name)
|
@@ -0,0 +1,70 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Rails
|
6
|
+
# Checks for Rails framework classes that are patched directly instead of using Active Support load hooks. Direct
|
7
|
+
# patching forcibly loads the framework referenced, using hooks defers loading until it's actually needed.
|
8
|
+
#
|
9
|
+
# @safety
|
10
|
+
# While using lazy load hooks is recommended, it changes the order in which is code is loaded and may reveal
|
11
|
+
# load order dependency bugs.
|
12
|
+
#
|
13
|
+
# @example
|
14
|
+
#
|
15
|
+
# # bad
|
16
|
+
# ActiveRecord::Base.include(MyClass)
|
17
|
+
#
|
18
|
+
# # good
|
19
|
+
# ActiveSupport.on_load(:active_record) { include MyClass }
|
20
|
+
class ActiveSupportOnLoad < Base
|
21
|
+
extend AutoCorrector
|
22
|
+
|
23
|
+
MSG = 'Use `%<prefer>s` instead of `%<current>s`.'
|
24
|
+
RESTRICT_ON_SEND = %i[prepend include extend].freeze
|
25
|
+
LOAD_HOOKS = {
|
26
|
+
'ActionCable' => 'action_cable',
|
27
|
+
'ActionCable::Channel::Base' => 'action_cable_channel',
|
28
|
+
'ActionCable::Connection::Base' => 'action_cable_connection',
|
29
|
+
'ActionCable::Connection::TestCase' => 'action_cable_connection_test_case',
|
30
|
+
'ActionController::API' => 'action_controller',
|
31
|
+
'ActionController::Base' => 'action_controller',
|
32
|
+
'ActionController::TestCase' => 'action_controller_test_case',
|
33
|
+
'ActionDispatch::IntegrationTest' => 'action_dispatch_integration_test',
|
34
|
+
'ActionDispatch::Request' => 'action_dispatch_request',
|
35
|
+
'ActionDispatch::Response' => 'action_dispatch_response',
|
36
|
+
'ActionDispatch::SystemTestCase' => 'action_dispatch_system_test_case',
|
37
|
+
'ActionMailbox::Base' => 'action_mailbox',
|
38
|
+
'ActionMailbox::InboundEmail' => 'action_mailbox_inbound_email',
|
39
|
+
'ActionMailbox::Record' => 'action_mailbox_record',
|
40
|
+
'ActionMailbox::TestCase' => 'action_mailbox_test_case',
|
41
|
+
'ActionMailer::Base' => 'action_mailer',
|
42
|
+
'ActionMailer::TestCase' => 'action_mailer_test_case',
|
43
|
+
'ActionText::Content' => 'action_text_content',
|
44
|
+
'ActionText::Record' => 'action_text_record',
|
45
|
+
'ActionText::RichText' => 'action_text_rich_text',
|
46
|
+
'ActionView::Base' => 'action_view',
|
47
|
+
'ActionView::TestCase' => 'action_view_test_case',
|
48
|
+
'ActiveJob::Base' => 'active_job',
|
49
|
+
'ActiveJob::TestCase' => 'active_job_test_case',
|
50
|
+
'ActiveRecord::Base' => 'active_record',
|
51
|
+
'ActiveStorage::Attachment' => 'active_storage_attachment',
|
52
|
+
'ActiveStorage::Blob' => 'active_storage_blob',
|
53
|
+
'ActiveStorage::Record' => 'active_storage_record',
|
54
|
+
'ActiveStorage::VariantRecord' => 'active_storage_variant_record',
|
55
|
+
'ActiveSupport::TestCase' => 'active_support_test_case'
|
56
|
+
}.freeze
|
57
|
+
|
58
|
+
def on_send(node)
|
59
|
+
receiver, method, arguments = *node # rubocop:disable InternalAffairs/NodeDestructuring
|
60
|
+
return unless receiver && (hook = LOAD_HOOKS[receiver.const_name])
|
61
|
+
|
62
|
+
preferred = "ActiveSupport.on_load(:#{hook}) { #{method} #{arguments.source} }"
|
63
|
+
add_offense(node, message: format(MSG, prefer: preferred, current: node.source)) do |corrector|
|
64
|
+
corrector.replace(node, preferred)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
@@ -53,10 +53,7 @@ module RuboCop
|
|
53
53
|
private
|
54
54
|
|
55
55
|
def index_range(pair_node)
|
56
|
-
range_with_surrounding_comma(
|
57
|
-
range_with_surrounding_space(range: pair_node.loc.expression, side: :left),
|
58
|
-
:left
|
59
|
-
)
|
56
|
+
range_with_surrounding_comma(range_with_surrounding_space(pair_node.loc.expression, side: :left), :left)
|
60
57
|
end
|
61
58
|
end
|
62
59
|
end
|
@@ -63,8 +63,7 @@ module RuboCop
|
|
63
63
|
|
64
64
|
MSG_NIL_OR_EMPTY = 'Use `%<prefer>s` instead of `%<current>s`.'
|
65
65
|
MSG_NOT_PRESENT = 'Use `%<prefer>s` instead of `%<current>s`.'
|
66
|
-
MSG_UNLESS_PRESENT = 'Use `if %<prefer>s` instead of '
|
67
|
-
'`%<current>s`.'
|
66
|
+
MSG_UNLESS_PRESENT = 'Use `if %<prefer>s` instead of `%<current>s`.'
|
68
67
|
RESTRICT_ON_SEND = %i[!].freeze
|
69
68
|
|
70
69
|
# `(send nil $_)` is not actually a valid match for an offense. Nodes
|
@@ -111,25 +111,13 @@ module RuboCop
|
|
111
111
|
remove_timestamps
|
112
112
|
].freeze
|
113
113
|
|
114
|
-
MYSQL_COMBINABLE_TRANSFORMATIONS = %i[
|
115
|
-
rename
|
116
|
-
index
|
117
|
-
remove_index
|
118
|
-
].freeze
|
114
|
+
MYSQL_COMBINABLE_TRANSFORMATIONS = %i[rename index remove_index].freeze
|
119
115
|
|
120
|
-
MYSQL_COMBINABLE_ALTER_METHODS = %i[
|
121
|
-
rename_column
|
122
|
-
add_index
|
123
|
-
remove_index
|
124
|
-
].freeze
|
116
|
+
MYSQL_COMBINABLE_ALTER_METHODS = %i[rename_column add_index remove_index].freeze
|
125
117
|
|
126
|
-
POSTGRESQL_COMBINABLE_TRANSFORMATIONS = %i[
|
127
|
-
change_default
|
128
|
-
].freeze
|
118
|
+
POSTGRESQL_COMBINABLE_TRANSFORMATIONS = %i[change_default].freeze
|
129
119
|
|
130
|
-
POSTGRESQL_COMBINABLE_ALTER_METHODS = %i[
|
131
|
-
change_column_default
|
132
|
-
].freeze
|
120
|
+
POSTGRESQL_COMBINABLE_ALTER_METHODS = %i[change_column_default].freeze
|
133
121
|
|
134
122
|
def on_def(node)
|
135
123
|
return unless support_bulk_alter?
|
@@ -186,8 +174,7 @@ module RuboCop
|
|
186
174
|
options = node.arguments[1]
|
187
175
|
return false unless options
|
188
176
|
|
189
|
-
options.hash_type? &&
|
190
|
-
options.keys.any? { |key| key.sym_type? && key.value == :bulk }
|
177
|
+
options.hash_type? && options.keys.any? { |key| key.sym_type? && key.value == :bulk }
|
191
178
|
end
|
192
179
|
|
193
180
|
def database
|
@@ -237,8 +224,7 @@ module RuboCop
|
|
237
224
|
end
|
238
225
|
|
239
226
|
def call_to_combinable_alter_method?(child_node)
|
240
|
-
child_node.send_type? &&
|
241
|
-
combinable_alter_methods.include?(child_node.method_name)
|
227
|
+
child_node.send_type? && combinable_alter_methods.include?(child_node.method_name)
|
242
228
|
end
|
243
229
|
|
244
230
|
def combinable_alter_methods
|
@@ -93,7 +93,11 @@ module RuboCop
|
|
93
93
|
end
|
94
94
|
|
95
95
|
def offense_range(node)
|
96
|
-
end_pos = node.parent&.block_type?
|
96
|
+
end_pos = if node.parent&.block_type? && node.parent&.send_node == node
|
97
|
+
node.parent.loc.expression.end_pos
|
98
|
+
else
|
99
|
+
node.loc.expression.end_pos
|
100
|
+
end
|
97
101
|
|
98
102
|
range_between(node.loc.selector.begin_pos, end_pos)
|
99
103
|
end
|
@@ -37,9 +37,7 @@ module RuboCop
|
|
37
37
|
return if node.arguments.count >= 3
|
38
38
|
|
39
39
|
first_argument = node.first_argument
|
40
|
-
return if !first_argument ||
|
41
|
-
allowed_argument?(first_argument) ||
|
42
|
-
corrected_ancestor?(node)
|
40
|
+
return if !first_argument || allowed_argument?(first_argument) || corrected_ancestor?(node)
|
43
41
|
|
44
42
|
preferred_method = node.first_argument.value.to_s.underscore
|
45
43
|
message = format(MSG, preferred_method: preferred_method, current_argument: first_argument.source)
|
@@ -53,22 +53,17 @@ module RuboCop
|
|
53
53
|
class Date < Base
|
54
54
|
include ConfigurableEnforcedStyle
|
55
55
|
|
56
|
-
MSG = 'Do not use `Date.%<method_called>s` without zone. Use '
|
57
|
-
'`Time.zone.%<day>s` instead.'
|
56
|
+
MSG = 'Do not use `Date.%<method_called>s` without zone. Use `Time.zone.%<day>s` instead.'
|
58
57
|
|
59
|
-
MSG_SEND = 'Do not use `%<method>s` on Date objects, because they '
|
60
|
-
'know nothing about the time zone in use.'
|
58
|
+
MSG_SEND = 'Do not use `%<method>s` on Date objects, because they know nothing about the time zone in use.'
|
61
59
|
|
62
60
|
RESTRICT_ON_SEND = %i[to_time to_time_in_current_zone].freeze
|
63
61
|
|
64
62
|
BAD_DAYS = %i[today current yesterday tomorrow].freeze
|
65
63
|
|
66
|
-
DEPRECATED_METHODS = [
|
67
|
-
{ deprecated: 'to_time_in_current_zone', relevant: 'in_time_zone' }
|
68
|
-
].freeze
|
64
|
+
DEPRECATED_METHODS = [{ deprecated: 'to_time_in_current_zone', relevant: 'in_time_zone' }].freeze
|
69
65
|
|
70
|
-
DEPRECATED_MSG = '`%<deprecated>s` is deprecated. '
|
71
|
-
'Use `%<relevant>s` instead.'
|
66
|
+
DEPRECATED_MSG = '`%<deprecated>s` is deprecated. Use `%<relevant>s` instead.'
|
72
67
|
|
73
68
|
def on_const(node)
|
74
69
|
mod, klass = *node.children
|
@@ -93,15 +93,12 @@ module RuboCop
|
|
93
93
|
return false if arg_array.size != argument_array.size
|
94
94
|
|
95
95
|
arg_array.zip(argument_array).all? do |arg, argument|
|
96
|
-
arg.arg_type? &&
|
97
|
-
argument.lvar_type? &&
|
98
|
-
arg.children == argument.children
|
96
|
+
arg.arg_type? && argument.lvar_type? && arg.children == argument.children
|
99
97
|
end
|
100
98
|
end
|
101
99
|
|
102
100
|
def method_name_matches?(method_name, body)
|
103
|
-
method_name == body.method_name ||
|
104
|
-
(include_prefix_case? && method_name == prefixed_method_name(body))
|
101
|
+
method_name == body.method_name || (include_prefix_case? && method_name == prefixed_method_name(body))
|
105
102
|
end
|
106
103
|
|
107
104
|
def include_prefix_case?
|