rubocop-rails 2.6.0 → 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 +189 -6
- data/lib/rubocop/cop/mixin/active_record_helper.rb +12 -3
- data/lib/rubocop/cop/mixin/enforce_superclass.rb +40 -0
- data/lib/rubocop/cop/mixin/index_method.rb +25 -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 +148 -0
- 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 +91 -0
- 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 +20 -33
- 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 +61 -0
- data/lib/rubocop/cop/rails/delegate.rb +10 -10
- data/lib/rubocop/cop/rails/delegate_allow_blank.rb +7 -8
- data/lib/rubocop/cop/rails/dynamic_find_by.rb +13 -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 +5 -4
- data/lib/rubocop/cop/rails/find_by.rb +13 -13
- data/lib/rubocop/cop/rails/find_by_id.rb +94 -0
- 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 +4 -7
- data/lib/rubocop/cop/rails/helper_instance_variable.rb +4 -2
- data/lib/rubocop/cop/rails/http_positional_arguments.rb +25 -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 +11 -2
- data/lib/rubocop/cop/rails/index_with.rb +11 -2
- data/lib/rubocop/cop/rails/inquiry.rb +39 -0
- 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 -20
- data/lib/rubocop/cop/rails/mailer_name.rb +86 -0
- data/lib/rubocop/cop/rails/match_route.rb +120 -0
- data/lib/rubocop/cop/rails/negate_include.rb +41 -0
- data/lib/rubocop/cop/rails/not_null_column.rb +2 -1
- data/lib/rubocop/cop/rails/order_by_id.rb +52 -0
- 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 +21 -15
- data/lib/rubocop/cop/rails/pluck.rb +56 -0
- data/lib/rubocop/cop/rails/pluck_id.rb +56 -0
- data/lib/rubocop/cop/rails/pluck_in_where.rb +70 -0
- 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 +9 -11
- 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 +4 -3
- data/lib/rubocop/cop/rails/refute_methods.rb +9 -10
- data/lib/rubocop/cop/rails/relative_date_constant.rb +20 -9
- data/lib/rubocop/cop/rails/render_inline.rb +41 -0
- data/lib/rubocop/cop/rails/render_plain_text.rb +71 -0
- data/lib/rubocop/cop/rails/request_referer.rb +7 -7
- data/lib/rubocop/cop/rails/reversible_migration.rb +82 -7
- data/lib/rubocop/cop/rails/safe_navigation.rb +12 -11
- data/lib/rubocop/cop/rails/safe_navigation_with_blank.rb +5 -10
- data/lib/rubocop/cop/rails/save_bang.rb +19 -22
- data/lib/rubocop/cop/rails/scope_args.rb +2 -1
- data/lib/rubocop/cop/rails/short_i18n.rb +74 -0
- data/lib/rubocop/cop/rails/skips_model_validations.rb +46 -11
- data/lib/rubocop/cop/rails/squished_sql_heredocs.rb +82 -0
- data/lib/rubocop/cop/rails/time_zone.rb +22 -20
- data/lib/rubocop/cop/rails/uniq_before_pluck.rb +10 -10
- data/lib/rubocop/cop/rails/unique_validation_without_index.rb +18 -8
- data/lib/rubocop/cop/rails/unknown_env.rb +15 -4
- 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 +126 -0
- data/lib/rubocop/cop/rails/where_not.rb +97 -0
- data/lib/rubocop/cop/rails_cops.rb +22 -0
- data/lib/rubocop/rails/schema_loader.rb +4 -4
- data/lib/rubocop/rails/schema_loader/schema.rb +5 -5
- data/lib/rubocop/rails/version.rb +5 -1
- metadata +37 -9
@@ -0,0 +1,56 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Rails
|
6
|
+
# This cop enforces the use of `ids` over `pluck(:id)` and `pluck(primary_key)`.
|
7
|
+
#
|
8
|
+
# @example
|
9
|
+
# # bad
|
10
|
+
# User.pluck(:id)
|
11
|
+
# user.posts.pluck(:id)
|
12
|
+
#
|
13
|
+
# def self.user_ids
|
14
|
+
# pluck(primary_key)
|
15
|
+
# end
|
16
|
+
#
|
17
|
+
# # good
|
18
|
+
# User.ids
|
19
|
+
# user.posts.ids
|
20
|
+
#
|
21
|
+
# def self.user_ids
|
22
|
+
# ids
|
23
|
+
# end
|
24
|
+
#
|
25
|
+
class PluckId < Base
|
26
|
+
include RangeHelp
|
27
|
+
include ActiveRecordHelper
|
28
|
+
extend AutoCorrector
|
29
|
+
|
30
|
+
MSG = 'Use `ids` instead of `%<bad_method>s`.'
|
31
|
+
RESTRICT_ON_SEND = %i[pluck].freeze
|
32
|
+
|
33
|
+
def_node_matcher :pluck_id_call?, <<~PATTERN
|
34
|
+
(send _ :pluck {(sym :id) (send nil? :primary_key)})
|
35
|
+
PATTERN
|
36
|
+
|
37
|
+
def on_send(node)
|
38
|
+
return if !pluck_id_call?(node) || in_where?(node)
|
39
|
+
|
40
|
+
range = offense_range(node)
|
41
|
+
message = format(MSG, bad_method: range.source)
|
42
|
+
|
43
|
+
add_offense(range, message: message) do |corrector|
|
44
|
+
corrector.replace(offense_range(node), 'ids')
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
private
|
49
|
+
|
50
|
+
def offense_range(node)
|
51
|
+
range_between(node.loc.selector.begin_pos, node.loc.expression.end_pos)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Rails
|
6
|
+
# This cop identifies places where `pluck` is used in `where` query methods
|
7
|
+
# and can be replaced with `select`.
|
8
|
+
#
|
9
|
+
# Since `pluck` is an eager method and hits the database immediately,
|
10
|
+
# using `select` helps to avoid additional database queries.
|
11
|
+
#
|
12
|
+
# This cop has two different enforcement modes. When the EnforcedStyle
|
13
|
+
# is conservative (the default) then only calls to `pluck` on a constant
|
14
|
+
# (i.e. a model class) in the `where` is used as offenses.
|
15
|
+
#
|
16
|
+
# When the EnforcedStyle is aggressive then all calls to `pluck` in the
|
17
|
+
# `where` is used as offenses. This may lead to false positives
|
18
|
+
# as the cop cannot replace to `select` between calls to `pluck` on an
|
19
|
+
# `ActiveRecord::Relation` instance vs a call to `pluck` on an `Array` instance.
|
20
|
+
#
|
21
|
+
# @example
|
22
|
+
# # bad
|
23
|
+
# Post.where(user_id: User.active.pluck(:id))
|
24
|
+
#
|
25
|
+
# # good
|
26
|
+
# Post.where(user_id: User.active.select(:id))
|
27
|
+
# Post.where(user_id: active_users.select(:id))
|
28
|
+
#
|
29
|
+
# @example EnforcedStyle: conservative (default)
|
30
|
+
# # good
|
31
|
+
# Post.where(user_id: active_users.pluck(:id))
|
32
|
+
#
|
33
|
+
# @example EnforcedStyle: aggressive
|
34
|
+
# # bad
|
35
|
+
# Post.where(user_id: active_users.pluck(:id))
|
36
|
+
#
|
37
|
+
class PluckInWhere < Base
|
38
|
+
include ActiveRecordHelper
|
39
|
+
include ConfigurableEnforcedStyle
|
40
|
+
extend AutoCorrector
|
41
|
+
|
42
|
+
MSG = 'Use `select` instead of `pluck` within `where` query method.'
|
43
|
+
RESTRICT_ON_SEND = %i[pluck].freeze
|
44
|
+
|
45
|
+
def on_send(node)
|
46
|
+
return unless in_where?(node)
|
47
|
+
return if style == :conservative && !root_receiver(node)&.const_type?
|
48
|
+
|
49
|
+
range = node.loc.selector
|
50
|
+
|
51
|
+
add_offense(range) do |corrector|
|
52
|
+
corrector.replace(range, 'select')
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
private
|
57
|
+
|
58
|
+
def root_receiver(node)
|
59
|
+
receiver = node.receiver
|
60
|
+
|
61
|
+
if receiver&.send_type?
|
62
|
+
root_receiver(receiver)
|
63
|
+
else
|
64
|
+
receiver
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
@@ -14,7 +14,9 @@ module RuboCop
|
|
14
14
|
# # good
|
15
15
|
# 3.days.ago
|
16
16
|
# 1.month.ago
|
17
|
-
class PluralizationGrammar <
|
17
|
+
class PluralizationGrammar < Base
|
18
|
+
extend AutoCorrector
|
19
|
+
|
18
20
|
SINGULAR_DURATION_METHODS = { second: :seconds,
|
19
21
|
minute: :minutes,
|
20
22
|
hour: :hours,
|
@@ -24,21 +26,18 @@ module RuboCop
|
|
24
26
|
month: :months,
|
25
27
|
year: :years }.freeze
|
26
28
|
|
29
|
+
RESTRICT_ON_SEND = SINGULAR_DURATION_METHODS.keys + SINGULAR_DURATION_METHODS.values
|
30
|
+
|
27
31
|
PLURAL_DURATION_METHODS = SINGULAR_DURATION_METHODS.invert.freeze
|
28
32
|
|
29
33
|
MSG = 'Prefer `%<number>s.%<correct>s`.'
|
30
34
|
|
31
35
|
def on_send(node)
|
32
|
-
return unless duration_method?(node.method_name)
|
33
|
-
return unless literal_number?(node.receiver)
|
36
|
+
return unless duration_method?(node.method_name) && literal_number?(node.receiver) && offense?(node)
|
34
37
|
|
35
|
-
|
36
|
-
|
37
|
-
add_offense(node)
|
38
|
-
end
|
38
|
+
number, = *node.receiver
|
39
39
|
|
40
|
-
|
41
|
-
lambda do |corrector|
|
40
|
+
add_offense(node, message: message(number, node.method_name)) do |corrector|
|
42
41
|
method_name = node.loc.selector.source
|
43
42
|
|
44
43
|
corrector.replace(node.loc.selector, correct_method(method_name))
|
@@ -47,11 +46,8 @@ module RuboCop
|
|
47
46
|
|
48
47
|
private
|
49
48
|
|
50
|
-
def message(
|
51
|
-
number,
|
52
|
-
|
53
|
-
format(MSG, number: number,
|
54
|
-
correct: correct_method(node.method_name.to_s))
|
49
|
+
def message(number, method_name)
|
50
|
+
format(MSG, number: number, correct: correct_method(method_name))
|
55
51
|
end
|
56
52
|
|
57
53
|
def correct_method(method_name)
|
@@ -37,8 +37,9 @@ module RuboCop
|
|
37
37
|
#
|
38
38
|
# # good
|
39
39
|
# a.presence || b
|
40
|
-
class Presence <
|
40
|
+
class Presence < Base
|
41
41
|
include RangeHelp
|
42
|
+
extend AutoCorrector
|
42
43
|
|
43
44
|
MSG = 'Use `%<prefer>s` instead of `%<current>s`.'
|
44
45
|
|
@@ -76,28 +77,26 @@ module RuboCop
|
|
76
77
|
return if ignore_if_node?(node)
|
77
78
|
|
78
79
|
redundant_receiver_and_other(node) do |receiver, other|
|
79
|
-
|
80
|
+
return if ignore_other_node?(other) || receiver.nil?
|
81
|
+
|
82
|
+
register_offense(node, receiver, other)
|
80
83
|
end
|
81
84
|
|
82
85
|
redundant_negative_receiver_and_other(node) do |receiver, other|
|
83
|
-
|
86
|
+
return if ignore_other_node?(other) || receiver.nil?
|
87
|
+
|
88
|
+
register_offense(node, receiver, other)
|
84
89
|
end
|
85
90
|
end
|
86
91
|
|
87
|
-
|
88
|
-
lambda do |corrector|
|
89
|
-
redundant_receiver_and_other(node) do |receiver, other|
|
90
|
-
corrector.replace(node.source_range, replacement(receiver, other))
|
91
|
-
end
|
92
|
+
private
|
92
93
|
|
93
|
-
|
94
|
-
|
95
|
-
|
94
|
+
def register_offense(node, receiver, other)
|
95
|
+
add_offense(node, message: message(node, receiver, other)) do |corrector|
|
96
|
+
corrector.replace(node.source_range, replacement(receiver, other))
|
96
97
|
end
|
97
98
|
end
|
98
99
|
|
99
|
-
private
|
100
|
-
|
101
100
|
def ignore_if_node?(node)
|
102
101
|
node.elsif?
|
103
102
|
end
|
@@ -43,12 +43,15 @@ module RuboCop
|
|
43
43
|
#
|
44
44
|
# # good
|
45
45
|
# something if foo.present?
|
46
|
-
class Present <
|
46
|
+
class Present < Base
|
47
|
+
extend AutoCorrector
|
48
|
+
|
47
49
|
MSG_NOT_BLANK = 'Use `%<prefer>s` instead of `%<current>s`.'
|
48
50
|
MSG_EXISTS_AND_NOT_EMPTY = 'Use `%<prefer>s` instead of ' \
|
49
51
|
'`%<current>s`.'
|
50
52
|
MSG_UNLESS_BLANK = 'Use `if %<prefer>s` instead of ' \
|
51
53
|
'`%<current>s`.'
|
54
|
+
RESTRICT_ON_SEND = %i[!].freeze
|
52
55
|
|
53
56
|
def_node_matcher :exists_and_not_empty?, <<~PATTERN
|
54
57
|
(and
|
@@ -74,10 +77,11 @@ module RuboCop
|
|
74
77
|
return unless cop_config['NotBlank']
|
75
78
|
|
76
79
|
not_blank?(node) do |receiver|
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
80
|
+
message = format(MSG_NOT_BLANK, prefer: replacement(receiver), current: node.source)
|
81
|
+
|
82
|
+
add_offense(node, message: message) do |corrector|
|
83
|
+
autocorrect(corrector, node)
|
84
|
+
end
|
81
85
|
end
|
82
86
|
end
|
83
87
|
|
@@ -87,10 +91,11 @@ module RuboCop
|
|
87
91
|
exists_and_not_empty?(node) do |var1, var2|
|
88
92
|
return unless var1 == var2
|
89
93
|
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
+
message = format(MSG_EXISTS_AND_NOT_EMPTY, prefer: replacement(var1), current: node.source)
|
95
|
+
|
96
|
+
add_offense(node, message: message) do |corrector|
|
97
|
+
autocorrect(corrector, node)
|
98
|
+
end
|
94
99
|
end
|
95
100
|
end
|
96
101
|
|
@@ -100,7 +105,9 @@ module RuboCop
|
|
100
105
|
exists_and_not_empty?(node) do |var1, var2|
|
101
106
|
return unless var1 == var2
|
102
107
|
|
103
|
-
add_offense(node, message: MSG_EXISTS_AND_NOT_EMPTY)
|
108
|
+
add_offense(node, message: MSG_EXISTS_AND_NOT_EMPTY) do |corrector|
|
109
|
+
autocorrect(corrector, node)
|
110
|
+
end
|
104
111
|
end
|
105
112
|
end
|
106
113
|
|
@@ -113,25 +120,24 @@ module RuboCop
|
|
113
120
|
range = unless_condition(node, method_call)
|
114
121
|
msg = format(MSG_UNLESS_BLANK, prefer: replacement(receiver),
|
115
122
|
current: range.source)
|
116
|
-
add_offense(
|
123
|
+
add_offense(range, message: msg) do |corrector|
|
124
|
+
autocorrect(corrector, node)
|
125
|
+
end
|
117
126
|
end
|
118
127
|
end
|
119
128
|
|
120
|
-
def autocorrect(node)
|
121
|
-
|
122
|
-
method_call, variable1 = unless_blank?(node)
|
123
|
-
|
124
|
-
if method_call
|
125
|
-
corrector.replace(node.loc.keyword, 'if')
|
126
|
-
range = method_call.loc.expression
|
127
|
-
else
|
128
|
-
variable1, _variable2 =
|
129
|
-
exists_and_not_empty?(node) || not_blank?(node)
|
130
|
-
range = node.loc.expression
|
131
|
-
end
|
129
|
+
def autocorrect(corrector, node)
|
130
|
+
method_call, variable1 = unless_blank?(node)
|
132
131
|
|
133
|
-
|
132
|
+
if method_call
|
133
|
+
corrector.replace(node.loc.keyword, 'if')
|
134
|
+
range = method_call.loc.expression
|
135
|
+
else
|
136
|
+
variable1, _variable2 = exists_and_not_empty?(node) || not_blank?(node)
|
137
|
+
range = node.loc.expression
|
134
138
|
end
|
139
|
+
|
140
|
+
corrector.replace(range, replacement(variable1))
|
135
141
|
end
|
136
142
|
|
137
143
|
private
|
@@ -25,7 +25,9 @@ module RuboCop
|
|
25
25
|
# do_something
|
26
26
|
# end
|
27
27
|
#
|
28
|
-
class RakeEnvironment <
|
28
|
+
class RakeEnvironment < Base
|
29
|
+
extend AutoCorrector
|
30
|
+
|
29
31
|
MSG = 'Include `:environment` task as a dependency for all Rake tasks.'
|
30
32
|
|
31
33
|
def_node_matcher :task_definition?, <<~PATTERN
|
@@ -37,16 +39,12 @@ module RuboCop
|
|
37
39
|
return if task_name(task_method) == :default
|
38
40
|
return if with_dependencies?(task_method)
|
39
41
|
|
40
|
-
add_offense(task_method)
|
41
|
-
|
42
|
-
|
42
|
+
add_offense(task_method) do |corrector|
|
43
|
+
task_name = task_method.arguments[0]
|
44
|
+
task_dependency = correct_task_dependency(task_name)
|
43
45
|
|
44
|
-
|
45
|
-
|
46
|
-
task_name = node.arguments[0]
|
47
|
-
task_dependency = correct_task_dependency(task_name)
|
48
|
-
|
49
|
-
corrector.replace(task_name.loc.expression, task_dependency)
|
46
|
+
corrector.replace(task_name.loc.expression, task_dependency)
|
47
|
+
end
|
50
48
|
end
|
51
49
|
end
|
52
50
|
|
@@ -54,7 +52,7 @@ module RuboCop
|
|
54
52
|
|
55
53
|
def correct_task_dependency(task_name)
|
56
54
|
if task_name.sym_type?
|
57
|
-
task_name.source.delete(':|\'|"')
|
55
|
+
"#{task_name.source.delete(':|\'|"')}: :environment"
|
58
56
|
else
|
59
57
|
"#{task_name.source} => :environment"
|
60
58
|
end
|
@@ -23,8 +23,11 @@ module RuboCop
|
|
23
23
|
# # good
|
24
24
|
# x = self[:attr]
|
25
25
|
# self[:attr] = val
|
26
|
-
class ReadWriteAttribute <
|
26
|
+
class ReadWriteAttribute < Base
|
27
|
+
extend AutoCorrector
|
28
|
+
|
27
29
|
MSG = 'Prefer `%<prefer>s` over `%<current>s`.'
|
30
|
+
RESTRICT_ON_SEND = %i[read_attribute write_attribute].freeze
|
28
31
|
|
29
32
|
def_node_matcher :read_write_attribute?, <<~PATTERN
|
30
33
|
{
|
@@ -36,18 +39,16 @@ module RuboCop
|
|
36
39
|
def on_send(node)
|
37
40
|
return unless read_write_attribute?(node)
|
38
41
|
|
39
|
-
add_offense(node,
|
40
|
-
|
42
|
+
add_offense(node.loc.selector, message: message(node)) do |corrector|
|
43
|
+
case node.method_name
|
44
|
+
when :read_attribute
|
45
|
+
replacement = read_attribute_replacement(node)
|
46
|
+
when :write_attribute
|
47
|
+
replacement = write_attribute_replacement(node)
|
48
|
+
end
|
41
49
|
|
42
|
-
|
43
|
-
case node.method_name
|
44
|
-
when :read_attribute
|
45
|
-
replacement = read_attribute_replacement(node)
|
46
|
-
when :write_attribute
|
47
|
-
replacement = write_attribute_replacement(node)
|
50
|
+
corrector.replace(node.source_range, replacement)
|
48
51
|
end
|
49
|
-
|
50
|
-
->(corrector) { corrector.replace(node.source_range, replacement) }
|
51
52
|
end
|
52
53
|
|
53
54
|
private
|
@@ -26,8 +26,9 @@ module RuboCop
|
|
26
26
|
# # Here, `nil` is valid but `''` is not
|
27
27
|
# validates :x, length: { is: 5 }, allow_nil: true, allow_blank: false
|
28
28
|
#
|
29
|
-
class RedundantAllowNil <
|
29
|
+
class RedundantAllowNil < Base
|
30
30
|
include RangeHelp
|
31
|
+
extend AutoCorrector
|
31
32
|
|
32
33
|
MSG_SAME =
|
33
34
|
'`allow_nil` is redundant when `allow_blank` has the same value.'
|
@@ -35,59 +36,56 @@ module RuboCop
|
|
35
36
|
MSG_ALLOW_NIL_FALSE =
|
36
37
|
'`allow_nil: false` is redundant when `allow_blank` is true.'
|
37
38
|
|
38
|
-
|
39
|
-
return unless node.method?(:validates)
|
39
|
+
RESTRICT_ON_SEND = %i[validates].freeze
|
40
40
|
|
41
|
+
def on_send(node)
|
41
42
|
allow_nil, allow_blank = find_allow_nil_and_allow_blank(node)
|
42
43
|
return unless allow_nil && allow_blank
|
43
44
|
|
44
45
|
allow_nil_val = allow_nil.children.last
|
45
46
|
allow_blank_val = allow_blank.children.last
|
46
47
|
|
47
|
-
|
48
|
+
if allow_nil_val.type == allow_blank_val.type
|
49
|
+
register_offense(allow_nil, MSG_SAME)
|
50
|
+
elsif allow_nil_val.false_type? && allow_blank_val.true_type?
|
51
|
+
register_offense(allow_nil, MSG_ALLOW_NIL_FALSE)
|
52
|
+
end
|
48
53
|
end
|
49
54
|
|
50
|
-
|
51
|
-
|
52
|
-
|
55
|
+
private
|
56
|
+
|
57
|
+
def register_offense(allow_nil, message)
|
58
|
+
add_offense(allow_nil, message: message) do |corrector|
|
59
|
+
prv_sib = previous_sibling(allow_nil)
|
60
|
+
nxt_sib = next_sibling(allow_nil)
|
53
61
|
|
54
|
-
lambda do |corrector|
|
55
62
|
if nxt_sib
|
56
|
-
corrector.remove(range_between(node_beg(
|
63
|
+
corrector.remove(range_between(node_beg(allow_nil), node_beg(nxt_sib)))
|
57
64
|
elsif prv_sib
|
58
|
-
corrector.remove(range_between(node_end(prv_sib), node_end(
|
65
|
+
corrector.remove(range_between(node_end(prv_sib), node_end(allow_nil)))
|
59
66
|
else
|
60
|
-
corrector.remove(
|
67
|
+
corrector.remove(allow_nil.loc.expression)
|
61
68
|
end
|
62
69
|
end
|
63
70
|
end
|
64
71
|
|
65
|
-
private
|
66
|
-
|
67
|
-
def offense(allow_nil_val, allow_blank_val, allow_nil)
|
68
|
-
if allow_nil_val.type == allow_blank_val.type
|
69
|
-
add_offense(allow_nil, message: MSG_SAME)
|
70
|
-
elsif allow_nil_val.false_type? && allow_blank_val.true_type?
|
71
|
-
add_offense(allow_nil, message: MSG_ALLOW_NIL_FALSE)
|
72
|
-
end
|
73
|
-
end
|
74
|
-
|
75
72
|
def find_allow_nil_and_allow_blank(node)
|
76
|
-
allow_nil = nil
|
77
|
-
allow_blank = nil
|
73
|
+
allow_nil, allow_blank = nil
|
78
74
|
|
79
|
-
node.
|
80
|
-
|
75
|
+
node.each_child_node do |child_node|
|
76
|
+
if child_node.pair_type?
|
77
|
+
key = child_node.children.first.source
|
81
78
|
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
79
|
+
allow_nil = child_node if key == 'allow_nil'
|
80
|
+
allow_blank = child_node if key == 'allow_blank'
|
81
|
+
end
|
82
|
+
return [allow_nil, allow_blank] if allow_nil && allow_blank
|
86
83
|
|
87
|
-
|
84
|
+
found_in_children_nodes = find_allow_nil_and_allow_blank(child_node)
|
85
|
+
return found_in_children_nodes if found_in_children_nodes
|
88
86
|
end
|
89
87
|
|
90
|
-
|
88
|
+
nil
|
91
89
|
end
|
92
90
|
|
93
91
|
def previous_sibling(node)
|