rubocop-rails 2.15.2 → 2.17.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/config/default.yml +120 -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 +99 -0
- data/lib/rubocop/cop/rails/action_controller_test_case.rb +1 -1
- data/lib/rubocop/cop/rails/action_filter.rb +1 -1
- data/lib/rubocop/cop/rails/action_order.rb +81 -0
- 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 +3 -4
- 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 +8 -6
- data/lib/rubocop/cop/rails/eager_evaluation_log_message.rb +4 -0
- 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 +11 -11
- data/lib/rubocop/cop/rails/ignored_columns_assignment.rb +50 -0
- 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/pluck.rb +8 -7
- data/lib/rubocop/cop/rails/pluralization_grammar.rb +1 -2
- data/lib/rubocop/cop/rails/presence.rb +21 -12
- 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 +3 -3
- data/lib/rubocop/cop/rails/redundant_receiver_in_with_options.rb +30 -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 +10 -21
- 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/where_not_with_multiple_conditions.rb +55 -0
- data/lib/rubocop/cop/rails_cops.rb +10 -0
- data/lib/rubocop/rails/version.rb +1 -1
- data/lib/rubocop-rails.rb +10 -0
- metadata +16 -8
- data/bin/console +0 -11
- data/bin/setup +0 -7
@@ -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)
|
@@ -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)
|
@@ -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?
|
@@ -37,7 +37,8 @@ module RuboCop
|
|
37
37
|
extend AutoCorrector
|
38
38
|
|
39
39
|
MSG = 'Avoid manipulating ActiveModel errors as hash directly.'
|
40
|
-
|
40
|
+
AUTOCORRECTABLE_METHODS = %i[<< clear keys].freeze
|
41
|
+
INCOMPATIBLE_METHODS = %i[keys values to_h to_xml].freeze
|
41
42
|
|
42
43
|
MANIPULATIVE_METHODS = Set[
|
43
44
|
*%i[
|
@@ -55,7 +56,7 @@ module RuboCop
|
|
55
56
|
{
|
56
57
|
#root_manipulation?
|
57
58
|
#root_assignment?
|
58
|
-
#
|
59
|
+
#errors_deprecated?
|
59
60
|
#messages_details_manipulation?
|
60
61
|
#messages_details_assignment?
|
61
62
|
}
|
@@ -77,10 +78,10 @@ module RuboCop
|
|
77
78
|
...)
|
78
79
|
PATTERN
|
79
80
|
|
80
|
-
def_node_matcher :
|
81
|
+
def_node_matcher :errors_deprecated?, <<~PATTERN
|
81
82
|
(send
|
82
83
|
(send #receiver_matcher :errors)
|
83
|
-
:keys)
|
84
|
+
{:keys :values :to_h :to_xml})
|
84
85
|
PATTERN
|
85
86
|
|
86
87
|
def_node_matcher :messages_details_manipulation?, <<~PATTERN
|
@@ -106,10 +107,10 @@ module RuboCop
|
|
106
107
|
|
107
108
|
def on_send(node)
|
108
109
|
any_manipulation?(node) do
|
109
|
-
next if
|
110
|
+
next if target_rails_version <= 6.0 && INCOMPATIBLE_METHODS.include?(node.method_name)
|
110
111
|
|
111
112
|
add_offense(node) do |corrector|
|
112
|
-
next
|
113
|
+
next if skip_autocorrect?(node)
|
113
114
|
|
114
115
|
autocorrect(corrector, node)
|
115
116
|
end
|
@@ -118,14 +119,16 @@ module RuboCop
|
|
118
119
|
|
119
120
|
private
|
120
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
|
+
|
121
129
|
def autocorrect(corrector, node)
|
122
130
|
receiver = node.receiver
|
123
131
|
|
124
|
-
if receiver.receiver.send_type? && receiver.receiver.method?(:messages)
|
125
|
-
corrector.remove(receiver.receiver.loc.dot)
|
126
|
-
corrector.remove(receiver.receiver.loc.selector)
|
127
|
-
end
|
128
|
-
|
129
132
|
range = offense_range(node, receiver)
|
130
133
|
replacement = replacement(node, receiver)
|
131
134
|
|
@@ -133,11 +136,12 @@ module RuboCop
|
|
133
136
|
end
|
134
137
|
|
135
138
|
def offense_range(node, receiver)
|
136
|
-
|
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)
|
137
141
|
end
|
138
142
|
|
139
143
|
def replacement(node, receiver)
|
140
|
-
return '.
|
144
|
+
return '.attribute_names' if node.method?(:keys)
|
141
145
|
|
142
146
|
key = receiver.first_argument.source
|
143
147
|
|
@@ -37,7 +37,7 @@ module RuboCop
|
|
37
37
|
|
38
38
|
add_offense(scope_node) do |corrector|
|
39
39
|
# Eat the comma on the left.
|
40
|
-
range = range_with_surrounding_space(
|
40
|
+
range = range_with_surrounding_space(scope_node.source_range, side: :left)
|
41
41
|
range = range_with_surrounding_comma(range, :left)
|
42
42
|
corrector.remove(range)
|
43
43
|
|
@@ -22,19 +22,23 @@ module RuboCop
|
|
22
22
|
# User.find_by(name: name, email: email)
|
23
23
|
# User.find_by!(email: email)
|
24
24
|
#
|
25
|
-
# @example AllowedMethods: find_by_sql
|
25
|
+
# @example AllowedMethods: ['find_by_sql', 'find_by_token_for'] (default)
|
26
26
|
# # bad
|
27
27
|
# User.find_by_query(users_query)
|
28
|
+
# User.find_by_token_for(:password_reset, token)
|
28
29
|
#
|
29
30
|
# # good
|
30
31
|
# User.find_by_sql(users_sql)
|
32
|
+
# User.find_by_token_for(:password_reset, token)
|
31
33
|
#
|
32
|
-
# @example AllowedReceivers: Gem::Specification
|
34
|
+
# @example AllowedReceivers: ['Gem::Specification', 'page'] (default)
|
33
35
|
# # bad
|
34
36
|
# Specification.find_by_name('backend').gem_dir
|
37
|
+
# page.find_by_id('a_dom_id').click
|
35
38
|
#
|
36
39
|
# # good
|
37
40
|
# Gem::Specification.find_by_name('backend').gem_dir
|
41
|
+
# page.find_by_id('a_dom_id').click
|
38
42
|
class DynamicFindBy < Base
|
39
43
|
include ActiveRecordHelper
|
40
44
|
extend AutoCorrector
|
@@ -70,8 +74,7 @@ module RuboCop
|
|
70
74
|
end
|
71
75
|
|
72
76
|
def allowed_invocation?(node)
|
73
|
-
allowed_method?(node) || allowed_receiver?(node) ||
|
74
|
-
whitelisted?(node)
|
77
|
+
allowed_method?(node) || allowed_receiver?(node) || whitelisted?(node)
|
75
78
|
end
|
76
79
|
|
77
80
|
def allowed_method?(node)
|
@@ -95,8 +98,7 @@ module RuboCop
|
|
95
98
|
end
|
96
99
|
|
97
100
|
def autocorrect_method_name(corrector, node)
|
98
|
-
corrector.replace(node.loc.selector,
|
99
|
-
static_method_name(node.method_name.to_s))
|
101
|
+
corrector.replace(node.loc.selector, static_method_name(node.method_name.to_s))
|
100
102
|
end
|
101
103
|
|
102
104
|
def autocorrect_argument_keywords(corrector, node, keywords)
|
@@ -20,8 +20,7 @@ module RuboCop
|
|
20
20
|
class EnumUniqueness < Base
|
21
21
|
include Duplication
|
22
22
|
|
23
|
-
MSG = 'Duplicate value `%<value>s` found in `%<enum>s` '
|
24
|
-
'enum declaration.'
|
23
|
+
MSG = 'Duplicate value `%<value>s` found in `%<enum>s` enum declaration.'
|
25
24
|
RESTRICT_ON_SEND = %i[enum].freeze
|
26
25
|
|
27
26
|
def_node_matcher :enum?, <<~PATTERN
|
@@ -41,9 +40,7 @@ module RuboCop
|
|
41
40
|
next unless duplicates?(items)
|
42
41
|
|
43
42
|
consecutive_duplicates(items).each do |item|
|
44
|
-
add_offense(item, message: format(
|
45
|
-
MSG, value: item.source, enum: enum_name(key)
|
46
|
-
))
|
43
|
+
add_offense(item, message: format(MSG, value: item.source, enum: enum_name(key)))
|
47
44
|
end
|
48
45
|
end
|
49
46
|
end
|
@@ -96,8 +96,7 @@ module RuboCop
|
|
96
96
|
end
|
97
97
|
|
98
98
|
def rails_env_on_lhs?(node)
|
99
|
-
comparing_str_env_with_rails_env_on_lhs?(node) ||
|
100
|
-
comparing_sym_env_with_rails_env_on_lhs?(node)
|
99
|
+
comparing_str_env_with_rails_env_on_lhs?(node) || comparing_sym_env_with_rails_env_on_lhs?(node)
|
101
100
|
end
|
102
101
|
|
103
102
|
def build_predicate_method_for_rails_env_on_lhs(node)
|
@@ -50,8 +50,7 @@ module RuboCop
|
|
50
50
|
return unless node.children.last.str_type?
|
51
51
|
|
52
52
|
last_child_source = node.children.last.source
|
53
|
-
return unless last_child_source.start_with?('.') ||
|
54
|
-
last_child_source.include?(File::SEPARATOR)
|
53
|
+
return unless last_child_source.start_with?('.') || last_child_source.include?(File::SEPARATOR)
|
55
54
|
return if last_child_source.start_with?(':')
|
56
55
|
|
57
56
|
register_offense(node)
|
@@ -97,8 +96,7 @@ module RuboCop
|
|
97
96
|
|
98
97
|
def register_offense(node)
|
99
98
|
line_range = node.loc.column...node.loc.last_column
|
100
|
-
source_range = source_range(processed_source.buffer, node.first_line,
|
101
|
-
line_range)
|
99
|
+
source_range = source_range(processed_source.buffer, node.first_line, line_range)
|
102
100
|
add_offense(source_range)
|
103
101
|
end
|
104
102
|
|
@@ -13,11 +13,17 @@ module RuboCop
|
|
13
13
|
# # good
|
14
14
|
# User.all.find_each
|
15
15
|
#
|
16
|
-
# @example
|
16
|
+
# @example AllowedMethods: ['order']
|
17
|
+
# # good
|
18
|
+
# User.order(:foo).each
|
19
|
+
#
|
20
|
+
# @example AllowedPattern: ['order']
|
17
21
|
# # good
|
18
22
|
# User.order(:foo).each
|
19
23
|
class FindEach < Base
|
20
24
|
include ActiveRecordHelper
|
25
|
+
include AllowedMethods
|
26
|
+
include AllowedPattern
|
21
27
|
extend AutoCorrector
|
22
28
|
|
23
29
|
MSG = 'Use `find_each` instead of `each`.'
|
@@ -47,7 +53,7 @@ module RuboCop
|
|
47
53
|
|
48
54
|
method_chain = node.each_node(:send).map(&:method_name)
|
49
55
|
|
50
|
-
|
56
|
+
method_chain.any? { |method_name| allowed_method?(method_name) || matches_allowed_pattern?(method_name) }
|
51
57
|
end
|
52
58
|
|
53
59
|
def active_model_error_where?(node)
|
@@ -0,0 +1,74 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Rails
|
6
|
+
# Identifies usages of `travel_to` with an argument of the current time and
|
7
|
+
# change them to use `freeze_time` instead.
|
8
|
+
#
|
9
|
+
# @safety
|
10
|
+
# This cop’s autocorrection is unsafe because `freeze_time` just delegates to
|
11
|
+
# `travel_to` with a default `Time.now`, it is not strictly equivalent to `Time.now`
|
12
|
+
# if the argument of `travel_to` is the current time considering time zone.
|
13
|
+
#
|
14
|
+
# @example
|
15
|
+
# # bad
|
16
|
+
# travel_to(Time.now)
|
17
|
+
# travel_to(Time.new)
|
18
|
+
# travel_to(DateTime.now)
|
19
|
+
# travel_to(Time.current)
|
20
|
+
# travel_to(Time.zone.now)
|
21
|
+
# travel_to(Time.now.in_time_zone)
|
22
|
+
# travel_to(Time.current.to_time)
|
23
|
+
#
|
24
|
+
# # good
|
25
|
+
# freeze_time
|
26
|
+
#
|
27
|
+
class FreezeTime < Base
|
28
|
+
extend AutoCorrector
|
29
|
+
|
30
|
+
MSG = 'Use `freeze_time` instead of `travel_to`.'
|
31
|
+
NOW_METHODS = %i[now new current].freeze
|
32
|
+
CONV_METHODS = %i[to_time in_time_zone].freeze
|
33
|
+
RESTRICT_ON_SEND = %i[travel_to].freeze
|
34
|
+
|
35
|
+
# @!method time_now?(node)
|
36
|
+
def_node_matcher :time_now?, <<~PATTERN
|
37
|
+
(const nil? {:Time :DateTime})
|
38
|
+
PATTERN
|
39
|
+
|
40
|
+
# @!method zoned_time_now?(node)
|
41
|
+
def_node_matcher :zoned_time_now?, <<~PATTERN
|
42
|
+
(send (const nil? :Time) :zone)
|
43
|
+
PATTERN
|
44
|
+
|
45
|
+
def on_send(node)
|
46
|
+
child_node, method_name, time_argument = *node.first_argument&.children
|
47
|
+
return if time_argument || !child_node
|
48
|
+
return unless current_time?(child_node, method_name) || current_time_with_convert?(child_node, method_name)
|
49
|
+
|
50
|
+
add_offense(node) do |corrector|
|
51
|
+
last_argument = node.last_argument
|
52
|
+
freeze_time_method = last_argument.block_pass_type? ? "freeze_time(#{last_argument.source})" : 'freeze_time'
|
53
|
+
corrector.replace(node, freeze_time_method)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
private
|
58
|
+
|
59
|
+
def current_time?(node, method_name)
|
60
|
+
return false unless NOW_METHODS.include?(method_name)
|
61
|
+
|
62
|
+
node.send_type? ? zoned_time_now?(node) : time_now?(node)
|
63
|
+
end
|
64
|
+
|
65
|
+
def current_time_with_convert?(node, method_name)
|
66
|
+
return false unless CONV_METHODS.include?(method_name)
|
67
|
+
|
68
|
+
child_node, child_method_name = *node.children
|
69
|
+
current_time?(child_node, child_method_name)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
@@ -105,9 +105,7 @@ module RuboCop
|
|
105
105
|
|
106
106
|
return false unless node.parent
|
107
107
|
|
108
|
-
return true if contain_valid_options_in_with_options_block?(
|
109
|
-
node.parent.parent
|
110
|
-
)
|
108
|
+
return true if contain_valid_options_in_with_options_block?(node.parent.parent)
|
111
109
|
end
|
112
110
|
|
113
111
|
false
|
@@ -22,11 +22,8 @@ module RuboCop
|
|
22
22
|
extend AutoCorrector
|
23
23
|
extend TargetRailsVersion
|
24
24
|
|
25
|
-
MSG = 'Use keyword arguments instead of '
|
26
|
-
|
27
|
-
KEYWORD_ARGS = %i[
|
28
|
-
method params session body flash xhr as headers env to
|
29
|
-
].freeze
|
25
|
+
MSG = 'Use keyword arguments instead of positional arguments for http call: `%<verb>s`.'
|
26
|
+
KEYWORD_ARGS = %i[method params session body flash xhr as headers env to].freeze
|
30
27
|
ROUTING_METHODS = %i[draw routes].freeze
|
31
28
|
RESTRICT_ON_SEND = %i[get post put patch delete head].freeze
|
32
29
|
|
@@ -75,8 +72,7 @@ module RuboCop
|
|
75
72
|
return false if kwsplat_hash?(data)
|
76
73
|
|
77
74
|
data.each_pair.none? do |pair|
|
78
|
-
special_keyword_arg?(pair.key) ||
|
79
|
-
(format_arg?(pair.key) && data.pairs.one?)
|
75
|
+
special_keyword_arg?(pair.key) || (format_arg?(pair.key) && data.pairs.one?)
|
80
76
|
end
|
81
77
|
end
|
82
78
|
|
@@ -98,8 +94,7 @@ module RuboCop
|
|
98
94
|
return '' if data.hash_type? && data.empty?
|
99
95
|
|
100
96
|
hash_data = if data.hash_type?
|
101
|
-
format('{ %<data>s }',
|
102
|
-
data: data.pairs.map(&:source).join(', '))
|
97
|
+
format('{ %<data>s }', data: data.pairs.map(&:source).join(', '))
|
103
98
|
else
|
104
99
|
# user supplies an object,
|
105
100
|
# no need to surround with braces
|
@@ -12,6 +12,7 @@ module RuboCop
|
|
12
12
|
# render plain: 'foo/bar', status: 304
|
13
13
|
# redirect_to root_url, status: 301
|
14
14
|
# head 200
|
15
|
+
# get '/foobar', to: redirect('/foobar/baz', status: 301)
|
15
16
|
#
|
16
17
|
# # good
|
17
18
|
# render :foo, status: :ok
|
@@ -19,6 +20,7 @@ module RuboCop
|
|
19
20
|
# render plain: 'foo/bar', status: :not_modified
|
20
21
|
# redirect_to root_url, status: :moved_permanently
|
21
22
|
# head :ok
|
23
|
+
# get '/foobar', to: redirect('/foobar/baz', status: :moved_permanently)
|
22
24
|
#
|
23
25
|
# @example EnforcedStyle: numeric
|
24
26
|
# # bad
|
@@ -27,6 +29,7 @@ module RuboCop
|
|
27
29
|
# render plain: 'foo/bar', status: :not_modified
|
28
30
|
# redirect_to root_url, status: :moved_permanently
|
29
31
|
# head :ok
|
32
|
+
# get '/foobar', to: redirect('/foobar/baz', status: :moved_permanently)
|
30
33
|
#
|
31
34
|
# # good
|
32
35
|
# render :foo, status: 200
|
@@ -34,18 +37,20 @@ module RuboCop
|
|
34
37
|
# render plain: 'foo/bar', status: 304
|
35
38
|
# redirect_to root_url, status: 301
|
36
39
|
# head 200
|
40
|
+
# get '/foobar', to: redirect('/foobar/baz', status: 301)
|
37
41
|
#
|
38
42
|
class HttpStatus < Base
|
39
43
|
include ConfigurableEnforcedStyle
|
40
44
|
extend AutoCorrector
|
41
45
|
|
42
|
-
RESTRICT_ON_SEND = %i[render redirect_to head].freeze
|
46
|
+
RESTRICT_ON_SEND = %i[render redirect_to head redirect].freeze
|
43
47
|
|
44
48
|
def_node_matcher :http_status, <<~PATTERN
|
45
49
|
{
|
46
50
|
(send nil? {:render :redirect_to} _ $hash)
|
47
51
|
(send nil? {:render :redirect_to} $hash)
|
48
52
|
(send nil? :head ${int sym} ...)
|
53
|
+
(send nil? :redirect _ $hash)
|
49
54
|
}
|
50
55
|
PATTERN
|
51
56
|
|
@@ -84,10 +89,8 @@ module RuboCop
|
|
84
89
|
|
85
90
|
# :nodoc:
|
86
91
|
class SymbolicStyleChecker
|
87
|
-
MSG = 'Prefer `%<prefer>s` over `%<current>s` '
|
88
|
-
|
89
|
-
DEFAULT_MSG = 'Prefer `symbolic` over `numeric` ' \
|
90
|
-
'to define HTTP status code.'
|
92
|
+
MSG = 'Prefer `%<prefer>s` over `%<current>s` to define HTTP status code.'
|
93
|
+
DEFAULT_MSG = 'Prefer `symbolic` over `numeric` to define HTTP status code.'
|
91
94
|
|
92
95
|
attr_reader :node
|
93
96
|
|
@@ -118,17 +121,14 @@ module RuboCop
|
|
118
121
|
end
|
119
122
|
|
120
123
|
def custom_http_status_code?
|
121
|
-
node.int_type? &&
|
122
|
-
!::Rack::Utils::SYMBOL_TO_STATUS_CODE.value?(number)
|
124
|
+
node.int_type? && !::Rack::Utils::SYMBOL_TO_STATUS_CODE.value?(number)
|
123
125
|
end
|
124
126
|
end
|
125
127
|
|
126
128
|
# :nodoc:
|
127
129
|
class NumericStyleChecker
|
128
|
-
MSG = 'Prefer `%<prefer>s` over `%<current>s` '
|
129
|
-
|
130
|
-
DEFAULT_MSG = 'Prefer `numeric` over `symbolic` ' \
|
131
|
-
'to define HTTP status code.'
|
130
|
+
MSG = 'Prefer `%<prefer>s` over `%<current>s` to define HTTP status code.'
|
131
|
+
DEFAULT_MSG = 'Prefer `numeric` over `symbolic` to define HTTP status code.'
|
132
132
|
PERMITTED_STATUS = %i[error success missing redirect].freeze
|
133
133
|
|
134
134
|
attr_reader :node
|
@@ -0,0 +1,50 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Rails
|
6
|
+
# Looks for assignments of `ignored_columns` that may override previous
|
7
|
+
# assignments.
|
8
|
+
#
|
9
|
+
# Overwriting previous assignments is usually a mistake, since it will
|
10
|
+
# un-ignore the first set of columns. Since duplicate column names is not
|
11
|
+
# a problem, it is better to simply append to the list.
|
12
|
+
#
|
13
|
+
# @example
|
14
|
+
#
|
15
|
+
# # bad
|
16
|
+
# class User < ActiveRecord::Base
|
17
|
+
# self.ignored_columns = [:one]
|
18
|
+
# end
|
19
|
+
#
|
20
|
+
# # bad
|
21
|
+
# class User < ActiveRecord::Base
|
22
|
+
# self.ignored_columns = [:one, :two]
|
23
|
+
# end
|
24
|
+
#
|
25
|
+
# # good
|
26
|
+
# class User < ActiveRecord::Base
|
27
|
+
# self.ignored_columns += [:one, :two]
|
28
|
+
# end
|
29
|
+
#
|
30
|
+
# # good
|
31
|
+
# class User < ActiveRecord::Base
|
32
|
+
# self.ignored_columns += [:one]
|
33
|
+
# self.ignored_columns += [:two]
|
34
|
+
# end
|
35
|
+
#
|
36
|
+
class IgnoredColumnsAssignment < Base
|
37
|
+
extend AutoCorrector
|
38
|
+
|
39
|
+
MSG = 'Use `+=` instead of `=`.'
|
40
|
+
RESTRICT_ON_SEND = %i[ignored_columns=].freeze
|
41
|
+
|
42
|
+
def on_send(node)
|
43
|
+
add_offense(node.loc.operator) do |corrector|
|
44
|
+
corrector.replace(node.loc.operator, '+=')
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -42,12 +42,7 @@ module RuboCop
|
|
42
42
|
`%<ignore>s` option will be ignored when `%<prefer>s` and `%<ignore>s` are used together.
|
43
43
|
MSG
|
44
44
|
|
45
|
-
RESTRICT_ON_SEND = %i[
|
46
|
-
skip_after_action
|
47
|
-
skip_around_action
|
48
|
-
skip_before_action
|
49
|
-
skip_action_callback
|
50
|
-
].freeze
|
45
|
+
RESTRICT_ON_SEND = %i[skip_after_action skip_around_action skip_before_action skip_action_callback].freeze
|
51
46
|
|
52
47
|
FILTERS = RESTRICT_ON_SEND.map { |method_name| ":#{method_name}" }
|
53
48
|
|
@@ -67,11 +62,9 @@ module RuboCop
|
|
67
62
|
options = options_hash(options)
|
68
63
|
|
69
64
|
if if_and_only?(options)
|
70
|
-
add_offense(options[:if],
|
71
|
-
message: format(MSG, prefer: :only, ignore: :if))
|
65
|
+
add_offense(options[:if], message: format(MSG, prefer: :only, ignore: :if))
|
72
66
|
elsif if_and_except?(options)
|
73
|
-
add_offense(options[:except],
|
74
|
-
message: format(MSG, prefer: :if, ignore: :except))
|
67
|
+
add_offense(options[:except], message: format(MSG, prefer: :if, ignore: :except))
|
75
68
|
end
|
76
69
|
end
|
77
70
|
|
@@ -192,8 +192,7 @@ module RuboCop
|
|
192
192
|
end
|
193
193
|
return if options_ignoring_inverse_of?(options)
|
194
194
|
|
195
|
-
return unless scope?(arguments) ||
|
196
|
-
options_requiring_inverse_of?(options)
|
195
|
+
return unless scope?(arguments) || options_requiring_inverse_of?(options)
|
197
196
|
|
198
197
|
return if options_contain_inverse_of?(options)
|
199
198
|
|
@@ -206,8 +205,7 @@ module RuboCop
|
|
206
205
|
|
207
206
|
def options_requiring_inverse_of?(options)
|
208
207
|
required = options.any? do |opt|
|
209
|
-
conditions_option?(opt) ||
|
210
|
-
foreign_key_option?(opt)
|
208
|
+
conditions_option?(opt) || foreign_key_option?(opt)
|
211
209
|
end
|
212
210
|
|
213
211
|
return required if target_rails_version >= 5.2
|
@@ -227,8 +225,7 @@ module RuboCop
|
|
227
225
|
|
228
226
|
def with_options_arguments(recv, node)
|
229
227
|
blocks = node.each_ancestor(:block).select do |block|
|
230
|
-
block.send_node.command?(:with_options) &&
|
231
|
-
same_context_in_with_options?(block.arguments.first, recv)
|
228
|
+
block.send_node.command?(:with_options) && same_context_in_with_options?(block.arguments.first, recv)
|
232
229
|
end
|
233
230
|
blocks.flat_map { |n| n.send_node.arguments }
|
234
231
|
end
|