rubocop-rails 2.14.2 → 2.19.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/LICENSE.txt +1 -1
- data/README.md +23 -2
- data/config/default.yml +190 -12
- data/config/obsoletion.yml +10 -0
- data/lib/rubocop/cop/mixin/active_record_helper.rb +3 -6
- data/lib/rubocop/cop/mixin/active_record_migrations_helper.rb +1 -3
- data/lib/rubocop/cop/mixin/enforce_superclass.rb +1 -1
- data/lib/rubocop/cop/mixin/index_method.rb +7 -17
- data/lib/rubocop/cop/mixin/migrations_helper.rb +1 -1
- data/lib/rubocop/cop/rails/action_controller_flash_before_render.rb +112 -0
- data/lib/rubocop/cop/rails/action_controller_test_case.rb +2 -2
- data/lib/rubocop/cop/rails/action_filter.rb +2 -2
- data/lib/rubocop/cop/rails/action_order.rb +116 -0
- data/lib/rubocop/cop/rails/active_record_aliases.rb +3 -4
- data/lib/rubocop/cop/rails/active_record_callbacks_order.rb +7 -4
- data/lib/rubocop/cop/rails/active_record_override.rb +2 -5
- data/lib/rubocop/cop/rails/active_support_aliases.rb +1 -1
- data/lib/rubocop/cop/rails/active_support_on_load.rb +70 -0
- data/lib/rubocop/cop/rails/add_column_index.rb +3 -6
- data/lib/rubocop/cop/rails/after_commit_override.rb +1 -1
- data/lib/rubocop/cop/rails/application_controller.rb +2 -2
- data/lib/rubocop/cop/rails/application_job.rb +3 -3
- data/lib/rubocop/cop/rails/application_mailer.rb +2 -2
- data/lib/rubocop/cop/rails/application_record.rb +2 -2
- data/lib/rubocop/cop/rails/arel_star.rb +2 -2
- data/lib/rubocop/cop/rails/assert_not.rb +1 -1
- data/lib/rubocop/cop/rails/attribute_default_block_value.rb +1 -1
- data/lib/rubocop/cop/rails/belongs_to.rb +2 -5
- data/lib/rubocop/cop/rails/blank.rb +10 -11
- data/lib/rubocop/cop/rails/bulk_change_table.rb +8 -25
- data/lib/rubocop/cop/rails/compact_blank.rb +6 -2
- data/lib/rubocop/cop/rails/content_tag.rb +6 -7
- data/lib/rubocop/cop/rails/create_table_with_timestamps.rb +16 -3
- data/lib/rubocop/cop/rails/date.rb +12 -17
- data/lib/rubocop/cop/rails/default_scope.rb +1 -1
- data/lib/rubocop/cop/rails/delegate.rb +24 -18
- data/lib/rubocop/cop/rails/delegate_allow_blank.rb +2 -2
- data/lib/rubocop/cop/rails/deprecated_active_model_errors_methods.rb +63 -3
- data/lib/rubocop/cop/rails/dot_separated_keys.rb +71 -0
- data/lib/rubocop/cop/rails/duplicate_association.rb +2 -2
- data/lib/rubocop/cop/rails/duplicate_scope.rb +1 -1
- data/lib/rubocop/cop/rails/duration_arithmetic.rb +4 -4
- data/lib/rubocop/cop/rails/dynamic_find_by.rb +26 -14
- data/lib/rubocop/cop/rails/eager_evaluation_log_message.rb +6 -2
- data/lib/rubocop/cop/rails/enum_hash.rb +3 -4
- data/lib/rubocop/cop/rails/enum_uniqueness.rb +3 -6
- data/lib/rubocop/cop/rails/environment_comparison.rb +3 -4
- data/lib/rubocop/cop/rails/environment_variable_access.rb +1 -1
- data/lib/rubocop/cop/rails/exit.rb +1 -1
- data/lib/rubocop/cop/rails/expanded_date_range.rb +39 -23
- data/lib/rubocop/cop/rails/file_path.rb +41 -24
- data/lib/rubocop/cop/rails/find_by.rb +1 -1
- data/lib/rubocop/cop/rails/find_by_id.rb +3 -3
- data/lib/rubocop/cop/rails/find_each.rb +14 -4
- data/lib/rubocop/cop/rails/freeze_time.rb +79 -0
- data/lib/rubocop/cop/rails/has_and_belongs_to_many.rb +1 -1
- data/lib/rubocop/cop/rails/has_many_or_has_one_dependent.rb +14 -8
- data/lib/rubocop/cop/rails/helper_instance_variable.rb +3 -3
- data/lib/rubocop/cop/rails/http_positional_arguments.rb +23 -12
- data/lib/rubocop/cop/rails/http_status.rb +6 -11
- data/lib/rubocop/cop/rails/i18n_lazy_lookup.rb +3 -1
- data/lib/rubocop/cop/rails/i18n_locale_assignment.rb +1 -1
- data/lib/rubocop/cop/rails/i18n_locale_texts.rb +2 -2
- data/lib/rubocop/cop/rails/ignored_columns_assignment.rb +50 -0
- data/lib/rubocop/cop/rails/ignored_skip_action_filter_option.rb +5 -14
- data/lib/rubocop/cop/rails/index_by.rb +2 -2
- data/lib/rubocop/cop/rails/index_with.rb +2 -2
- data/lib/rubocop/cop/rails/inquiry.rb +1 -1
- data/lib/rubocop/cop/rails/inverse_of.rb +4 -10
- data/lib/rubocop/cop/rails/lexically_scoped_action_filter.rb +22 -16
- data/lib/rubocop/cop/rails/link_to_blank.rb +2 -5
- data/lib/rubocop/cop/rails/mailer_name.rb +5 -5
- data/lib/rubocop/cop/rails/match_route.rb +1 -1
- data/lib/rubocop/cop/rails/migration_class_name.rb +2 -2
- data/lib/rubocop/cop/rails/negate_include.rb +2 -2
- data/lib/rubocop/cop/rails/not_null_column.rb +10 -7
- data/lib/rubocop/cop/rails/order_by_id.rb +2 -3
- data/lib/rubocop/cop/rails/output.rb +7 -9
- data/lib/rubocop/cop/rails/output_safety.rb +6 -2
- data/lib/rubocop/cop/rails/pick.rb +1 -1
- data/lib/rubocop/cop/rails/pluck.rb +45 -13
- data/lib/rubocop/cop/rails/pluck_id.rb +2 -2
- data/lib/rubocop/cop/rails/pluck_in_where.rb +1 -1
- data/lib/rubocop/cop/rails/pluralization_grammar.rb +2 -3
- data/lib/rubocop/cop/rails/presence.rb +22 -13
- data/lib/rubocop/cop/rails/present.rb +10 -13
- data/lib/rubocop/cop/rails/rake_environment.rb +3 -3
- data/lib/rubocop/cop/rails/read_write_attribute.rb +2 -2
- data/lib/rubocop/cop/rails/redundant_allow_nil.rb +5 -7
- data/lib/rubocop/cop/rails/redundant_foreign_key.rb +3 -3
- data/lib/rubocop/cop/rails/redundant_presence_validation_on_belongs_to.rb +3 -3
- data/lib/rubocop/cop/rails/redundant_receiver_in_with_options.rb +31 -27
- data/lib/rubocop/cop/rails/redundant_travel_back.rb +1 -1
- data/lib/rubocop/cop/rails/reflection_class_name.rb +35 -2
- data/lib/rubocop/cop/rails/refute_methods.rb +1 -5
- data/lib/rubocop/cop/rails/relative_date_constant.rb +5 -8
- data/lib/rubocop/cop/rails/render_inline.rb +1 -1
- data/lib/rubocop/cop/rails/render_plain_text.rb +1 -1
- data/lib/rubocop/cop/rails/request_referer.rb +2 -3
- data/lib/rubocop/cop/rails/require_dependency.rb +2 -2
- data/lib/rubocop/cop/rails/response_parsed_body.rb +57 -0
- data/lib/rubocop/cop/rails/reversible_migration.rb +15 -63
- data/lib/rubocop/cop/rails/reversible_migration_method_definition.rb +5 -6
- data/lib/rubocop/cop/rails/root_join_chain.rb +1 -1
- data/lib/rubocop/cop/rails/root_pathname_methods.rb +238 -0
- data/lib/rubocop/cop/rails/root_public_path.rb +59 -0
- data/lib/rubocop/cop/rails/safe_navigation.rb +8 -13
- data/lib/rubocop/cop/rails/safe_navigation_with_blank.rb +2 -4
- data/lib/rubocop/cop/rails/save_bang.rb +12 -24
- data/lib/rubocop/cop/rails/schema_comment.rb +1 -1
- data/lib/rubocop/cop/rails/scope_args.rb +1 -1
- data/lib/rubocop/cop/rails/short_i18n.rb +3 -6
- data/lib/rubocop/cop/rails/skips_model_validations.rb +3 -4
- data/lib/rubocop/cop/rails/squished_sql_heredocs.rb +10 -7
- data/lib/rubocop/cop/rails/strip_heredoc.rb +56 -0
- data/lib/rubocop/cop/rails/table_name_assignment.rb +1 -1
- data/lib/rubocop/cop/rails/three_state_boolean_column.rb +73 -0
- data/lib/rubocop/cop/rails/time_zone.rb +34 -32
- data/lib/rubocop/cop/rails/time_zone_assignment.rb +4 -4
- data/lib/rubocop/cop/rails/to_formatted_s.rb +46 -0
- data/lib/rubocop/cop/rails/to_s_with_argument.rb +78 -0
- data/lib/rubocop/cop/rails/top_level_hash_with_indifferent_access.rb +49 -0
- data/lib/rubocop/cop/rails/transaction_exit_statement.rb +17 -12
- data/lib/rubocop/cop/rails/uniq_before_pluck.rb +3 -6
- data/lib/rubocop/cop/rails/unique_validation_without_index.rb +14 -7
- data/lib/rubocop/cop/rails/unknown_env.rb +3 -5
- data/lib/rubocop/cop/rails/unused_ignored_columns.rb +7 -2
- data/lib/rubocop/cop/rails/validation.rb +5 -13
- data/lib/rubocop/cop/rails/where_equals.rb +2 -2
- data/lib/rubocop/cop/rails/where_exists.rb +3 -3
- data/lib/rubocop/cop/rails/where_missing.rb +118 -0
- data/lib/rubocop/cop/rails/where_not.rb +2 -2
- data/lib/rubocop/cop/rails/where_not_with_multiple_conditions.rb +55 -0
- data/lib/rubocop/cop/rails_cops.rb +16 -0
- data/lib/rubocop/rails/schema_loader/schema.rb +8 -5
- data/lib/rubocop/rails/version.rb +1 -1
- data/lib/rubocop/rails.rb +1 -1
- data/lib/rubocop-rails.rb +19 -0
- metadata +23 -9
- data/bin/console +0 -11
- data/bin/setup +0 -7
@@ -3,7 +3,7 @@
|
|
3
3
|
module RuboCop
|
4
4
|
module Cop
|
5
5
|
module Rails
|
6
|
-
#
|
6
|
+
# Checks whether alter queries are combinable.
|
7
7
|
# If combinable queries are detected, it suggests to you
|
8
8
|
# to use `change_table` with `bulk: true` instead.
|
9
9
|
# This option causes the migration to generate a single
|
@@ -62,9 +62,6 @@ module RuboCop
|
|
62
62
|
# t.string :nickname
|
63
63
|
# end
|
64
64
|
# end
|
65
|
-
#
|
66
|
-
# @see https://api.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/SchemaStatements.html#method-i-change_table
|
67
|
-
# @see https://api.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/Table.html
|
68
65
|
class BulkChangeTable < Base
|
69
66
|
MSG_FOR_CHANGE_TABLE = <<~MSG.chomp
|
70
67
|
You can combine alter queries using `bulk: true` options.
|
@@ -111,25 +108,13 @@ module RuboCop
|
|
111
108
|
remove_timestamps
|
112
109
|
].freeze
|
113
110
|
|
114
|
-
MYSQL_COMBINABLE_TRANSFORMATIONS = %i[
|
115
|
-
rename
|
116
|
-
index
|
117
|
-
remove_index
|
118
|
-
].freeze
|
111
|
+
MYSQL_COMBINABLE_TRANSFORMATIONS = %i[rename index remove_index].freeze
|
119
112
|
|
120
|
-
MYSQL_COMBINABLE_ALTER_METHODS = %i[
|
121
|
-
rename_column
|
122
|
-
add_index
|
123
|
-
remove_index
|
124
|
-
].freeze
|
113
|
+
MYSQL_COMBINABLE_ALTER_METHODS = %i[rename_column add_index remove_index].freeze
|
125
114
|
|
126
|
-
POSTGRESQL_COMBINABLE_TRANSFORMATIONS = %i[
|
127
|
-
change_default
|
128
|
-
].freeze
|
115
|
+
POSTGRESQL_COMBINABLE_TRANSFORMATIONS = %i[change_default].freeze
|
129
116
|
|
130
|
-
POSTGRESQL_COMBINABLE_ALTER_METHODS = %i[
|
131
|
-
change_column_default
|
132
|
-
].freeze
|
117
|
+
POSTGRESQL_COMBINABLE_ALTER_METHODS = %i[change_column_default].freeze
|
133
118
|
|
134
119
|
def on_def(node)
|
135
120
|
return unless support_bulk_alter?
|
@@ -186,8 +171,7 @@ module RuboCop
|
|
186
171
|
options = node.arguments[1]
|
187
172
|
return false unless options
|
188
173
|
|
189
|
-
options.hash_type? &&
|
190
|
-
options.keys.any? { |key| key.sym_type? && key.value == :bulk }
|
174
|
+
options.hash_type? && options.keys.any? { |key| key.sym_type? && key.value == :bulk }
|
191
175
|
end
|
192
176
|
|
193
177
|
def database
|
@@ -229,7 +213,7 @@ module RuboCop
|
|
229
213
|
true
|
230
214
|
when POSTGRESQL
|
231
215
|
# Add bulk alter support for PostgreSQL in 5.2.0
|
232
|
-
#
|
216
|
+
# See: https://github.com/rails/rails/pull/31331
|
233
217
|
target_rails_version >= 5.2
|
234
218
|
else
|
235
219
|
false
|
@@ -237,8 +221,7 @@ module RuboCop
|
|
237
221
|
end
|
238
222
|
|
239
223
|
def call_to_combinable_alter_method?(child_node)
|
240
|
-
child_node.send_type? &&
|
241
|
-
combinable_alter_methods.include?(child_node.method_name)
|
224
|
+
child_node.send_type? && combinable_alter_methods.include?(child_node.method_name)
|
242
225
|
end
|
243
226
|
|
244
227
|
def combinable_alter_methods
|
@@ -17,7 +17,7 @@ module RuboCop
|
|
17
17
|
# `ActionController::Parameters`.
|
18
18
|
# `Array#compact_blank!`, `Hash#compact_blank!` are equivalent to `delete_if(&:blank?)`.
|
19
19
|
# `ActionController::Parameters#compact_blank!` is equivalent to `reject!(&:blank?)`.
|
20
|
-
# If the cop makes a mistake,
|
20
|
+
# If the cop makes a mistake, autocorrected code may get unexpected behavior.
|
21
21
|
#
|
22
22
|
# @example
|
23
23
|
#
|
@@ -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.source_range.end_pos
|
98
|
+
else
|
99
|
+
node.source_range.end_pos
|
100
|
+
end
|
97
101
|
|
98
102
|
range_between(node.loc.selector.begin_pos, end_pos)
|
99
103
|
end
|
@@ -3,7 +3,7 @@
|
|
3
3
|
module RuboCop
|
4
4
|
module Cop
|
5
5
|
module Rails
|
6
|
-
#
|
6
|
+
# Checks legacy syntax usage of `tag`
|
7
7
|
#
|
8
8
|
# NOTE: Allow `tag` when the first argument is a variable because
|
9
9
|
# `tag(name)` is simpler rather than `tag.public_send(name)`.
|
@@ -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)
|
@@ -58,7 +56,8 @@ module RuboCop
|
|
58
56
|
argument.send_type? ||
|
59
57
|
argument.const_type? ||
|
60
58
|
argument.splat_type? ||
|
61
|
-
allowed_name?(argument)
|
59
|
+
allowed_name?(argument) ||
|
60
|
+
!argument.respond_to?(:value)
|
62
61
|
end
|
63
62
|
|
64
63
|
def register_offense(node, message, preferred_method)
|
@@ -82,11 +81,11 @@ module RuboCop
|
|
82
81
|
def allowed_name?(argument)
|
83
82
|
return false unless argument.str_type? || argument.sym_type?
|
84
83
|
|
85
|
-
!/^[a-zA-Z
|
84
|
+
!/^[a-zA-Z-][a-zA-Z\-0-9]*$/.match?(argument.value)
|
86
85
|
end
|
87
86
|
|
88
87
|
def correction_range(node)
|
89
|
-
range_between(node.loc.selector.begin_pos, node.
|
88
|
+
range_between(node.loc.selector.begin_pos, node.source_range.end_pos)
|
90
89
|
end
|
91
90
|
end
|
92
91
|
end
|
@@ -3,10 +3,12 @@
|
|
3
3
|
module RuboCop
|
4
4
|
module Cop
|
5
5
|
module Rails
|
6
|
-
#
|
7
|
-
# when creating a new table.
|
6
|
+
# Checks the migration for which timestamps are not included when creating a new table.
|
8
7
|
# In many cases, timestamps are useful information and should be added.
|
9
8
|
#
|
9
|
+
# NOTE: Allow `timestamps` not written when `id: false` because this emphasizes respecting
|
10
|
+
# user's editing intentions.
|
11
|
+
#
|
10
12
|
# @example
|
11
13
|
# # bad
|
12
14
|
# create_table :users
|
@@ -40,12 +42,23 @@ module RuboCop
|
|
40
42
|
#
|
41
43
|
# t.datetime :updated_at, default: -> { 'CURRENT_TIMESTAMP' }
|
42
44
|
# end
|
45
|
+
#
|
46
|
+
# # good
|
47
|
+
# create_table :users, articles, id: false do |t|
|
48
|
+
# t.integer :user_id
|
49
|
+
# t.integer :article_id
|
50
|
+
# end
|
51
|
+
#
|
43
52
|
class CreateTableWithTimestamps < Base
|
44
53
|
include ActiveRecordMigrationsHelper
|
45
54
|
|
46
55
|
MSG = 'Add timestamps when creating a new table.'
|
47
56
|
RESTRICT_ON_SEND = %i[create_table].freeze
|
48
57
|
|
58
|
+
def_node_search :use_id_false_option?, <<~PATTERN
|
59
|
+
(pair (sym :id) (false))
|
60
|
+
PATTERN
|
61
|
+
|
49
62
|
def_node_matcher :create_table_with_timestamps_proc?, <<~PATTERN
|
50
63
|
(send nil? :create_table (sym _) ... (block-pass (sym :timestamps)))
|
51
64
|
PATTERN
|
@@ -61,7 +74,7 @@ module RuboCop
|
|
61
74
|
PATTERN
|
62
75
|
|
63
76
|
def on_send(node)
|
64
|
-
return
|
77
|
+
return if !node.command?(:create_table) || use_id_false_option?(node)
|
65
78
|
|
66
79
|
parent = node.parent
|
67
80
|
|
@@ -3,7 +3,7 @@
|
|
3
3
|
module RuboCop
|
4
4
|
module Cop
|
5
5
|
module Rails
|
6
|
-
#
|
6
|
+
# Checks for the correct use of Date methods,
|
7
7
|
# such as Date.today, Date.current etc.
|
8
8
|
#
|
9
9
|
# Using `Date.today` is dangerous, because it doesn't know anything about
|
@@ -22,26 +22,26 @@ module RuboCop
|
|
22
22
|
# And you can set a warning for `to_time` with `AllowToTime: false`.
|
23
23
|
# `AllowToTime` is `true` by default to prevent false positive on `DateTime` object.
|
24
24
|
#
|
25
|
-
# @example EnforcedStyle:
|
25
|
+
# @example EnforcedStyle: flexible (default)
|
26
26
|
# # bad
|
27
|
-
# Date.current
|
28
|
-
# Date.yesterday
|
29
27
|
# Date.today
|
30
28
|
#
|
31
29
|
# # good
|
32
30
|
# Time.zone.today
|
33
31
|
# Time.zone.today - 1.day
|
32
|
+
# Date.current
|
33
|
+
# Date.yesterday
|
34
|
+
# date.in_time_zone
|
34
35
|
#
|
35
|
-
# @example EnforcedStyle:
|
36
|
+
# @example EnforcedStyle: strict
|
36
37
|
# # bad
|
38
|
+
# Date.current
|
39
|
+
# Date.yesterday
|
37
40
|
# Date.today
|
38
41
|
#
|
39
42
|
# # good
|
40
43
|
# Time.zone.today
|
41
44
|
# Time.zone.today - 1.day
|
42
|
-
# Date.current
|
43
|
-
# Date.yesterday
|
44
|
-
# date.in_time_zone
|
45
45
|
#
|
46
46
|
# @example AllowToTime: true (default)
|
47
47
|
# # good
|
@@ -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
|
@@ -3,7 +3,7 @@
|
|
3
3
|
module RuboCop
|
4
4
|
module Cop
|
5
5
|
module Rails
|
6
|
-
#
|
6
|
+
# Looks for delegations that could have been created
|
7
7
|
# automatically with the `delegate` method.
|
8
8
|
#
|
9
9
|
# Safe navigation `&.` is ignored because Rails' `allow_nil`
|
@@ -24,6 +24,14 @@ module RuboCop
|
|
24
24
|
# # good
|
25
25
|
# delegate :bar, to: :foo
|
26
26
|
#
|
27
|
+
# # bad
|
28
|
+
# def bar
|
29
|
+
# self.bar
|
30
|
+
# end
|
31
|
+
#
|
32
|
+
# # good
|
33
|
+
# delegate :bar, to: :self
|
34
|
+
#
|
27
35
|
# # good
|
28
36
|
# def bar
|
29
37
|
# foo&.bar
|
@@ -54,12 +62,13 @@ module RuboCop
|
|
54
62
|
# delegate :bar, to: :foo, prefix: true
|
55
63
|
class Delegate < Base
|
56
64
|
extend AutoCorrector
|
65
|
+
include VisibilityHelp
|
57
66
|
|
58
67
|
MSG = 'Use `delegate` to define delegations.'
|
59
68
|
|
60
69
|
def_node_matcher :delegate?, <<~PATTERN
|
61
70
|
(def _method_name _args
|
62
|
-
(send (send nil? _) _ ...))
|
71
|
+
(send {(send nil? _) (self)} _ ...))
|
63
72
|
PATTERN
|
64
73
|
|
65
74
|
def on_def(node)
|
@@ -73,10 +82,14 @@ module RuboCop
|
|
73
82
|
|
74
83
|
def register_offense(node)
|
75
84
|
add_offense(node.loc.keyword) do |corrector|
|
76
|
-
|
85
|
+
body = node.body
|
86
|
+
|
87
|
+
receiver = body.receiver.self_type? ? 'self' : ":#{body.receiver.method_name}"
|
88
|
+
|
89
|
+
delegation = ["delegate :#{body.method_name}", "to: #{receiver}"]
|
77
90
|
delegation << ['prefix: true'] if node.method?(prefixed_method_name(node.body))
|
78
91
|
|
79
|
-
corrector.replace(node
|
92
|
+
corrector.replace(node, delegation.join(', '))
|
80
93
|
end
|
81
94
|
end
|
82
95
|
|
@@ -92,15 +105,12 @@ module RuboCop
|
|
92
105
|
return false if arg_array.size != argument_array.size
|
93
106
|
|
94
107
|
arg_array.zip(argument_array).all? do |arg, argument|
|
95
|
-
arg.arg_type? &&
|
96
|
-
argument.lvar_type? &&
|
97
|
-
arg.children == argument.children
|
108
|
+
arg.arg_type? && argument.lvar_type? && arg.children == argument.children
|
98
109
|
end
|
99
110
|
end
|
100
111
|
|
101
112
|
def method_name_matches?(method_name, body)
|
102
|
-
method_name == body.method_name ||
|
103
|
-
(include_prefix_case? && method_name == prefixed_method_name(body))
|
113
|
+
method_name == body.method_name || (include_prefix_case? && method_name == prefixed_method_name(body))
|
104
114
|
end
|
105
115
|
|
106
116
|
def include_prefix_case?
|
@@ -108,21 +118,17 @@ module RuboCop
|
|
108
118
|
end
|
109
119
|
|
110
120
|
def prefixed_method_name(body)
|
121
|
+
return '' if body.receiver.self_type?
|
122
|
+
|
111
123
|
[body.receiver.method_name, body.method_name].join('_').to_sym
|
112
124
|
end
|
113
125
|
|
114
126
|
def private_or_protected_delegation(node)
|
115
|
-
|
116
|
-
private_or_protected_before(line) ||
|
117
|
-
private_or_protected_inline(line)
|
118
|
-
end
|
119
|
-
|
120
|
-
def private_or_protected_before(line)
|
121
|
-
(processed_source[0..line].map(&:strip) & %w[private protected]).any?
|
127
|
+
private_or_protected_inline(node) || node_visibility(node) != :public
|
122
128
|
end
|
123
129
|
|
124
|
-
def private_or_protected_inline(
|
125
|
-
processed_source[
|
130
|
+
def private_or_protected_inline(node)
|
131
|
+
processed_source[node.first_line - 1].strip.match?(/\A(private )|(protected )/)
|
126
132
|
end
|
127
133
|
end
|
128
134
|
end
|
@@ -3,7 +3,7 @@
|
|
3
3
|
module RuboCop
|
4
4
|
module Cop
|
5
5
|
module Rails
|
6
|
-
#
|
6
|
+
# Looks for delegations that pass :allow_blank as an option
|
7
7
|
# instead of :allow_nil. :allow_blank is not a valid option to pass
|
8
8
|
# to ActiveSupport#delegate.
|
9
9
|
#
|
@@ -27,7 +27,7 @@ module RuboCop
|
|
27
27
|
return unless (offending_node = allow_blank_option(node))
|
28
28
|
|
29
29
|
add_offense(offending_node) do |corrector|
|
30
|
-
corrector.replace(offending_node.key
|
30
|
+
corrector.replace(offending_node.key, 'allow_nil')
|
31
31
|
end
|
32
32
|
end
|
33
33
|
end
|
@@ -3,7 +3,7 @@
|
|
3
3
|
module RuboCop
|
4
4
|
module Cop
|
5
5
|
module Rails
|
6
|
-
#
|
6
|
+
# Checks direct manipulation of ActiveModel#errors as hash.
|
7
7
|
# These operations are deprecated in Rails 6.1 and will not work in Rails 7.
|
8
8
|
#
|
9
9
|
# @safety
|
@@ -26,8 +26,19 @@ module RuboCop
|
|
26
26
|
# # good
|
27
27
|
# user.errors.delete(:name)
|
28
28
|
#
|
29
|
+
# # bad
|
30
|
+
# user.errors.keys.include?(:attr)
|
31
|
+
#
|
32
|
+
# # good
|
33
|
+
# user.errors.attribute_names.include?(:attr)
|
34
|
+
#
|
29
35
|
class DeprecatedActiveModelErrorsMethods < Base
|
36
|
+
include RangeHelp
|
37
|
+
extend AutoCorrector
|
38
|
+
|
30
39
|
MSG = 'Avoid manipulating ActiveModel errors as hash directly.'
|
40
|
+
AUTOCORRECTABLE_METHODS = %i[<< clear keys].freeze
|
41
|
+
INCOMPATIBLE_METHODS = %i[keys values to_h to_xml].freeze
|
31
42
|
|
32
43
|
MANIPULATIVE_METHODS = Set[
|
33
44
|
*%i[
|
@@ -45,6 +56,7 @@ module RuboCop
|
|
45
56
|
{
|
46
57
|
#root_manipulation?
|
47
58
|
#root_assignment?
|
59
|
+
#errors_deprecated?
|
48
60
|
#messages_details_manipulation?
|
49
61
|
#messages_details_assignment?
|
50
62
|
}
|
@@ -66,6 +78,12 @@ module RuboCop
|
|
66
78
|
...)
|
67
79
|
PATTERN
|
68
80
|
|
81
|
+
def_node_matcher :errors_deprecated?, <<~PATTERN
|
82
|
+
(send
|
83
|
+
(send #receiver_matcher :errors)
|
84
|
+
{:keys :values :to_h :to_xml})
|
85
|
+
PATTERN
|
86
|
+
|
69
87
|
def_node_matcher :messages_details_manipulation?, <<~PATTERN
|
70
88
|
(send
|
71
89
|
(send
|
@@ -89,18 +107,60 @@ module RuboCop
|
|
89
107
|
|
90
108
|
def on_send(node)
|
91
109
|
any_manipulation?(node) do
|
92
|
-
|
110
|
+
next if target_rails_version <= 6.0 && INCOMPATIBLE_METHODS.include?(node.method_name)
|
111
|
+
|
112
|
+
add_offense(node) do |corrector|
|
113
|
+
next if skip_autocorrect?(node)
|
114
|
+
|
115
|
+
autocorrect(corrector, node)
|
116
|
+
end
|
93
117
|
end
|
94
118
|
end
|
95
119
|
|
96
120
|
private
|
97
121
|
|
122
|
+
def skip_autocorrect?(node)
|
123
|
+
return true unless AUTOCORRECTABLE_METHODS.include?(node.method_name)
|
124
|
+
return false unless (receiver = node.receiver.receiver)
|
125
|
+
|
126
|
+
receiver.send_type? && receiver.method?(:details) && node.method?(:<<)
|
127
|
+
end
|
128
|
+
|
129
|
+
def autocorrect(corrector, node)
|
130
|
+
receiver = node.receiver
|
131
|
+
|
132
|
+
range = offense_range(node, receiver)
|
133
|
+
replacement = replacement(node, receiver)
|
134
|
+
|
135
|
+
corrector.replace(range, replacement)
|
136
|
+
end
|
137
|
+
|
138
|
+
def offense_range(node, receiver)
|
139
|
+
receiver = receiver.receiver while receiver.send_type? && !receiver.method?(:errors) && receiver.receiver
|
140
|
+
range_between(receiver.source_range.end_pos, node.source_range.end_pos)
|
141
|
+
end
|
142
|
+
|
143
|
+
def replacement(node, receiver)
|
144
|
+
return '.attribute_names' if node.method?(:keys)
|
145
|
+
|
146
|
+
key = receiver.first_argument.source
|
147
|
+
|
148
|
+
case node.method_name
|
149
|
+
when :<<
|
150
|
+
value = node.first_argument.source
|
151
|
+
|
152
|
+
".add(#{key}, #{value})"
|
153
|
+
when :clear
|
154
|
+
".delete(#{key})"
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
98
158
|
def receiver_matcher(node)
|
99
159
|
model_file? ? receiver_matcher_inside_model(node) : receiver_matcher_outside_model(node)
|
100
160
|
end
|
101
161
|
|
102
162
|
def model_file?
|
103
|
-
processed_source.
|
163
|
+
processed_source.file_path.include?('/models/')
|
104
164
|
end
|
105
165
|
end
|
106
166
|
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Rails
|
6
|
+
# Enforces the use of dot-separated locale keys instead of specifying the `:scope` option
|
7
|
+
# with an array or a single symbol in `I18n` translation methods.
|
8
|
+
# Dot-separated notation is easier to read and trace the hierarchy.
|
9
|
+
#
|
10
|
+
# @example
|
11
|
+
# # bad
|
12
|
+
# I18n.t :record_invalid, scope: [:activerecord, :errors, :messages]
|
13
|
+
# I18n.t :title, scope: :invitation
|
14
|
+
#
|
15
|
+
# # good
|
16
|
+
# I18n.t 'activerecord.errors.messages.record_invalid'
|
17
|
+
# I18n.t :record_invalid, scope: 'activerecord.errors.messages'
|
18
|
+
#
|
19
|
+
class DotSeparatedKeys < Base
|
20
|
+
include RangeHelp
|
21
|
+
extend AutoCorrector
|
22
|
+
|
23
|
+
MSG = 'Use the dot-separated keys instead of specifying the `:scope` option.'
|
24
|
+
TRANSLATE_METHODS = %i[translate t].freeze
|
25
|
+
|
26
|
+
def_node_matcher :translate_with_scope?, <<~PATTERN
|
27
|
+
(send {nil? (const {nil? cbase} :I18n)} {:translate :t} ${sym_type? str_type?}
|
28
|
+
(hash <$(pair (sym :scope) ${array_type? sym_type?}) ...>)
|
29
|
+
)
|
30
|
+
PATTERN
|
31
|
+
|
32
|
+
def on_send(node)
|
33
|
+
return unless TRANSLATE_METHODS.include?(node.method_name)
|
34
|
+
|
35
|
+
translate_with_scope?(node) do |key_node, scope_node|
|
36
|
+
return unless should_convert_scope?(scope_node)
|
37
|
+
|
38
|
+
add_offense(scope_node) do |corrector|
|
39
|
+
# Eat the comma on the left.
|
40
|
+
range = range_with_surrounding_space(scope_node.source_range, side: :left)
|
41
|
+
range = range_with_surrounding_comma(range, :left)
|
42
|
+
corrector.remove(range)
|
43
|
+
|
44
|
+
corrector.replace(key_node, new_key(key_node, scope_node))
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
private
|
50
|
+
|
51
|
+
def should_convert_scope?(scope_node)
|
52
|
+
scopes(scope_node).all?(&:basic_literal?)
|
53
|
+
end
|
54
|
+
|
55
|
+
def new_key(key_node, scope_node)
|
56
|
+
"'#{scopes(scope_node).map(&:value).join('.')}.#{key_node.value}'".squeeze('.')
|
57
|
+
end
|
58
|
+
|
59
|
+
def scopes(scope_node)
|
60
|
+
value = scope_node.value
|
61
|
+
|
62
|
+
if value.array_type?
|
63
|
+
value.values
|
64
|
+
else
|
65
|
+
[value]
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
@@ -3,7 +3,7 @@
|
|
3
3
|
module RuboCop
|
4
4
|
module Cop
|
5
5
|
module Rails
|
6
|
-
#
|
6
|
+
# Looks for associations that have been defined multiple times in the same file.
|
7
7
|
#
|
8
8
|
# When an association is defined multiple times on a model, Active Record overrides the
|
9
9
|
# previously defined association with the new one. Because of this, this cop's autocorrection
|
@@ -35,7 +35,7 @@ module RuboCop
|
|
35
35
|
offenses(class_node).each do |name, nodes|
|
36
36
|
nodes.each do |node|
|
37
37
|
add_offense(node, message: format(MSG, name: name)) do |corrector|
|
38
|
-
next if nodes.last
|
38
|
+
next if same_line?(nodes.last, node)
|
39
39
|
|
40
40
|
corrector.remove(range_by_whole_lines(node.source_range, include_final_newline: true))
|
41
41
|
end
|
@@ -3,7 +3,7 @@
|
|
3
3
|
module RuboCop
|
4
4
|
module Cop
|
5
5
|
module Rails
|
6
|
-
#
|
6
|
+
# Checks for multiple scopes in a model that have the same `where` clause. This
|
7
7
|
# often means you copy/pasted a scope, updated the name, and forgot to change the condition.
|
8
8
|
#
|
9
9
|
# @example
|
@@ -3,7 +3,7 @@
|
|
3
3
|
module RuboCop
|
4
4
|
module Cop
|
5
5
|
module Rails
|
6
|
-
#
|
6
|
+
# Checks if a duration is added to or subtracted from `Time.current`.
|
7
7
|
#
|
8
8
|
# @example
|
9
9
|
# # bad
|
@@ -70,15 +70,15 @@ module RuboCop
|
|
70
70
|
# @return [Boolean] true if matches
|
71
71
|
def_node_matcher :time_current?, <<~PATTERN
|
72
72
|
{
|
73
|
-
(send (const
|
74
|
-
(send (send (const
|
73
|
+
(send (const {nil? cbase} :Time) :current)
|
74
|
+
(send (send (const {nil? cbase} :Time) :zone) :now)
|
75
75
|
}
|
76
76
|
PATTERN
|
77
77
|
|
78
78
|
def on_send(node)
|
79
79
|
duration_arithmetic_argument?(node) do |*operation|
|
80
80
|
add_offense(node) do |corrector|
|
81
|
-
corrector.replace(node
|
81
|
+
corrector.replace(node, corrected_source(*operation))
|
82
82
|
end
|
83
83
|
end
|
84
84
|
end
|