rubocop-rails 2.8.1 → 2.9.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/README.md +16 -0
- data/config/default.yml +33 -1
- data/lib/rubocop/cop/mixin/active_record_helper.rb +4 -3
- data/lib/rubocop/cop/mixin/enforce_superclass.rb +40 -0
- data/lib/rubocop/cop/mixin/index_method.rb +8 -11
- data/lib/rubocop/cop/rails/action_filter.rb +10 -14
- data/lib/rubocop/cop/rails/active_record_aliases.rb +13 -17
- data/lib/rubocop/cop/rails/active_record_callbacks_order.rb +17 -12
- data/lib/rubocop/cop/rails/active_record_override.rb +1 -1
- data/lib/rubocop/cop/rails/active_support_aliases.rb +12 -21
- data/lib/rubocop/cop/rails/after_commit_override.rb +1 -1
- data/lib/rubocop/cop/rails/application_controller.rb +3 -7
- data/lib/rubocop/cop/rails/application_job.rb +2 -1
- data/lib/rubocop/cop/rails/application_mailer.rb +2 -7
- data/lib/rubocop/cop/rails/application_record.rb +2 -7
- data/lib/rubocop/cop/rails/arel_star.rb +41 -0
- data/lib/rubocop/cop/rails/assert_not.rb +8 -10
- data/lib/rubocop/cop/rails/attribute_default_block_value.rb +90 -0
- data/lib/rubocop/cop/rails/belongs_to.rb +9 -18
- data/lib/rubocop/cop/rails/blank.rb +27 -27
- data/lib/rubocop/cop/rails/bulk_change_table.rb +1 -1
- data/lib/rubocop/cop/rails/content_tag.rb +16 -16
- data/lib/rubocop/cop/rails/create_table_with_timestamps.rb +2 -1
- data/lib/rubocop/cop/rails/date.rb +10 -11
- data/lib/rubocop/cop/rails/default_scope.rb +11 -4
- data/lib/rubocop/cop/rails/delegate.rb +9 -9
- data/lib/rubocop/cop/rails/delegate_allow_blank.rb +7 -8
- data/lib/rubocop/cop/rails/dynamic_find_by.rb +12 -11
- data/lib/rubocop/cop/rails/enum_hash.rb +11 -10
- data/lib/rubocop/cop/rails/enum_uniqueness.rb +2 -1
- data/lib/rubocop/cop/rails/environment_comparison.rb +18 -14
- data/lib/rubocop/cop/rails/exit.rb +4 -10
- data/lib/rubocop/cop/rails/file_path.rb +4 -3
- data/lib/rubocop/cop/rails/find_by.rb +13 -13
- data/lib/rubocop/cop/rails/find_by_id.rb +12 -21
- data/lib/rubocop/cop/rails/find_each.rb +16 -14
- data/lib/rubocop/cop/rails/has_and_belongs_to_many.rb +3 -2
- data/lib/rubocop/cop/rails/has_many_or_has_one_dependent.rb +3 -2
- data/lib/rubocop/cop/rails/helper_instance_variable.rb +2 -2
- data/lib/rubocop/cop/rails/http_positional_arguments.rb +19 -21
- data/lib/rubocop/cop/rails/http_status.rb +7 -9
- data/lib/rubocop/cop/rails/ignored_skip_action_filter_option.rb +8 -6
- data/lib/rubocop/cop/rails/index_by.rb +2 -1
- data/lib/rubocop/cop/rails/index_with.rb +2 -1
- data/lib/rubocop/cop/rails/inquiry.rb +4 -3
- data/lib/rubocop/cop/rails/inverse_of.rb +3 -2
- data/lib/rubocop/cop/rails/lexically_scoped_action_filter.rb +17 -15
- data/lib/rubocop/cop/rails/link_to_blank.rb +20 -22
- data/lib/rubocop/cop/rails/mailer_name.rb +19 -13
- data/lib/rubocop/cop/rails/match_route.rb +14 -13
- data/lib/rubocop/cop/rails/negate_include.rb +10 -8
- data/lib/rubocop/cop/rails/not_null_column.rb +2 -1
- data/lib/rubocop/cop/rails/order_by_id.rb +1 -2
- data/lib/rubocop/cop/rails/output.rb +5 -2
- data/lib/rubocop/cop/rails/output_safety.rb +3 -2
- data/lib/rubocop/cop/rails/pick.rb +14 -12
- data/lib/rubocop/cop/rails/pluck.rb +6 -9
- data/lib/rubocop/cop/rails/pluck_id.rb +4 -6
- data/lib/rubocop/cop/rails/pluck_in_where.rb +7 -7
- data/lib/rubocop/cop/rails/pluralization_grammar.rb +10 -14
- data/lib/rubocop/cop/rails/presence.rb +12 -13
- data/lib/rubocop/cop/rails/present.rb +30 -24
- data/lib/rubocop/cop/rails/rake_environment.rb +8 -10
- data/lib/rubocop/cop/rails/read_write_attribute.rb +12 -11
- data/lib/rubocop/cop/rails/redundant_allow_nil.rb +29 -31
- data/lib/rubocop/cop/rails/redundant_foreign_key.rb +9 -12
- data/lib/rubocop/cop/rails/redundant_receiver_in_with_options.rb +11 -10
- data/lib/rubocop/cop/rails/reflection_class_name.rb +3 -2
- data/lib/rubocop/cop/rails/refute_methods.rb +9 -10
- data/lib/rubocop/cop/rails/relative_date_constant.rb +16 -8
- data/lib/rubocop/cop/rails/render_inline.rb +2 -1
- data/lib/rubocop/cop/rails/render_plain_text.rb +9 -14
- data/lib/rubocop/cop/rails/request_referer.rb +7 -7
- data/lib/rubocop/cop/rails/reversible_migration.rb +2 -6
- data/lib/rubocop/cop/rails/safe_navigation.rb +11 -10
- data/lib/rubocop/cop/rails/safe_navigation_with_blank.rb +5 -10
- data/lib/rubocop/cop/rails/save_bang.rb +17 -20
- data/lib/rubocop/cop/rails/scope_args.rb +2 -1
- data/lib/rubocop/cop/rails/short_i18n.rb +7 -9
- data/lib/rubocop/cop/rails/skips_model_validations.rb +4 -4
- data/lib/rubocop/cop/rails/squished_sql_heredocs.rb +5 -6
- data/lib/rubocop/cop/rails/time_zone.rb +22 -20
- data/lib/rubocop/cop/rails/uniq_before_pluck.rb +4 -6
- data/lib/rubocop/cop/rails/unique_validation_without_index.rb +2 -2
- data/lib/rubocop/cop/rails/unknown_env.rb +2 -2
- data/lib/rubocop/cop/rails/validation.rb +15 -14
- data/lib/rubocop/cop/rails/where_equals.rb +94 -0
- data/lib/rubocop/cop/rails/where_exists.rb +8 -13
- data/lib/rubocop/cop/rails/where_not.rb +5 -16
- data/lib/rubocop/cop/rails_cops.rb +4 -0
- data/lib/rubocop/rails/schema_loader.rb +4 -4
- data/lib/rubocop/rails/schema_loader/schema.rb +1 -1
- data/lib/rubocop/rails/version.rb +5 -1
- metadata +19 -9
@@ -40,8 +40,9 @@ module RuboCop
|
|
40
40
|
#
|
41
41
|
# t.datetime :updated_at, default: -> { 'CURRENT_TIMESTAMP' }
|
42
42
|
# end
|
43
|
-
class CreateTableWithTimestamps <
|
43
|
+
class CreateTableWithTimestamps < Base
|
44
44
|
MSG = 'Add timestamps when creating a new table.'
|
45
|
+
RESTRICT_ON_SEND = %i[create_table].freeze
|
45
46
|
|
46
47
|
def_node_matcher :create_table_with_block?, <<~PATTERN
|
47
48
|
(block
|
@@ -43,7 +43,7 @@ module RuboCop
|
|
43
43
|
# Date.yesterday
|
44
44
|
# date.in_time_zone
|
45
45
|
#
|
46
|
-
class Date <
|
46
|
+
class Date < Base
|
47
47
|
include ConfigurableEnforcedStyle
|
48
48
|
|
49
49
|
MSG = 'Do not use `Date.%<method_called>s` without zone. Use ' \
|
@@ -52,6 +52,8 @@ module RuboCop
|
|
52
52
|
MSG_SEND = 'Do not use `%<method>s` on Date objects, because they ' \
|
53
53
|
'know nothing about the time zone in use.'
|
54
54
|
|
55
|
+
RESTRICT_ON_SEND = %i[to_time to_time_in_current_zone].freeze
|
56
|
+
|
55
57
|
BAD_DAYS = %i[today current yesterday tomorrow].freeze
|
56
58
|
|
57
59
|
DEPRECATED_METHODS = [
|
@@ -76,8 +78,7 @@ module RuboCop
|
|
76
78
|
|
77
79
|
check_deprecated_methods(node)
|
78
80
|
|
79
|
-
add_offense(node,
|
80
|
-
message: format(MSG_SEND, method: node.method_name))
|
81
|
+
add_offense(node.loc.selector, message: format(MSG_SEND, method: node.method_name))
|
81
82
|
end
|
82
83
|
alias on_csend on_send
|
83
84
|
|
@@ -87,10 +88,9 @@ module RuboCop
|
|
87
88
|
DEPRECATED_METHODS.each do |method|
|
88
89
|
next unless node.method?(method[:deprecated].to_sym)
|
89
90
|
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
relevant: method[:relevant]))
|
91
|
+
message = format(DEPRECATED_MSG, deprecated: method[:deprecated], relevant: method[:relevant])
|
92
|
+
|
93
|
+
add_offense(node.loc.selector, message: message)
|
94
94
|
end
|
95
95
|
end
|
96
96
|
|
@@ -104,10 +104,9 @@ module RuboCop
|
|
104
104
|
day = method_name
|
105
105
|
day = 'today' if method_name == 'current'
|
106
106
|
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
day: day))
|
107
|
+
message = format(MSG, method_called: method_name, day: day)
|
108
|
+
|
109
|
+
add_offense(node.loc.selector, message: message)
|
111
110
|
end
|
112
111
|
|
113
112
|
def extract_method_chain(node)
|
@@ -22,8 +22,9 @@ module RuboCop
|
|
22
22
|
# where(hidden: false)
|
23
23
|
# end
|
24
24
|
#
|
25
|
-
class DefaultScope <
|
25
|
+
class DefaultScope < Base
|
26
26
|
MSG = 'Avoid use of `default_scope`. It is better to use explicitly named scopes.'
|
27
|
+
RESTRICT_ON_SEND = %i[default_scope].freeze
|
27
28
|
|
28
29
|
def_node_matcher :method_call?, <<~PATTERN
|
29
30
|
(send nil? :default_scope ...)
|
@@ -38,15 +39,21 @@ module RuboCop
|
|
38
39
|
PATTERN
|
39
40
|
|
40
41
|
def on_send(node)
|
41
|
-
|
42
|
+
return unless method_call?(node)
|
43
|
+
|
44
|
+
add_offense(node.loc.selector)
|
42
45
|
end
|
43
46
|
|
44
47
|
def on_defs(node)
|
45
|
-
|
48
|
+
return unless class_method_definition?(node)
|
49
|
+
|
50
|
+
add_offense(node.loc.name)
|
46
51
|
end
|
47
52
|
|
48
53
|
def on_sclass(node)
|
49
|
-
eigenclass_method_definition?(node)
|
54
|
+
eigenclass_method_definition?(node) do |default_scope|
|
55
|
+
add_offense(default_scope.loc.name)
|
56
|
+
end
|
50
57
|
end
|
51
58
|
end
|
52
59
|
end
|
@@ -52,7 +52,9 @@ module RuboCop
|
|
52
52
|
#
|
53
53
|
# # good
|
54
54
|
# delegate :bar, to: :foo, prefix: true
|
55
|
-
class Delegate <
|
55
|
+
class Delegate < Base
|
56
|
+
extend AutoCorrector
|
57
|
+
|
56
58
|
MSG = 'Use `delegate` to define delegations.'
|
57
59
|
|
58
60
|
def_node_matcher :delegate?, <<~PATTERN
|
@@ -64,22 +66,20 @@ module RuboCop
|
|
64
66
|
return unless trivial_delegate?(node)
|
65
67
|
return if private_or_protected_delegation(node)
|
66
68
|
|
67
|
-
|
69
|
+
register_offense(node)
|
68
70
|
end
|
69
71
|
|
70
|
-
|
71
|
-
delegation = ["delegate :#{node.body.method_name}",
|
72
|
-
"to: :#{node.body.receiver.method_name}"]
|
72
|
+
private
|
73
73
|
|
74
|
-
|
74
|
+
def register_offense(node)
|
75
|
+
add_offense(node.loc.keyword) do |corrector|
|
76
|
+
delegation = ["delegate :#{node.body.method_name}", "to: :#{node.body.receiver.method_name}"]
|
77
|
+
delegation << ['prefix: true'] if node.method?(prefixed_method_name(node.body))
|
75
78
|
|
76
|
-
lambda do |corrector|
|
77
79
|
corrector.replace(node.source_range, delegation.join(', '))
|
78
80
|
end
|
79
81
|
end
|
80
82
|
|
81
|
-
private
|
82
|
-
|
83
83
|
def trivial_delegate?(def_node)
|
84
84
|
delegate?(def_node) &&
|
85
85
|
method_name_matches?(def_node.method_name, def_node.body) &&
|
@@ -13,22 +13,21 @@ module RuboCop
|
|
13
13
|
#
|
14
14
|
# # good
|
15
15
|
# delegate :foo, to: :bar, allow_nil: true
|
16
|
-
class DelegateAllowBlank <
|
16
|
+
class DelegateAllowBlank < Base
|
17
|
+
extend AutoCorrector
|
18
|
+
|
17
19
|
MSG = '`allow_blank` is not a valid option, use `allow_nil`.'
|
20
|
+
RESTRICT_ON_SEND = %i[delegate].freeze
|
18
21
|
|
19
22
|
def_node_matcher :allow_blank_option, <<~PATTERN
|
20
23
|
(send nil? :delegate _ (hash <$(pair (sym :allow_blank) true) ...>))
|
21
24
|
PATTERN
|
22
25
|
|
23
26
|
def on_send(node)
|
24
|
-
allow_blank_option(node)
|
25
|
-
add_offense(offending_node)
|
26
|
-
end
|
27
|
-
end
|
27
|
+
return unless (offending_node = allow_blank_option(node))
|
28
28
|
|
29
|
-
|
30
|
-
|
31
|
-
corrector.replace(pair_node.key.source_range, 'allow_nil')
|
29
|
+
add_offense(offending_node) do |corrector|
|
30
|
+
corrector.replace(offending_node.key.source_range, 'allow_nil')
|
32
31
|
end
|
33
32
|
end
|
34
33
|
end
|
@@ -31,7 +31,9 @@ module RuboCop
|
|
31
31
|
#
|
32
32
|
# # good
|
33
33
|
# Gem::Specification.find_by_name('backend').gem_dir
|
34
|
-
class DynamicFindBy <
|
34
|
+
class DynamicFindBy < Base
|
35
|
+
extend AutoCorrector
|
36
|
+
|
35
37
|
MSG = 'Use `%<static_name>s` instead of dynamic `%<method>s`.'
|
36
38
|
METHOD_PATTERN = /^find_by_(.+?)(!)?$/.freeze
|
37
39
|
|
@@ -43,25 +45,24 @@ module RuboCop
|
|
43
45
|
return unless static_name
|
44
46
|
return if node.arguments.any?(&:splat_type?)
|
45
47
|
|
46
|
-
|
47
|
-
|
48
|
-
|
48
|
+
message = format(MSG, static_name: static_name, method: method_name)
|
49
|
+
add_offense(node, message: message) do |corrector|
|
50
|
+
autocorrect(corrector, node)
|
51
|
+
end
|
49
52
|
end
|
50
53
|
alias on_csend on_send
|
51
54
|
|
52
|
-
|
55
|
+
private
|
56
|
+
|
57
|
+
def autocorrect(corrector, node)
|
53
58
|
keywords = column_keywords(node.method_name)
|
54
59
|
|
55
60
|
return if keywords.size != node.arguments.size
|
56
61
|
|
57
|
-
|
58
|
-
|
59
|
-
autocorrect_argument_keywords(corrector, node, keywords)
|
60
|
-
end
|
62
|
+
autocorrect_method_name(corrector, node)
|
63
|
+
autocorrect_argument_keywords(corrector, node, keywords)
|
61
64
|
end
|
62
65
|
|
63
|
-
private
|
64
|
-
|
65
66
|
def allowed_invocation?(node)
|
66
67
|
allowed_method?(node) || allowed_receiver?(node) ||
|
67
68
|
whitelisted?(node)
|
@@ -17,9 +17,12 @@ module RuboCop
|
|
17
17
|
# # good
|
18
18
|
# enum status: { active: 0, archived: 1 }
|
19
19
|
#
|
20
|
-
class EnumHash <
|
20
|
+
class EnumHash < Base
|
21
|
+
extend AutoCorrector
|
22
|
+
|
21
23
|
MSG = 'Enum defined as an array found in `%<enum>s` enum declaration. '\
|
22
24
|
'Use hash syntax instead.'
|
25
|
+
RESTRICT_ON_SEND = %i[enum].freeze
|
23
26
|
|
24
27
|
def_node_matcher :enum?, <<~PATTERN
|
25
28
|
(send nil? :enum (hash $...))
|
@@ -35,19 +38,17 @@ module RuboCop
|
|
35
38
|
key, array = array_pair?(pair)
|
36
39
|
next unless key
|
37
40
|
|
38
|
-
add_offense(array, message: format(MSG, enum: enum_name(key)))
|
41
|
+
add_offense(array, message: format(MSG, enum: enum_name(key))) do |corrector|
|
42
|
+
hash = array.children.each_with_index.map do |elem, index|
|
43
|
+
"#{source(elem)} => #{index}"
|
44
|
+
end.join(', ')
|
45
|
+
|
46
|
+
corrector.replace(array.loc.expression, "{#{hash}}")
|
47
|
+
end
|
39
48
|
end
|
40
49
|
end
|
41
50
|
end
|
42
51
|
|
43
|
-
def autocorrect(node)
|
44
|
-
hash = node.children.each_with_index.map do |elem, index|
|
45
|
-
"#{source(elem)} => #{index}"
|
46
|
-
end.join(', ')
|
47
|
-
|
48
|
-
->(corrector) { corrector.replace(node.loc.expression, "{#{hash}}") }
|
49
|
-
end
|
50
|
-
|
51
52
|
private
|
52
53
|
|
53
54
|
def enum_name(key)
|
@@ -17,11 +17,12 @@ module RuboCop
|
|
17
17
|
#
|
18
18
|
# # good
|
19
19
|
# enum status: [:active, :archived]
|
20
|
-
class EnumUniqueness <
|
20
|
+
class EnumUniqueness < Base
|
21
21
|
include Duplication
|
22
22
|
|
23
23
|
MSG = 'Duplicate value `%<value>s` found in `%<enum>s` ' \
|
24
24
|
'enum declaration.'
|
25
|
+
RESTRICT_ON_SEND = %i[enum].freeze
|
25
26
|
|
26
27
|
def_node_matcher :enum?, <<~PATTERN
|
27
28
|
(send nil? :enum (hash $...))
|
@@ -15,12 +15,16 @@ module RuboCop
|
|
15
15
|
#
|
16
16
|
# # good
|
17
17
|
# Rails.env.production?
|
18
|
-
class EnvironmentComparison <
|
18
|
+
class EnvironmentComparison < Base
|
19
|
+
extend AutoCorrector
|
20
|
+
|
19
21
|
MSG = 'Favor `%<bang>sRails.env.%<env>s?` over `%<source>s`.'
|
20
22
|
|
21
23
|
SYM_MSG = 'Do not compare `Rails.env` with a symbol, it will always ' \
|
22
24
|
'evaluate to `false`.'
|
23
25
|
|
26
|
+
RESTRICT_ON_SEND = %i[== !=].freeze
|
27
|
+
|
24
28
|
def_node_matcher :comparing_str_env_with_rails_env_on_lhs?, <<~PATTERN
|
25
29
|
(send
|
26
30
|
(send (const {nil? cbase} :Rails) :env)
|
@@ -62,28 +66,28 @@ module RuboCop
|
|
62
66
|
comparing_str_env_with_rails_env_on_rhs?(node))
|
63
67
|
env, = *env_node
|
64
68
|
bang = node.method?(:!=) ? '!' : ''
|
69
|
+
message = format(MSG, bang: bang, env: env, source: node.source)
|
65
70
|
|
66
|
-
add_offense(node, message:
|
67
|
-
|
68
|
-
|
69
|
-
end
|
70
|
-
|
71
|
-
if comparing_sym_env_with_rails_env_on_lhs?(node) ||
|
72
|
-
comparing_sym_env_with_rails_env_on_rhs?(node)
|
73
|
-
add_offense(node, message: SYM_MSG)
|
71
|
+
add_offense(node, message: message) do |corrector|
|
72
|
+
autocorrect(corrector, node)
|
73
|
+
end
|
74
74
|
end
|
75
|
-
end
|
76
75
|
|
77
|
-
|
78
|
-
lambda do |corrector|
|
79
|
-
replacement = build_predicate_method(node)
|
76
|
+
return unless comparing_sym_env_with_rails_env_on_lhs?(node) || comparing_sym_env_with_rails_env_on_rhs?(node)
|
80
77
|
|
81
|
-
|
78
|
+
add_offense(node, message: SYM_MSG) do |corrector|
|
79
|
+
autocorrect(corrector, node)
|
82
80
|
end
|
83
81
|
end
|
84
82
|
|
85
83
|
private
|
86
84
|
|
85
|
+
def autocorrect(corrector, node)
|
86
|
+
replacement = build_predicate_method(node)
|
87
|
+
|
88
|
+
corrector.replace(node.source_range, replacement)
|
89
|
+
end
|
90
|
+
|
87
91
|
def build_predicate_method(node)
|
88
92
|
if rails_env_on_lhs?(node)
|
89
93
|
build_predicate_method_for_rails_env_on_lhs(node)
|
@@ -23,27 +23,21 @@ module RuboCop
|
|
23
23
|
#
|
24
24
|
# # good
|
25
25
|
# raise 'a bad error has happened'
|
26
|
-
class Exit <
|
26
|
+
class Exit < Base
|
27
27
|
include ConfigurableEnforcedStyle
|
28
28
|
|
29
29
|
MSG = 'Do not use `exit` in Rails applications.'
|
30
|
-
|
30
|
+
RESTRICT_ON_SEND = %i[exit exit!].freeze
|
31
31
|
EXPLICIT_RECEIVERS = %i[Kernel Process].freeze
|
32
32
|
|
33
33
|
def on_send(node)
|
34
|
-
add_offense(node
|
34
|
+
add_offense(node.loc.selector) if offending_node?(node)
|
35
35
|
end
|
36
36
|
|
37
37
|
private
|
38
38
|
|
39
39
|
def offending_node?(node)
|
40
|
-
|
41
|
-
right_argument_count?(node.arguments) &&
|
42
|
-
right_receiver?(node.receiver)
|
43
|
-
end
|
44
|
-
|
45
|
-
def right_method_name?(method_name)
|
46
|
-
TARGET_METHODS.include?(method_name)
|
40
|
+
right_argument_count?(node.arguments) && right_receiver?(node.receiver)
|
47
41
|
end
|
48
42
|
|
49
43
|
# More than 1 argument likely means it is a different
|
@@ -25,7 +25,7 @@ module RuboCop
|
|
25
25
|
# # good
|
26
26
|
# Rails.root.join('app/models/goober')
|
27
27
|
#
|
28
|
-
class FilePath <
|
28
|
+
class FilePath < Base
|
29
29
|
include ConfigurableEnforcedStyle
|
30
30
|
include RangeHelp
|
31
31
|
|
@@ -33,6 +33,7 @@ module RuboCop
|
|
33
33
|
'instead.'
|
34
34
|
MSG_ARGUMENTS = 'Please use `Rails.root.join(\'path\', \'to\')` ' \
|
35
35
|
'instead.'
|
36
|
+
RESTRICT_ON_SEND = %i[join].freeze
|
36
37
|
|
37
38
|
def_node_matcher :file_join_nodes?, <<~PATTERN
|
38
39
|
(send (const nil? :File) :join ...)
|
@@ -97,10 +98,10 @@ module RuboCop
|
|
97
98
|
line_range = node.loc.column...node.loc.last_column
|
98
99
|
source_range = source_range(processed_source.buffer, node.first_line,
|
99
100
|
line_range)
|
100
|
-
add_offense(
|
101
|
+
add_offense(source_range)
|
101
102
|
end
|
102
103
|
|
103
|
-
def message(
|
104
|
+
def message(_range)
|
104
105
|
format(style == :arguments ? MSG_ARGUMENTS : MSG_SLASHES)
|
105
106
|
end
|
106
107
|
end
|
@@ -13,11 +13,12 @@ module RuboCop
|
|
13
13
|
#
|
14
14
|
# # good
|
15
15
|
# User.find_by(name: 'Bruce')
|
16
|
-
class FindBy <
|
16
|
+
class FindBy < Base
|
17
17
|
include RangeHelp
|
18
|
+
extend AutoCorrector
|
18
19
|
|
19
20
|
MSG = 'Use `find_by` instead of `where.%<method>s`.'
|
20
|
-
|
21
|
+
RESTRICT_ON_SEND = %i[first take].freeze
|
21
22
|
|
22
23
|
def_node_matcher :where_first?, <<~PATTERN
|
23
24
|
(send ({send csend} _ :where ...) {:first :take})
|
@@ -26,28 +27,27 @@ module RuboCop
|
|
26
27
|
def on_send(node)
|
27
28
|
return unless where_first?(node)
|
28
29
|
|
29
|
-
range = range_between(node.receiver.loc.selector.begin_pos,
|
30
|
-
node.loc.selector.end_pos)
|
30
|
+
range = range_between(node.receiver.loc.selector.begin_pos, node.loc.selector.end_pos)
|
31
31
|
|
32
|
-
add_offense(
|
33
|
-
|
32
|
+
add_offense(range, message: format(MSG, method: node.method_name)) do |corrector|
|
33
|
+
autocorrect(corrector, node)
|
34
|
+
end
|
34
35
|
end
|
35
36
|
alias on_csend on_send
|
36
37
|
|
37
|
-
|
38
|
+
private
|
39
|
+
|
40
|
+
def autocorrect(corrector, node)
|
38
41
|
# Don't autocorrect where(...).first, because it can return different
|
39
42
|
# results from find_by. (They order records differently, so the
|
40
43
|
# 'first' record can be different.)
|
41
44
|
return if node.method?(:first)
|
42
45
|
|
43
46
|
where_loc = node.receiver.loc.selector
|
44
|
-
first_loc = range_between(node.loc.dot.begin_pos,
|
45
|
-
node.loc.selector.end_pos)
|
47
|
+
first_loc = range_between(node.loc.dot.begin_pos, node.loc.selector.end_pos)
|
46
48
|
|
47
|
-
|
48
|
-
|
49
|
-
corrector.replace(first_loc, '')
|
50
|
-
end
|
49
|
+
corrector.replace(where_loc, 'find_by')
|
50
|
+
corrector.replace(first_loc, '')
|
51
51
|
end
|
52
52
|
end
|
53
53
|
end
|