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 dynamic `find_by_*` methods.
|
7
7
|
# Use `find_by` instead of dynamic method.
|
8
8
|
# See. https://rails.rubystyle.guide#find_by
|
9
9
|
#
|
@@ -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
|
@@ -49,7 +53,7 @@ module RuboCop
|
|
49
53
|
method_name = node.method_name
|
50
54
|
static_name = static_method_name(method_name)
|
51
55
|
return unless static_name
|
52
|
-
return
|
56
|
+
return unless dynamic_find_by_arguments?(node)
|
53
57
|
|
54
58
|
message = format(MSG, static_name: static_name, method: method_name)
|
55
59
|
add_offense(node, message: message) do |corrector|
|
@@ -61,17 +65,12 @@ module RuboCop
|
|
61
65
|
private
|
62
66
|
|
63
67
|
def autocorrect(corrector, node)
|
64
|
-
keywords = column_keywords(node.method_name)
|
65
|
-
|
66
|
-
return if keywords.size != node.arguments.size
|
67
|
-
|
68
68
|
autocorrect_method_name(corrector, node)
|
69
|
-
autocorrect_argument_keywords(corrector, node,
|
69
|
+
autocorrect_argument_keywords(corrector, node, column_keywords(node.method_name))
|
70
70
|
end
|
71
71
|
|
72
72
|
def allowed_invocation?(node)
|
73
|
-
allowed_method?(node) || allowed_receiver?(node) ||
|
74
|
-
whitelisted?(node)
|
73
|
+
allowed_method?(node) || allowed_receiver?(node) || whitelisted?(node)
|
75
74
|
end
|
76
75
|
|
77
76
|
def allowed_method?(node)
|
@@ -95,13 +94,12 @@ module RuboCop
|
|
95
94
|
end
|
96
95
|
|
97
96
|
def autocorrect_method_name(corrector, node)
|
98
|
-
corrector.replace(node.loc.selector,
|
99
|
-
static_method_name(node.method_name.to_s))
|
97
|
+
corrector.replace(node.loc.selector, static_method_name(node.method_name.to_s))
|
100
98
|
end
|
101
99
|
|
102
100
|
def autocorrect_argument_keywords(corrector, node, keywords)
|
103
101
|
keywords.each.with_index do |keyword, idx|
|
104
|
-
corrector.insert_before(node.arguments[idx]
|
102
|
+
corrector.insert_before(node.arguments[idx], keyword)
|
105
103
|
end
|
106
104
|
end
|
107
105
|
|
@@ -118,6 +116,20 @@ module RuboCop
|
|
118
116
|
|
119
117
|
match[2] ? 'find_by!' : 'find_by'
|
120
118
|
end
|
119
|
+
|
120
|
+
def dynamic_find_by_arguments?(node)
|
121
|
+
dynamic_find_by_arguments_count?(node) && dynamic_find_by_arguments_type?(node)
|
122
|
+
end
|
123
|
+
|
124
|
+
def dynamic_find_by_arguments_count?(node)
|
125
|
+
column_keywords(node.method_name).size == node.arguments.size
|
126
|
+
end
|
127
|
+
|
128
|
+
def dynamic_find_by_arguments_type?(node)
|
129
|
+
node.arguments.none? do |argument|
|
130
|
+
IGNORED_ARGUMENT_TYPES.include?(argument.type)
|
131
|
+
end
|
132
|
+
end
|
121
133
|
end
|
122
134
|
end
|
123
135
|
end
|
@@ -3,7 +3,7 @@
|
|
3
3
|
module RuboCop
|
4
4
|
module Cop
|
5
5
|
module Rails
|
6
|
-
#
|
6
|
+
# Checks that blocks are used for interpolated strings passed to
|
7
7
|
# `Rails.logger.debug`.
|
8
8
|
#
|
9
9
|
# By default, Rails production environments use the `:info` log level.
|
@@ -37,6 +37,10 @@ module RuboCop
|
|
37
37
|
)
|
38
38
|
PATTERN
|
39
39
|
|
40
|
+
def self.autocorrect_incompatible_with
|
41
|
+
[Style::MethodCallWithArgsParentheses]
|
42
|
+
end
|
43
|
+
|
40
44
|
def on_send(node)
|
41
45
|
return if node.parent&.block_type?
|
42
46
|
|
@@ -55,7 +59,7 @@ module RuboCop
|
|
55
59
|
private
|
56
60
|
|
57
61
|
def replacement_range(node)
|
58
|
-
stop = node.
|
62
|
+
stop = node.source_range.end
|
59
63
|
start = node.loc.selector.end
|
60
64
|
|
61
65
|
if node.parenthesized_call?
|
@@ -3,7 +3,7 @@
|
|
3
3
|
module RuboCop
|
4
4
|
module Cop
|
5
5
|
module Rails
|
6
|
-
#
|
6
|
+
# Looks for enums written with array syntax.
|
7
7
|
#
|
8
8
|
# When using array syntax, adding an element in a
|
9
9
|
# position other than the last causes all previous
|
@@ -20,8 +20,7 @@ module RuboCop
|
|
20
20
|
class EnumHash < Base
|
21
21
|
extend AutoCorrector
|
22
22
|
|
23
|
-
MSG = 'Enum defined as an array found in `%<enum>s` enum declaration. '
|
24
|
-
'Use hash syntax instead.'
|
23
|
+
MSG = 'Enum defined as an array found in `%<enum>s` enum declaration. Use hash syntax instead.'
|
25
24
|
RESTRICT_ON_SEND = %i[enum].freeze
|
26
25
|
|
27
26
|
def_node_matcher :enum?, <<~PATTERN
|
@@ -43,7 +42,7 @@ module RuboCop
|
|
43
42
|
"#{source(elem)} => #{index}"
|
44
43
|
end.join(', ')
|
45
44
|
|
46
|
-
corrector.replace(array
|
45
|
+
corrector.replace(array, "{#{hash}}")
|
47
46
|
end
|
48
47
|
end
|
49
48
|
end
|
@@ -3,7 +3,7 @@
|
|
3
3
|
module RuboCop
|
4
4
|
module Cop
|
5
5
|
module Rails
|
6
|
-
#
|
6
|
+
# Looks for duplicate values in enum declarations.
|
7
7
|
#
|
8
8
|
# @example
|
9
9
|
# # bad
|
@@ -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
|
@@ -3,7 +3,7 @@
|
|
3
3
|
module RuboCop
|
4
4
|
module Cop
|
5
5
|
module Rails
|
6
|
-
#
|
6
|
+
# Checks that Rails.env is compared using `.production?`-like
|
7
7
|
# methods instead of equality against a string or symbol.
|
8
8
|
#
|
9
9
|
# @example
|
@@ -84,7 +84,7 @@ module RuboCop
|
|
84
84
|
def autocorrect(corrector, node)
|
85
85
|
replacement = build_predicate_method(node)
|
86
86
|
|
87
|
-
corrector.replace(node
|
87
|
+
corrector.replace(node, replacement)
|
88
88
|
end
|
89
89
|
|
90
90
|
def build_predicate_method(node)
|
@@ -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)
|
@@ -3,7 +3,7 @@
|
|
3
3
|
module RuboCop
|
4
4
|
module Cop
|
5
5
|
module Rails
|
6
|
-
#
|
6
|
+
# Looks for direct access to environment variables through the
|
7
7
|
# `ENV` variable within the application code. This can lead to runtime
|
8
8
|
# errors due to misconfiguration that could have been discovered at boot
|
9
9
|
# time if the environment variables were loaded as part of initialization
|
@@ -3,7 +3,7 @@
|
|
3
3
|
module RuboCop
|
4
4
|
module Cop
|
5
5
|
module Rails
|
6
|
-
#
|
6
|
+
# Enforces that `exit` calls are not used within a rails app.
|
7
7
|
# Valid options are instead to raise an error, break, return, or some
|
8
8
|
# other form of stopping execution of current request.
|
9
9
|
#
|
@@ -3,7 +3,7 @@
|
|
3
3
|
module RuboCop
|
4
4
|
module Cop
|
5
5
|
module Rails
|
6
|
-
#
|
6
|
+
# Checks for expanded date range. It only compatible `..` range is targeted.
|
7
7
|
# Incompatible `...` range is ignored.
|
8
8
|
#
|
9
9
|
# @example
|
@@ -29,14 +29,6 @@ module RuboCop
|
|
29
29
|
|
30
30
|
minimum_target_rails_version 5.1
|
31
31
|
|
32
|
-
def_node_matcher :expanded_date_range, <<~PATTERN
|
33
|
-
(irange
|
34
|
-
(send
|
35
|
-
$_ {:beginning_of_day :beginning_of_week :beginning_of_month :beginning_of_quarter :beginning_of_year})
|
36
|
-
(send
|
37
|
-
$_ {:end_of_day :end_of_week :end_of_month :end_of_quarter :end_of_year}))
|
38
|
-
PATTERN
|
39
|
-
|
40
32
|
PREFERRED_METHODS = {
|
41
33
|
beginning_of_day: 'all_day',
|
42
34
|
beginning_of_week: 'all_week',
|
@@ -54,31 +46,55 @@ module RuboCop
|
|
54
46
|
}.freeze
|
55
47
|
|
56
48
|
def on_irange(node)
|
57
|
-
return unless expanded_date_range(node)
|
58
|
-
|
59
49
|
begin_node = node.begin
|
60
50
|
end_node = node.end
|
61
|
-
return
|
62
|
-
|
63
|
-
beginning_method = begin_node.method_name
|
64
|
-
end_method = end_node.method_name
|
65
|
-
return unless use_mapped_methods?(beginning_method, end_method)
|
51
|
+
return if allow?(begin_node, end_node)
|
66
52
|
|
67
|
-
preferred_method =
|
53
|
+
preferred_method = preferred_method(begin_node)
|
54
|
+
if begin_node.method?(:beginning_of_week) && begin_node.arguments.one?
|
55
|
+
return unless same_argument?(begin_node, end_node)
|
68
56
|
|
69
|
-
|
70
|
-
|
57
|
+
preferred_method << "(#{begin_node.first_argument.source})"
|
58
|
+
elsif any_arguments?(begin_node, end_node)
|
59
|
+
return
|
71
60
|
end
|
61
|
+
|
62
|
+
register_offense(node, preferred_method)
|
72
63
|
end
|
73
64
|
|
74
65
|
private
|
75
66
|
|
76
|
-
def
|
77
|
-
|
67
|
+
def allow?(begin_node, end_node)
|
68
|
+
return true unless (begin_source = receiver_source(begin_node))
|
69
|
+
return true unless (end_source = receiver_source(end_node))
|
70
|
+
|
71
|
+
begin_source != end_source || MAPPED_DATE_RANGE_METHODS[begin_node.method_name] != end_node.method_name
|
72
|
+
end
|
73
|
+
|
74
|
+
def receiver_source(node)
|
75
|
+
return if !node&.send_type? || node.receiver.nil?
|
76
|
+
|
77
|
+
node.receiver.source
|
78
78
|
end
|
79
79
|
|
80
|
-
def
|
81
|
-
|
80
|
+
def same_argument?(begin_node, end_node)
|
81
|
+
begin_node.first_argument.source == end_node.first_argument.source
|
82
|
+
end
|
83
|
+
|
84
|
+
def preferred_method(begin_node)
|
85
|
+
+"#{begin_node.receiver.source}.#{PREFERRED_METHODS[begin_node.method_name]}"
|
86
|
+
end
|
87
|
+
|
88
|
+
def any_arguments?(begin_node, end_node)
|
89
|
+
begin_node.arguments.any? || end_node.arguments.any?
|
90
|
+
end
|
91
|
+
|
92
|
+
def register_offense(node, preferred_method)
|
93
|
+
message = format(MSG, preferred_method: preferred_method)
|
94
|
+
|
95
|
+
add_offense(node, message: message) do |corrector|
|
96
|
+
corrector.replace(node, preferred_method)
|
97
|
+
end
|
82
98
|
end
|
83
99
|
end
|
84
100
|
end
|
@@ -3,55 +3,66 @@
|
|
3
3
|
module RuboCop
|
4
4
|
module Cop
|
5
5
|
module Rails
|
6
|
-
#
|
7
|
-
#
|
8
|
-
# joining paths.
|
6
|
+
# Identifies usages of file path joining process to use `Rails.root.join` clause.
|
7
|
+
# It is used to add uniformity when joining paths.
|
9
8
|
#
|
10
|
-
# @example EnforcedStyle:
|
9
|
+
# @example EnforcedStyle: slashes (default)
|
11
10
|
# # bad
|
11
|
+
# Rails.root.join('app', 'models', 'goober')
|
12
|
+
#
|
13
|
+
# # good
|
12
14
|
# Rails.root.join('app/models/goober')
|
15
|
+
#
|
16
|
+
# # bad
|
13
17
|
# File.join(Rails.root, 'app/models/goober')
|
14
18
|
# "#{Rails.root}/app/models/goober"
|
15
19
|
#
|
16
20
|
# # good
|
17
|
-
# Rails.root.join('app
|
21
|
+
# Rails.root.join('app/models/goober').to_s
|
18
22
|
#
|
19
|
-
# @example EnforcedStyle:
|
23
|
+
# @example EnforcedStyle: arguments
|
20
24
|
# # bad
|
25
|
+
# Rails.root.join('app/models/goober')
|
26
|
+
#
|
27
|
+
# # good
|
21
28
|
# Rails.root.join('app', 'models', 'goober')
|
29
|
+
#
|
30
|
+
# # bad
|
22
31
|
# File.join(Rails.root, 'app/models/goober')
|
23
32
|
# "#{Rails.root}/app/models/goober"
|
24
33
|
#
|
25
34
|
# # good
|
26
|
-
# Rails.root.join('app
|
35
|
+
# Rails.root.join('app', 'models', 'goober').to_s
|
27
36
|
#
|
28
37
|
class FilePath < Base
|
29
38
|
include ConfigurableEnforcedStyle
|
30
39
|
include RangeHelp
|
31
40
|
|
32
|
-
MSG_SLASHES = 'Prefer `Rails.root.join(\'path/to\')`.'
|
33
|
-
MSG_ARGUMENTS = 'Prefer `Rails.root.join(\'path\', \'to\')`.'
|
41
|
+
MSG_SLASHES = 'Prefer `Rails.root.join(\'path/to\')%<to_s>s`.'
|
42
|
+
MSG_ARGUMENTS = 'Prefer `Rails.root.join(\'path\', \'to\')%<to_s>s`.'
|
34
43
|
RESTRICT_ON_SEND = %i[join].freeze
|
35
44
|
|
36
45
|
def_node_matcher :file_join_nodes?, <<~PATTERN
|
37
|
-
(send (const nil? :File) :join ...)
|
46
|
+
(send (const {nil? cbase} :File) :join ...)
|
38
47
|
PATTERN
|
39
48
|
|
40
49
|
def_node_search :rails_root_nodes?, <<~PATTERN
|
41
|
-
(send (const nil? :Rails) :root)
|
50
|
+
(send (const {nil? cbase} :Rails) :root)
|
42
51
|
PATTERN
|
43
52
|
|
44
53
|
def_node_matcher :rails_root_join_nodes?, <<~PATTERN
|
45
|
-
(send
|
54
|
+
(send #rails_root_nodes? :join ...)
|
46
55
|
PATTERN
|
47
56
|
|
48
57
|
def on_dstr(node)
|
49
58
|
return unless rails_root_nodes?(node)
|
50
59
|
return unless node.children.last.str_type?
|
51
|
-
return unless node.children.last.source.start_with?('.') ||
|
52
|
-
node.children.last.source.include?(File::SEPARATOR)
|
53
60
|
|
54
|
-
|
61
|
+
last_child_source = node.children.last.source
|
62
|
+
return unless last_child_source.start_with?('.') || last_child_source.include?(File::SEPARATOR)
|
63
|
+
return if last_child_source.start_with?(':')
|
64
|
+
|
65
|
+
register_offense(node, require_to_s: true)
|
55
66
|
end
|
56
67
|
|
57
68
|
def on_send(node)
|
@@ -66,7 +77,7 @@ module RuboCop
|
|
66
77
|
return unless file_join_nodes?(node)
|
67
78
|
return unless node.arguments.any? { |e| rails_root_nodes?(e) }
|
68
79
|
|
69
|
-
register_offense(node)
|
80
|
+
register_offense(node, require_to_s: true)
|
70
81
|
end
|
71
82
|
|
72
83
|
def check_for_rails_root_join_with_string_arguments(node)
|
@@ -76,7 +87,7 @@ module RuboCop
|
|
76
87
|
return unless node.arguments.size > 1
|
77
88
|
return unless node.arguments.all?(&:str_type?)
|
78
89
|
|
79
|
-
register_offense(node)
|
90
|
+
register_offense(node, require_to_s: false)
|
80
91
|
end
|
81
92
|
|
82
93
|
def check_for_rails_root_join_with_slash_separated_path(node)
|
@@ -85,22 +96,28 @@ module RuboCop
|
|
85
96
|
return unless rails_root_join_nodes?(node)
|
86
97
|
return unless node.arguments.any? { |arg| string_with_slash?(arg) }
|
87
98
|
|
88
|
-
register_offense(node)
|
99
|
+
register_offense(node, require_to_s: false)
|
89
100
|
end
|
90
101
|
|
91
102
|
def string_with_slash?(node)
|
92
103
|
node.str_type? && node.source.include?('/')
|
93
104
|
end
|
94
105
|
|
95
|
-
def register_offense(node)
|
106
|
+
def register_offense(node, require_to_s:)
|
96
107
|
line_range = node.loc.column...node.loc.last_column
|
97
|
-
source_range = source_range(processed_source.buffer, node.first_line,
|
98
|
-
|
99
|
-
|
108
|
+
source_range = source_range(processed_source.buffer, node.first_line, line_range)
|
109
|
+
require_to_s = false if node.dstr_type?
|
110
|
+
|
111
|
+
message = build_message(require_to_s)
|
112
|
+
|
113
|
+
add_offense(source_range, message: message)
|
100
114
|
end
|
101
115
|
|
102
|
-
def
|
103
|
-
|
116
|
+
def build_message(require_to_s)
|
117
|
+
message_template = style == :arguments ? MSG_ARGUMENTS : MSG_SLASHES
|
118
|
+
to_s = require_to_s ? '.to_s' : ''
|
119
|
+
|
120
|
+
format(message_template, to_s: to_s)
|
104
121
|
end
|
105
122
|
end
|
106
123
|
end
|
@@ -3,7 +3,7 @@
|
|
3
3
|
module RuboCop
|
4
4
|
module Cop
|
5
5
|
module Rails
|
6
|
-
#
|
6
|
+
# Identifies usages of `where.take` and change them to use `find_by` instead.
|
7
7
|
#
|
8
8
|
# And `where(...).first` can return different results from `find_by`.
|
9
9
|
# (They order records differently, so the "first" record can be different.)
|
@@ -3,7 +3,7 @@
|
|
3
3
|
module RuboCop
|
4
4
|
module Cop
|
5
5
|
module Rails
|
6
|
-
#
|
6
|
+
# Enforces that `ActiveRecord#find` is used instead of
|
7
7
|
# `where.take!`, `find_by!`, and `find_by_id!` to retrieve a single record
|
8
8
|
# by primary key when you expect it to be found.
|
9
9
|
#
|
@@ -65,11 +65,11 @@ module RuboCop
|
|
65
65
|
end
|
66
66
|
|
67
67
|
def where_take_offense_range(node, where)
|
68
|
-
range_between(where.loc.selector.begin_pos, node.
|
68
|
+
range_between(where.loc.selector.begin_pos, node.source_range.end_pos)
|
69
69
|
end
|
70
70
|
|
71
71
|
def find_by_offense_range(node)
|
72
|
-
range_between(node.loc.selector.begin_pos, node.
|
72
|
+
range_between(node.loc.selector.begin_pos, node.source_range.end_pos)
|
73
73
|
end
|
74
74
|
|
75
75
|
def build_good_method(id_value)
|
@@ -3,8 +3,12 @@
|
|
3
3
|
module RuboCop
|
4
4
|
module Cop
|
5
5
|
module Rails
|
6
|
-
#
|
7
|
-
#
|
6
|
+
# Identifies usages of `all.each` and change them to use `all.find_each` instead.
|
7
|
+
#
|
8
|
+
# @safety
|
9
|
+
# This cop is unsafe if the receiver object is not an Active Record object.
|
10
|
+
# Also, `all.each` returns an `Array` instance and `all.find_each` returns nil,
|
11
|
+
# so the return values are different.
|
8
12
|
#
|
9
13
|
# @example
|
10
14
|
# # bad
|
@@ -13,11 +17,17 @@ module RuboCop
|
|
13
17
|
# # good
|
14
18
|
# User.all.find_each
|
15
19
|
#
|
16
|
-
# @example
|
20
|
+
# @example AllowedMethods: ['order']
|
21
|
+
# # good
|
22
|
+
# User.order(:foo).each
|
23
|
+
#
|
24
|
+
# @example AllowedPattern: ['order']
|
17
25
|
# # good
|
18
26
|
# User.order(:foo).each
|
19
27
|
class FindEach < Base
|
20
28
|
include ActiveRecordHelper
|
29
|
+
include AllowedMethods
|
30
|
+
include AllowedPattern
|
21
31
|
extend AutoCorrector
|
22
32
|
|
23
33
|
MSG = 'Use `find_each` instead of `each`.'
|
@@ -47,7 +57,7 @@ module RuboCop
|
|
47
57
|
|
48
58
|
method_chain = node.each_node(:send).map(&:method_name)
|
49
59
|
|
50
|
-
|
60
|
+
method_chain.any? { |method_name| allowed_method?(method_name) || matches_allowed_pattern?(method_name) }
|
51
61
|
end
|
52
62
|
|
53
63
|
def active_model_error_where?(node)
|
@@ -0,0 +1,79 @@
|
|
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
|
+
extend TargetRailsVersion
|
30
|
+
|
31
|
+
minimum_target_rails_version 5.2
|
32
|
+
|
33
|
+
MSG = 'Use `freeze_time` instead of `travel_to`.'
|
34
|
+
NOW_METHODS = %i[now new current].freeze
|
35
|
+
CONVERT_METHODS = %i[to_time in_time_zone].freeze
|
36
|
+
RESTRICT_ON_SEND = %i[travel_to].freeze
|
37
|
+
|
38
|
+
# @!method time_now?(node)
|
39
|
+
def_node_matcher :time_now?, <<~PATTERN
|
40
|
+
(const {nil? cbase} {:Time :DateTime})
|
41
|
+
PATTERN
|
42
|
+
|
43
|
+
# @!method zoned_time_now?(node)
|
44
|
+
def_node_matcher :zoned_time_now?, <<~PATTERN
|
45
|
+
(send (const {nil? cbase} :Time) :zone)
|
46
|
+
PATTERN
|
47
|
+
|
48
|
+
def on_send(node)
|
49
|
+
child_node, method_name, time_argument = *node.first_argument&.children
|
50
|
+
return if time_argument || !child_node
|
51
|
+
return unless current_time?(child_node, method_name) || current_time_with_convert?(child_node, method_name)
|
52
|
+
|
53
|
+
add_offense(node) do |corrector|
|
54
|
+
last_argument = node.last_argument
|
55
|
+
freeze_time_method = last_argument.block_pass_type? ? "freeze_time(#{last_argument.source})" : 'freeze_time'
|
56
|
+
corrector.replace(node, freeze_time_method)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
private
|
61
|
+
|
62
|
+
def current_time?(node, method_name)
|
63
|
+
return false unless NOW_METHODS.include?(method_name)
|
64
|
+
|
65
|
+
node.send_type? ? zoned_time_now?(node) : time_now?(node)
|
66
|
+
end
|
67
|
+
|
68
|
+
def current_time_with_convert?(node, method_name)
|
69
|
+
return false unless CONVERT_METHODS.include?(method_name)
|
70
|
+
|
71
|
+
child_node, child_method_name, time_argument = *node.children
|
72
|
+
return if time_argument
|
73
|
+
|
74
|
+
current_time?(child_node, child_method_name)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|