rubocop-rails 2.15.2 → 2.16.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.
Files changed (67) hide show
  1. checksums.yaml +4 -4
  2. data/config/default.yml +81 -0
  3. data/config/obsoletion.yml +10 -0
  4. data/lib/rubocop/cop/mixin/active_record_helper.rb +1 -4
  5. data/lib/rubocop/cop/mixin/active_record_migrations_helper.rb +1 -3
  6. data/lib/rubocop/cop/mixin/index_method.rb +5 -15
  7. data/lib/rubocop/cop/rails/action_controller_flash_before_render.rb +98 -0
  8. data/lib/rubocop/cop/rails/action_filter.rb +1 -1
  9. data/lib/rubocop/cop/rails/active_record_aliases.rb +1 -4
  10. data/lib/rubocop/cop/rails/active_record_override.rb +2 -5
  11. data/lib/rubocop/cop/rails/active_support_on_load.rb +70 -0
  12. data/lib/rubocop/cop/rails/add_column_index.rb +1 -4
  13. data/lib/rubocop/cop/rails/blank.rb +1 -2
  14. data/lib/rubocop/cop/rails/bulk_change_table.rb +6 -20
  15. data/lib/rubocop/cop/rails/compact_blank.rb +5 -1
  16. data/lib/rubocop/cop/rails/content_tag.rb +1 -3
  17. data/lib/rubocop/cop/rails/date.rb +4 -9
  18. data/lib/rubocop/cop/rails/delegate.rb +2 -5
  19. data/lib/rubocop/cop/rails/deprecated_active_model_errors_methods.rb +17 -13
  20. data/lib/rubocop/cop/rails/dot_separated_keys.rb +1 -1
  21. data/lib/rubocop/cop/rails/dynamic_find_by.rb +2 -4
  22. data/lib/rubocop/cop/rails/enum_uniqueness.rb +2 -5
  23. data/lib/rubocop/cop/rails/environment_comparison.rb +1 -2
  24. data/lib/rubocop/cop/rails/file_path.rb +2 -4
  25. data/lib/rubocop/cop/rails/find_each.rb +8 -2
  26. data/lib/rubocop/cop/rails/freeze_time.rb +74 -0
  27. data/lib/rubocop/cop/rails/has_many_or_has_one_dependent.rb +1 -3
  28. data/lib/rubocop/cop/rails/http_positional_arguments.rb +4 -9
  29. data/lib/rubocop/cop/rails/http_status.rb +5 -10
  30. data/lib/rubocop/cop/rails/ignored_skip_action_filter_option.rb +3 -10
  31. data/lib/rubocop/cop/rails/inverse_of.rb +3 -6
  32. data/lib/rubocop/cop/rails/lexically_scoped_action_filter.rb +2 -6
  33. data/lib/rubocop/cop/rails/link_to_blank.rb +1 -4
  34. data/lib/rubocop/cop/rails/output.rb +2 -5
  35. data/lib/rubocop/cop/rails/pluralization_grammar.rb +1 -2
  36. data/lib/rubocop/cop/rails/presence.rb +1 -3
  37. data/lib/rubocop/cop/rails/present.rb +3 -6
  38. data/lib/rubocop/cop/rails/rake_environment.rb +1 -1
  39. data/lib/rubocop/cop/rails/redundant_allow_nil.rb +2 -4
  40. data/lib/rubocop/cop/rails/redundant_foreign_key.rb +1 -1
  41. data/lib/rubocop/cop/rails/redundant_presence_validation_on_belongs_to.rb +2 -2
  42. data/lib/rubocop/cop/rails/redundant_receiver_in_with_options.rb +28 -26
  43. data/lib/rubocop/cop/rails/reflection_class_name.rb +17 -0
  44. data/lib/rubocop/cop/rails/refute_methods.rb +1 -5
  45. data/lib/rubocop/cop/rails/relative_date_constant.rb +2 -5
  46. data/lib/rubocop/cop/rails/request_referer.rb +1 -2
  47. data/lib/rubocop/cop/rails/reversible_migration.rb +10 -33
  48. data/lib/rubocop/cop/rails/reversible_migration_method_definition.rb +1 -2
  49. data/lib/rubocop/cop/rails/root_pathname_methods.rb +214 -0
  50. data/lib/rubocop/cop/rails/safe_navigation_with_blank.rb +1 -3
  51. data/lib/rubocop/cop/rails/save_bang.rb +10 -22
  52. data/lib/rubocop/cop/rails/short_i18n.rb +1 -4
  53. data/lib/rubocop/cop/rails/skips_model_validations.rb +1 -2
  54. data/lib/rubocop/cop/rails/squished_sql_heredocs.rb +1 -5
  55. data/lib/rubocop/cop/rails/time_zone.rb +8 -19
  56. data/lib/rubocop/cop/rails/to_s_with_argument.rb +41 -0
  57. data/lib/rubocop/cop/rails/top_level_hash_with_indifferent_access.rb +49 -0
  58. data/lib/rubocop/cop/rails/uniq_before_pluck.rb +3 -6
  59. data/lib/rubocop/cop/rails/unique_validation_without_index.rb +1 -3
  60. data/lib/rubocop/cop/rails/unknown_env.rb +2 -4
  61. data/lib/rubocop/cop/rails/validation.rb +4 -12
  62. data/lib/rubocop/cop/rails/where_missing.rb +111 -0
  63. data/lib/rubocop/cop/rails_cops.rb +7 -0
  64. data/lib/rubocop/rails/version.rb +1 -1
  65. metadata +13 -8
  66. data/bin/console +0 -11
  67. data/bin/setup +0 -7
@@ -37,7 +37,8 @@ module RuboCop
37
37
  extend AutoCorrector
38
38
 
39
39
  MSG = 'Avoid manipulating ActiveModel errors as hash directly.'
40
- AUTOCORECTABLE_METHODS = %i[<< clear keys].freeze
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
- #errors_keys?
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 :errors_keys?, <<~PATTERN
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 node.method?(:keys) && target_rails_version <= 6.0
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 unless AUTOCORECTABLE_METHODS.include?(node.method_name)
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
- range_between(receiver.receiver.source_range.end_pos, node.source_range.end_pos)
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 '.errors.attribute_names' if node.method?(:keys)
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(range: scope_node.source_range, side: :left)
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
 
@@ -70,8 +70,7 @@ module RuboCop
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,8 +94,7 @@ 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)
@@ -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 IgnoredMethods: ['order']
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
- (cop_config['IgnoredMethods'].map(&:to_sym) & method_chain).any?
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
- 'positional arguments for http call: `%<verb>s`.'
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
@@ -84,10 +84,8 @@ module RuboCop
84
84
 
85
85
  # :nodoc:
86
86
  class SymbolicStyleChecker
87
- MSG = 'Prefer `%<prefer>s` over `%<current>s` ' \
88
- 'to define HTTP status code.'
89
- DEFAULT_MSG = 'Prefer `symbolic` over `numeric` ' \
90
- 'to define HTTP status code.'
87
+ MSG = 'Prefer `%<prefer>s` over `%<current>s` to define HTTP status code.'
88
+ DEFAULT_MSG = 'Prefer `symbolic` over `numeric` to define HTTP status code.'
91
89
 
92
90
  attr_reader :node
93
91
 
@@ -118,17 +116,14 @@ module RuboCop
118
116
  end
119
117
 
120
118
  def custom_http_status_code?
121
- node.int_type? &&
122
- !::Rack::Utils::SYMBOL_TO_STATUS_CODE.value?(number)
119
+ node.int_type? && !::Rack::Utils::SYMBOL_TO_STATUS_CODE.value?(number)
123
120
  end
124
121
  end
125
122
 
126
123
  # :nodoc:
127
124
  class NumericStyleChecker
128
- MSG = 'Prefer `%<prefer>s` over `%<current>s` ' \
129
- 'to define HTTP status code.'
130
- DEFAULT_MSG = 'Prefer `numeric` over `symbolic` ' \
131
- 'to define HTTP status code.'
125
+ MSG = 'Prefer `%<prefer>s` over `%<current>s` to define HTTP status code.'
126
+ DEFAULT_MSG = 'Prefer `numeric` over `symbolic` to define HTTP status code.'
132
127
  PERMITTED_STATUS = %i[error success missing redirect].freeze
133
128
 
134
129
  attr_reader :node
@@ -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
@@ -184,13 +184,9 @@ module RuboCop
184
184
  # @return [String]
185
185
  def message(methods, parent)
186
186
  if methods.size == 1
187
- format(MSG,
188
- action: "`#{methods[0]}` is",
189
- type: parent.type)
187
+ format(MSG, action: "`#{methods[0]}` is", type: parent.type)
190
188
  else
191
- format(MSG,
192
- action: "`#{methods.join('`, `')}` are",
193
- type: parent.type)
189
+ format(MSG, action: "`#{methods.join('`, `')}` are", type: parent.type)
194
190
  end
195
191
  end
196
192
  end
@@ -68,10 +68,7 @@ module RuboCop
68
68
 
69
69
  def append_to_rel(rel_node, corrector)
70
70
  existing_rel = rel_node.children.last.value
71
- str_range = rel_node.children.last.loc.expression.adjust(
72
- begin_pos: 1,
73
- end_pos: -1
74
- )
71
+ str_range = rel_node.children.last.loc.expression.adjust(begin_pos: 1, end_pos: -1)
75
72
  corrector.replace(str_range, "#{existing_rel} noopener")
76
73
  end
77
74
 
@@ -21,11 +21,8 @@ module RuboCop
21
21
  include RangeHelp
22
22
  extend AutoCorrector
23
23
 
24
- MSG = 'Do not write to stdout. ' \
25
- "Use Rails's logger if you want to log."
26
- RESTRICT_ON_SEND = %i[
27
- ap p pp pretty_print print puts binwrite syswrite write write_nonblock
28
- ].freeze
24
+ MSG = "Do not write to stdout. Use Rails's logger if you want to log."
25
+ RESTRICT_ON_SEND = %i[ap p pp pretty_print print puts binwrite syswrite write write_nonblock].freeze
29
26
 
30
27
  def_node_matcher :output?, <<~PATTERN
31
28
  (send nil? {:ap :p :pp :pretty_print :print :puts} ...)
@@ -94,8 +94,7 @@ module RuboCop
94
94
  end
95
95
 
96
96
  def duration_method?(method_name)
97
- SINGULAR_DURATION_METHODS.key?(method_name) ||
98
- PLURAL_DURATION_METHODS.key?(method_name)
97
+ SINGULAR_DURATION_METHODS.key?(method_name) || PLURAL_DURATION_METHODS.key?(method_name)
99
98
  end
100
99
  end
101
100
  end
@@ -106,9 +106,7 @@ module RuboCop
106
106
  end
107
107
 
108
108
  def message(node, receiver, other)
109
- format(MSG,
110
- prefer: replacement(receiver, other),
111
- current: node.source)
109
+ format(MSG, prefer: replacement(receiver, other), current: node.source)
112
110
  end
113
111
 
114
112
  def replacement(receiver, other)
@@ -47,10 +47,8 @@ module RuboCop
47
47
  extend AutoCorrector
48
48
 
49
49
  MSG_NOT_BLANK = 'Use `%<prefer>s` instead of `%<current>s`.'
50
- MSG_EXISTS_AND_NOT_EMPTY = 'Use `%<prefer>s` instead of ' \
51
- '`%<current>s`.'
52
- MSG_UNLESS_BLANK = 'Use `if %<prefer>s` instead of ' \
53
- '`%<current>s`.'
50
+ MSG_EXISTS_AND_NOT_EMPTY = 'Use `%<prefer>s` instead of `%<current>s`.'
51
+ MSG_UNLESS_BLANK = 'Use `if %<prefer>s` instead of `%<current>s`.'
54
52
  RESTRICT_ON_SEND = %i[!].freeze
55
53
 
56
54
  def_node_matcher :exists_and_not_empty?, <<~PATTERN
@@ -118,8 +116,7 @@ module RuboCop
118
116
 
119
117
  unless_blank?(node) do |method_call, receiver|
120
118
  range = unless_condition(node, method_call)
121
- msg = format(MSG_UNLESS_BLANK, prefer: replacement(receiver),
122
- current: range.source)
119
+ msg = format(MSG_UNLESS_BLANK, prefer: replacement(receiver), current: range.source)
123
120
  add_offense(range, message: msg) do |corrector|
124
121
  autocorrect(corrector, node)
125
122
  end
@@ -39,7 +39,7 @@ module RuboCop
39
39
  (block $(send nil? :task ...) ...)
40
40
  PATTERN
41
41
 
42
- def on_block(node)
42
+ def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler
43
43
  task_definition?(node) do |task_method|
44
44
  return if task_name(task_method) == :default
45
45
  return if with_dependencies?(task_method)
@@ -30,11 +30,9 @@ module RuboCop
30
30
  include RangeHelp
31
31
  extend AutoCorrector
32
32
 
33
- MSG_SAME =
34
- '`allow_nil` is redundant when `allow_blank` has the same value.'
33
+ MSG_SAME = '`allow_nil` is redundant when `allow_blank` has the same value.'
35
34
 
36
- MSG_ALLOW_NIL_FALSE =
37
- '`allow_nil: false` is redundant when `allow_blank` is true.'
35
+ MSG_ALLOW_NIL_FALSE = '`allow_nil: false` is redundant when `allow_blank` is true.'
38
36
 
39
37
  RESTRICT_ON_SEND = %i[validates].freeze
40
38
 
@@ -41,7 +41,7 @@ module RuboCop
41
41
  association_with_foreign_key(node) do |type, name, options, foreign_key_pair, foreign_key|
42
42
  if redundant?(node, type, name, options, foreign_key)
43
43
  add_offense(foreign_key_pair.loc.expression) do |corrector|
44
- range = range_with_surrounding_space(range: foreign_key_pair.source_range, side: :left)
44
+ range = range_with_surrounding_space(foreign_key_pair.source_range, side: :left)
45
45
  range = range_with_surrounding_comma(range, :left)
46
46
 
47
47
  corrector.remove(range)
@@ -217,7 +217,7 @@ module RuboCop
217
217
  keys.each do |key|
218
218
  key_node = node.arguments.find { |arg| arg.value == key }
219
219
  key_range = range_with_surrounding_space(
220
- range: range_with_surrounding_comma(key_node.source_range, :right),
220
+ range_with_surrounding_comma(key_node.source_range, :right),
221
221
  side: :right
222
222
  )
223
223
  corrector.remove(key_range)
@@ -226,7 +226,7 @@ module RuboCop
226
226
 
227
227
  def remove_presence_option(corrector, presence)
228
228
  range = range_with_surrounding_comma(
229
- range_with_surrounding_space(range: presence.source_range, side: :left),
229
+ range_with_surrounding_space(presence.source_range, side: :left),
230
230
  :left
231
231
  )
232
232
  corrector.remove(range)
@@ -60,15 +60,6 @@ module RuboCop
60
60
 
61
61
  MSG = 'Redundant receiver in `with_options`.'
62
62
 
63
- def_node_matcher :with_options?, <<~PATTERN
64
- (block
65
- (send nil? :with_options
66
- (...))
67
- (args
68
- $_arg)
69
- $_body)
70
- PATTERN
71
-
72
63
  def_node_search :all_block_nodes_in, <<~PATTERN
73
64
  (block ...)
74
65
  PATTERN
@@ -78,29 +69,40 @@ module RuboCop
78
69
  PATTERN
79
70
 
80
71
  def on_block(node)
81
- with_options?(node) do |arg, body|
82
- return if body.nil?
83
- return unless all_block_nodes_in(body).count.zero?
84
-
85
- send_nodes = all_send_nodes_in(body)
86
-
87
- if send_nodes.all? { |n| same_value?(arg, n.receiver) }
88
- send_nodes.each do |send_node|
89
- receiver = send_node.receiver
90
- add_offense(receiver.source_range) do |corrector|
91
- autocorrect(corrector, send_node)
92
- end
93
- end
72
+ return unless node.method?(:with_options)
73
+ return unless (body = node.body)
74
+ return unless all_block_nodes_in(body).count.zero?
75
+
76
+ send_nodes = all_send_nodes_in(body)
77
+ return unless redundant_receiver?(send_nodes, node)
78
+
79
+ send_nodes.each do |send_node|
80
+ receiver = send_node.receiver
81
+ add_offense(receiver.source_range) do |corrector|
82
+ autocorrect(corrector, send_node, node)
94
83
  end
95
84
  end
96
85
  end
97
86
 
87
+ alias on_numblock on_block
88
+
98
89
  private
99
90
 
100
- def autocorrect(corrector, node)
101
- corrector.remove(node.receiver.source_range)
102
- corrector.remove(node.loc.dot)
103
- corrector.remove(block_argument_range(node))
91
+ def autocorrect(corrector, send_node, node)
92
+ corrector.remove(send_node.receiver.source_range)
93
+ corrector.remove(send_node.loc.dot)
94
+ corrector.remove(block_argument_range(send_node)) unless node.numblock_type?
95
+ end
96
+
97
+ def redundant_receiver?(send_nodes, node)
98
+ proc = if node.numblock_type?
99
+ ->(n) { n.receiver.lvar_type? && n.receiver.source == '_1' }
100
+ else
101
+ arg = node.arguments.first
102
+ ->(n) { same_value?(arg, n.receiver) }
103
+ end
104
+
105
+ send_nodes.all?(&proc)
104
106
  end
105
107
 
106
108
  def block_argument_range(node)
@@ -34,12 +34,29 @@ module RuboCop
34
34
 
35
35
  def on_send(node)
36
36
  association_with_reflection(node) do |reflection_class_name|
37
+ return if reflection_class_name.value.send_type? && reflection_class_name.value.receiver.nil?
38
+ return if reflection_class_name.value.lvar_type? && str_assigned?(reflection_class_name)
39
+
37
40
  add_offense(reflection_class_name.loc.expression)
38
41
  end
39
42
  end
40
43
 
41
44
  private
42
45
 
46
+ def str_assigned?(reflection_class_name)
47
+ lvar = reflection_class_name.value.source
48
+
49
+ reflection_class_name.ancestors.each do |nodes|
50
+ return true if nodes.each_child_node(:lvasgn).detect do |node|
51
+ lhs, rhs = *node
52
+
53
+ lhs.to_s == lvar && ALLOWED_REFLECTION_CLASS_TYPES.include?(rhs.type)
54
+ end
55
+ end
56
+
57
+ false
58
+ end
59
+
43
60
  def reflection_class_value?(class_value)
44
61
  if class_value.send_type?
45
62
  !class_value.method?(:to_s) || class_value.receiver&.const_type?