rubocop-rails 2.17.4 → 2.19.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.
Files changed (78) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE.txt +1 -1
  3. data/README.md +22 -2
  4. data/config/default.yml +54 -29
  5. data/lib/rubocop/cop/mixin/enforce_superclass.rb +1 -1
  6. data/lib/rubocop/cop/mixin/index_method.rb +3 -3
  7. data/lib/rubocop/cop/rails/action_controller_flash_before_render.rb +10 -2
  8. data/lib/rubocop/cop/rails/action_controller_test_case.rb +1 -1
  9. data/lib/rubocop/cop/rails/action_order.rb +5 -6
  10. data/lib/rubocop/cop/rails/active_record_aliases.rb +2 -0
  11. data/lib/rubocop/cop/rails/active_record_callbacks_order.rb +6 -3
  12. data/lib/rubocop/cop/rails/add_column_index.rb +2 -2
  13. data/lib/rubocop/cop/rails/application_job.rb +1 -1
  14. data/lib/rubocop/cop/rails/arel_star.rb +1 -1
  15. data/lib/rubocop/cop/rails/assert_not.rb +1 -1
  16. data/lib/rubocop/cop/rails/belongs_to.rb +1 -4
  17. data/lib/rubocop/cop/rails/blank.rb +5 -5
  18. data/lib/rubocop/cop/rails/bulk_change_table.rb +1 -4
  19. data/lib/rubocop/cop/rails/compact_blank.rb +2 -2
  20. data/lib/rubocop/cop/rails/content_tag.rb +1 -1
  21. data/lib/rubocop/cop/rails/create_table_with_timestamps.rb +16 -3
  22. data/lib/rubocop/cop/rails/delegate.rb +17 -3
  23. data/lib/rubocop/cop/rails/delegate_allow_blank.rb +1 -1
  24. data/lib/rubocop/cop/rails/deprecated_active_model_errors_methods.rb +1 -1
  25. data/lib/rubocop/cop/rails/duration_arithmetic.rb +1 -1
  26. data/lib/rubocop/cop/rails/dynamic_find_by.rb +1 -1
  27. data/lib/rubocop/cop/rails/eager_evaluation_log_message.rb +1 -1
  28. data/lib/rubocop/cop/rails/enum_hash.rb +1 -1
  29. data/lib/rubocop/cop/rails/environment_comparison.rb +1 -1
  30. data/lib/rubocop/cop/rails/file_path.rb +31 -15
  31. data/lib/rubocop/cop/rails/find_by_id.rb +2 -2
  32. data/lib/rubocop/cop/rails/find_each.rb +6 -2
  33. data/lib/rubocop/cop/rails/freeze_time.rb +3 -0
  34. data/lib/rubocop/cop/rails/has_many_or_has_one_dependent.rb +2 -2
  35. data/lib/rubocop/cop/rails/http_positional_arguments.rb +18 -2
  36. data/lib/rubocop/cop/rails/http_status.rb +1 -1
  37. data/lib/rubocop/cop/rails/ignored_skip_action_filter_option.rb +0 -2
  38. data/lib/rubocop/cop/rails/inverse_of.rb +0 -3
  39. data/lib/rubocop/cop/rails/lexically_scoped_action_filter.rb +17 -7
  40. data/lib/rubocop/cop/rails/link_to_blank.rb +1 -1
  41. data/lib/rubocop/cop/rails/mailer_name.rb +1 -1
  42. data/lib/rubocop/cop/rails/negate_include.rb +1 -1
  43. data/lib/rubocop/cop/rails/not_null_column.rb +9 -6
  44. data/lib/rubocop/cop/rails/output.rb +3 -2
  45. data/lib/rubocop/cop/rails/output_safety.rb +5 -1
  46. data/lib/rubocop/cop/rails/pluck.rb +13 -1
  47. data/lib/rubocop/cop/rails/pluck_id.rb +1 -1
  48. data/lib/rubocop/cop/rails/presence.rb +3 -3
  49. data/lib/rubocop/cop/rails/present.rb +5 -5
  50. data/lib/rubocop/cop/rails/rake_environment.rb +1 -1
  51. data/lib/rubocop/cop/rails/read_write_attribute.rb +1 -1
  52. data/lib/rubocop/cop/rails/redundant_allow_nil.rb +3 -3
  53. data/lib/rubocop/cop/rails/redundant_foreign_key.rb +1 -1
  54. data/lib/rubocop/cop/rails/redundant_receiver_in_with_options.rb +1 -1
  55. data/lib/rubocop/cop/rails/reflection_class_name.rb +17 -1
  56. data/lib/rubocop/cop/rails/relative_date_constant.rb +2 -2
  57. data/lib/rubocop/cop/rails/response_parsed_body.rb +57 -0
  58. data/lib/rubocop/cop/rails/reversible_migration.rb +4 -29
  59. data/lib/rubocop/cop/rails/root_join_chain.rb +1 -1
  60. data/lib/rubocop/cop/rails/root_pathname_methods.rb +1 -1
  61. data/lib/rubocop/cop/rails/safe_navigation.rb +1 -1
  62. data/lib/rubocop/cop/rails/squished_sql_heredocs.rb +8 -1
  63. data/lib/rubocop/cop/rails/three_state_boolean_column.rb +71 -0
  64. data/lib/rubocop/cop/rails/time_zone.rb +2 -2
  65. data/lib/rubocop/cop/rails/transaction_exit_statement.rb +0 -2
  66. data/lib/rubocop/cop/rails/unique_validation_without_index.rb +1 -1
  67. data/lib/rubocop/cop/rails/unused_ignored_columns.rb +6 -1
  68. data/lib/rubocop/cop/rails/validation.rb +1 -1
  69. data/lib/rubocop/cop/rails/where_equals.rb +1 -1
  70. data/lib/rubocop/cop/rails/where_exists.rb +1 -1
  71. data/lib/rubocop/cop/rails/where_missing.rb +3 -3
  72. data/lib/rubocop/cop/rails/where_not.rb +1 -1
  73. data/lib/rubocop/cop/rails/where_not_with_multiple_conditions.rb +2 -2
  74. data/lib/rubocop/cop/rails_cops.rb +2 -0
  75. data/lib/rubocop/rails/version.rb +1 -1
  76. data/lib/rubocop/rails.rb +1 -1
  77. data/lib/rubocop-rails.rb +1 -0
  78. metadata +6 -4
@@ -78,7 +78,7 @@ module RuboCop
78
78
  def on_send(node)
79
79
  duration_arithmetic_argument?(node) do |*operation|
80
80
  add_offense(node) do |corrector|
81
- corrector.replace(node.source_range, corrected_source(*operation))
81
+ corrector.replace(node, corrected_source(*operation))
82
82
  end
83
83
  end
84
84
  end
@@ -99,7 +99,7 @@ module RuboCop
99
99
 
100
100
  def autocorrect_argument_keywords(corrector, node, keywords)
101
101
  keywords.each.with_index do |keyword, idx|
102
- corrector.insert_before(node.arguments[idx].loc.expression, keyword)
102
+ corrector.insert_before(node.arguments[idx], keyword)
103
103
  end
104
104
  end
105
105
 
@@ -59,7 +59,7 @@ module RuboCop
59
59
  private
60
60
 
61
61
  def replacement_range(node)
62
- stop = node.loc.expression.end
62
+ stop = node.source_range.end
63
63
  start = node.loc.selector.end
64
64
 
65
65
  if node.parenthesized_call?
@@ -42,7 +42,7 @@ module RuboCop
42
42
  "#{source(elem)} => #{index}"
43
43
  end.join(', ')
44
44
 
45
- corrector.replace(array.loc.expression, "{#{hash}}")
45
+ corrector.replace(array, "{#{hash}}")
46
46
  end
47
47
  end
48
48
  end
@@ -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.source_range, replacement)
87
+ corrector.replace(node, replacement)
88
88
  end
89
89
 
90
90
  def build_predicate_method(node)
@@ -3,34 +3,43 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Rails
6
- # Identifies usages of file path joining process
7
- # to use `Rails.root.join` clause. It is used to add uniformity when
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
9
  # @example EnforcedStyle: slashes (default)
11
10
  # # bad
12
11
  # Rails.root.join('app', 'models', 'goober')
12
+ #
13
+ # # good
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/models/goober')
21
+ # Rails.root.join('app/models/goober').to_s
18
22
  #
19
23
  # @example EnforcedStyle: arguments
20
24
  # # bad
21
25
  # Rails.root.join('app/models/goober')
26
+ #
27
+ # # good
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', 'models', 'goober')
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
@@ -53,7 +62,7 @@ module RuboCop
53
62
  return unless last_child_source.start_with?('.') || last_child_source.include?(File::SEPARATOR)
54
63
  return if last_child_source.start_with?(':')
55
64
 
56
- register_offense(node)
65
+ register_offense(node, require_to_s: true)
57
66
  end
58
67
 
59
68
  def on_send(node)
@@ -68,7 +77,7 @@ module RuboCop
68
77
  return unless file_join_nodes?(node)
69
78
  return unless node.arguments.any? { |e| rails_root_nodes?(e) }
70
79
 
71
- register_offense(node)
80
+ register_offense(node, require_to_s: true)
72
81
  end
73
82
 
74
83
  def check_for_rails_root_join_with_string_arguments(node)
@@ -78,7 +87,7 @@ module RuboCop
78
87
  return unless node.arguments.size > 1
79
88
  return unless node.arguments.all?(&:str_type?)
80
89
 
81
- register_offense(node)
90
+ register_offense(node, require_to_s: false)
82
91
  end
83
92
 
84
93
  def check_for_rails_root_join_with_slash_separated_path(node)
@@ -87,21 +96,28 @@ module RuboCop
87
96
  return unless rails_root_join_nodes?(node)
88
97
  return unless node.arguments.any? { |arg| string_with_slash?(arg) }
89
98
 
90
- register_offense(node)
99
+ register_offense(node, require_to_s: false)
91
100
  end
92
101
 
93
102
  def string_with_slash?(node)
94
103
  node.str_type? && node.source.include?('/')
95
104
  end
96
105
 
97
- def register_offense(node)
106
+ def register_offense(node, require_to_s:)
98
107
  line_range = node.loc.column...node.loc.last_column
99
108
  source_range = source_range(processed_source.buffer, node.first_line, line_range)
100
- add_offense(source_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)
101
114
  end
102
115
 
103
- def message(_range)
104
- format(style == :arguments ? MSG_ARGUMENTS : MSG_SLASHES)
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)
105
121
  end
106
122
  end
107
123
  end
@@ -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.loc.expression.end_pos)
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.loc.expression.end_pos)
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
- # Identifies usages of `all.each` and
7
- # change them to use `all.find_each` instead.
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
@@ -26,6 +26,9 @@ module RuboCop
26
26
  #
27
27
  class FreezeTime < Base
28
28
  extend AutoCorrector
29
+ extend TargetRailsVersion
30
+
31
+ minimum_target_rails_version 5.2
29
32
 
30
33
  MSG = 'Use `freeze_time` instead of `travel_to`.'
31
34
  NOW_METHODS = %i[now new current].freeze
@@ -41,11 +41,11 @@ module RuboCop
41
41
  PATTERN
42
42
 
43
43
  def_node_matcher :association_without_options?, <<~PATTERN
44
- (send nil? {:has_many :has_one} _)
44
+ (send _ {:has_many :has_one} _)
45
45
  PATTERN
46
46
 
47
47
  def_node_matcher :association_with_options?, <<~PATTERN
48
- (send nil? {:has_many :has_one} ... (hash $...))
48
+ (send _ {:has_many :has_one} ... (hash $...))
49
49
  PATTERN
50
50
 
51
51
  def_node_matcher :dependent_option?, <<~PATTERN
@@ -10,6 +10,9 @@ module RuboCop
10
10
  # Rails/HttpPositionalArguments cop or set your TargetRailsVersion in your
11
11
  # .rubocop.yml file to 4.2.
12
12
  #
13
+ # NOTE: It does not detect any cases where `include Rack::Test::Methods` is used
14
+ # which makes the http methods incompatible behavior.
15
+ #
13
16
  # @example
14
17
  # # bad
15
18
  # get :new, { user_id: 1}
@@ -37,8 +40,15 @@ module RuboCop
37
40
  (hash (kwsplat _))
38
41
  PATTERN
39
42
 
43
+ def_node_matcher :include_rack_test_methods?, <<~PATTERN
44
+ (send nil? :include
45
+ (const
46
+ (const
47
+ (const {nil? cbase} :Rack) :Test) :Methods))
48
+ PATTERN
49
+
40
50
  def on_send(node)
41
- return if in_routing_block?(node)
51
+ return if in_routing_block?(node) || use_rack_test_methods?
42
52
 
43
53
  http_request?(node) do |data|
44
54
  return unless needs_conversion?(data)
@@ -56,7 +66,7 @@ module RuboCop
56
66
  # that represents the path/action on the Rails controller
57
67
  # the data is the http parameters and environment sent in
58
68
  # the Rails 5 http call
59
- corrector.replace(node.loc.expression, correction(node))
69
+ corrector.replace(node, correction(node))
60
70
  end
61
71
  end
62
72
  end
@@ -67,6 +77,12 @@ module RuboCop
67
77
  !!node.each_ancestor(:block).detect { |block| ROUTING_METHODS.include?(block.method_name) }
68
78
  end
69
79
 
80
+ def use_rack_test_methods?
81
+ processed_source.ast.each_descendant(:send).any? do |node|
82
+ include_rack_test_methods?(node)
83
+ end
84
+ end
85
+
70
86
  def needs_conversion?(data)
71
87
  return true unless data.hash_type?
72
88
  return false if kwsplat_hash?(data)
@@ -66,7 +66,7 @@ module RuboCop
66
66
  return unless checker.offensive?
67
67
 
68
68
  add_offense(checker.node, message: checker.message) do |corrector|
69
- corrector.replace(checker.node.loc.expression, checker.preferred_style)
69
+ corrector.replace(checker.node, checker.preferred_style)
70
70
  end
71
71
  end
72
72
  end
@@ -35,8 +35,6 @@ module RuboCop
35
35
  # skip_before_action :login_required,
36
36
  # if: -> { trusted_origin? && action_name != "admin" }
37
37
  # end
38
- #
39
- # @see https://api.rubyonrails.org/classes/AbstractController/Callbacks/ClassMethods.html#method-i-_normalize_callback_options
40
38
  class IgnoredSkipActionFilterOption < Base
41
39
  MSG = <<~MSG.chomp.freeze
42
40
  `%<ignore>s` option will be ignored when `%<prefer>s` and `%<ignore>s` are used together.
@@ -137,9 +137,6 @@ module RuboCop
137
137
  # class Blog < ApplicationRecord
138
138
  # has_many :posts, -> { order(published_at: :desc) }
139
139
  # end
140
- #
141
- # @see https://guides.rubyonrails.org/association_basics.html#bi-directional-associations
142
- # @see https://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html#module-ActiveRecord::Associations::ClassMethods-label-Setting+Inverses
143
140
  class InverseOf < Base
144
141
  SPECIFY_MSG = 'Specify an `:inverse_of` option.'
145
142
  NIL_MSG = 'You specified `inverse_of: nil`, you probably meant to use `inverse_of: false`.'
@@ -144,19 +144,29 @@ module RuboCop
144
144
  end
145
145
 
146
146
  def aliased_action_methods(node, defined_methods)
147
- alias_methods = node.each_child_node(:send).select { |send_node| send_node.method?(:alias_method) }
148
-
149
- hash_of_alias_methods = alias_methods.each_with_object({}) do |alias_method, result|
150
- result[alias_method.last_argument.value] = alias_method.first_argument.value
151
- end
152
-
147
+ alias_methods = alias_methods(node)
153
148
  defined_methods.each_with_object([]) do |defined_method, aliased_method|
154
- if (new_method_name = hash_of_alias_methods[defined_method])
149
+ if (new_method_name = alias_methods[defined_method])
155
150
  aliased_method << new_method_name
156
151
  end
157
152
  end
158
153
  end
159
154
 
155
+ def alias_methods(node)
156
+ result = {}
157
+ node.each_child_node(:send, :alias) do |child_node|
158
+ case child_node.type
159
+ when :send
160
+ if child_node.method?(:alias_method)
161
+ result[child_node.last_argument.value] = child_node.first_argument.value
162
+ end
163
+ when :alias
164
+ result[child_node.old_identifier.value] = child_node.new_identifier.value
165
+ end
166
+ end
167
+ result
168
+ end
169
+
160
170
  # @param node [RuboCop::AST::Node]
161
171
  # @return [Array<Symbol>]
162
172
  def array_values(node) # rubocop:disable Metrics/MethodLength
@@ -68,7 +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(begin_pos: 1, end_pos: -1)
71
+ str_range = rel_node.children.last.source_range.adjust(begin_pos: 1, end_pos: -1)
72
72
  corrector.replace(str_range, "#{existing_rel} noopener")
73
73
  end
74
74
 
@@ -77,7 +77,7 @@ module RuboCop
77
77
  corrector.replace(node.loc.name, "#{name}Mailer")
78
78
  else
79
79
  name = node.children.last
80
- corrector.replace(node.source_range, "#{name}Mailer")
80
+ corrector.replace(node, "#{name}Mailer")
81
81
  end
82
82
  end
83
83
 
@@ -26,7 +26,7 @@ module RuboCop
26
26
  RESTRICT_ON_SEND = %i[!].freeze
27
27
 
28
28
  def_node_matcher :negate_include_call?, <<~PATTERN
29
- (send (send $_ :include? $_) :!)
29
+ (send (send $!nil? :include? $_) :!)
30
30
  PATTERN
31
31
 
32
32
  def on_send(node)
@@ -21,7 +21,7 @@ module RuboCop
21
21
  RESTRICT_ON_SEND = %i[add_column add_reference].freeze
22
22
 
23
23
  def_node_matcher :add_not_null_column?, <<~PATTERN
24
- (send nil? :add_column _ _ _ (hash $...))
24
+ (send nil? :add_column _ _ $_ (hash $...))
25
25
  PATTERN
26
26
 
27
27
  def_node_matcher :add_not_null_reference?, <<~PATTERN
@@ -44,17 +44,20 @@ module RuboCop
44
44
  private
45
45
 
46
46
  def check_add_column(node)
47
- pairs = add_not_null_column?(node)
48
- check_pairs(pairs)
47
+ add_not_null_column?(node) do |type, pairs|
48
+ return if type.value == :virtual || type.value == 'virtual'
49
+
50
+ check_pairs(pairs)
51
+ end
49
52
  end
50
53
 
51
54
  def check_add_reference(node)
52
- pairs = add_not_null_reference?(node)
53
- check_pairs(pairs)
55
+ add_not_null_reference?(node) do |pairs|
56
+ check_pairs(pairs)
57
+ end
54
58
  end
55
59
 
56
60
  def check_pairs(pairs)
57
- return unless pairs
58
61
  return if pairs.any? { |pair| default_option?(pair) }
59
62
 
60
63
  null_false = pairs.find { |pair| null_false?(pair) }
@@ -39,7 +39,8 @@ module RuboCop
39
39
  PATTERN
40
40
 
41
41
  def on_send(node)
42
- return unless (output?(node) || io_output?(node)) && node.arguments?
42
+ return if node.parent&.call_type?
43
+ return unless output?(node) || io_output?(node)
43
44
 
44
45
  range = offense_range(node)
45
46
 
@@ -56,7 +57,7 @@ module RuboCop
56
57
 
57
58
  def offense_range(node)
58
59
  if node.receiver
59
- range_between(node.loc.expression.begin_pos, node.loc.selector.end_pos)
60
+ range_between(node.source_range.begin_pos, node.loc.selector.end_pos)
60
61
  else
61
62
  node.loc.selector
62
63
  end
@@ -66,8 +66,12 @@ module RuboCop
66
66
  MSG = 'Tagging a string as html safe may be a security risk.'
67
67
  RESTRICT_ON_SEND = %i[html_safe raw safe_concat].freeze
68
68
 
69
+ def_node_search :i18n_method?, <<~PATTERN
70
+ (send {nil? (const {nil? cbase} :I18n)} {:t :translate :l :localize} ...)
71
+ PATTERN
72
+
69
73
  def on_send(node)
70
- return if non_interpolated_string?(node)
74
+ return if non_interpolated_string?(node) || i18n_method?(node)
71
75
 
72
76
  return unless looks_like_rails_html_safe?(node) ||
73
77
  looks_like_rails_raw?(node) ||
@@ -9,6 +9,18 @@ module RuboCop
9
9
  # element in an enumerable. When called on an Active Record relation, it
10
10
  # results in a more efficient query that only selects the necessary key.
11
11
  #
12
+ # @safety
13
+ # This cop is unsafe because model can use column aliases.
14
+ #
15
+ # [source,ruby]
16
+ # ----
17
+ # # Original code
18
+ # User.select('name AS nickname').map { |user| user[:nickname] } # => array of nicknames
19
+ #
20
+ # # After autocorrection
21
+ # User.select('name AS nickname').pluck(:nickname) # => raises ActiveRecord::StatementInvalid
22
+ # ----
23
+ #
12
24
  # @example
13
25
  # # bad
14
26
  # Post.published.map { |post| post[:title] }
@@ -31,7 +43,7 @@ module RuboCop
31
43
 
32
44
  def on_block(node)
33
45
  pluck_candidate?(node) do |argument, key|
34
- next unless use_one_block_argument?(argument)
46
+ next if key.regexp_type? || !use_one_block_argument?(argument)
35
47
 
36
48
  match = if node.block_type?
37
49
  block_argument = argument.children.first.source
@@ -51,7 +51,7 @@ module RuboCop
51
51
  private
52
52
 
53
53
  def offense_range(node)
54
- range_between(node.loc.selector.begin_pos, node.loc.expression.end_pos)
54
+ range_between(node.loc.selector.begin_pos, node.source_range.end_pos)
55
55
  end
56
56
  end
57
57
  end
@@ -93,7 +93,7 @@ module RuboCop
93
93
 
94
94
  def register_offense(node, receiver, other)
95
95
  add_offense(node, message: message(node, receiver, other)) do |corrector|
96
- corrector.replace(node.source_range, replacement(receiver, other, node.left_sibling))
96
+ corrector.replace(node, replacement(receiver, other, node.left_sibling))
97
97
  end
98
98
  end
99
99
 
@@ -112,10 +112,10 @@ module RuboCop
112
112
  end
113
113
 
114
114
  def current(node)
115
- if node.source.include?("\n")
115
+ if !node.ternary? && node.source.include?("\n")
116
116
  "#{node.loc.keyword.with(end_pos: node.condition.loc.selector.end_pos).source} ... end"
117
117
  else
118
- node.source
118
+ node.source.gsub(/\n\s*/, ' ')
119
119
  end
120
120
  end
121
121
 
@@ -8,7 +8,7 @@ module RuboCop
8
8
  #
9
9
  # Interaction with `Style/UnlessElse`:
10
10
  # The configuration of `NotBlank` will not produce an offense in the
11
- # context of `unless else` if `Style/UnlessElse` is inabled. This is
11
+ # context of `unless else` if `Style/UnlessElse` is enabled. This is
12
12
  # to prevent interference between the autocorrection of the two cops.
13
13
  #
14
14
  # @example NotNilAndNotEmpty: true (default)
@@ -128,10 +128,10 @@ module RuboCop
128
128
 
129
129
  if method_call
130
130
  corrector.replace(node.loc.keyword, 'if')
131
- range = method_call.loc.expression
131
+ range = method_call.source_range
132
132
  else
133
133
  variable1, _variable2 = exists_and_not_empty?(node) || not_blank?(node)
134
- range = node.loc.expression
134
+ range = node.source_range
135
135
  end
136
136
 
137
137
  corrector.replace(range, replacement(variable1))
@@ -141,9 +141,9 @@ module RuboCop
141
141
 
142
142
  def unless_condition(node, method_call)
143
143
  if node.modifier_form?
144
- node.loc.keyword.join(node.loc.expression.end)
144
+ node.loc.keyword.join(node.source_range.end)
145
145
  else
146
- node.loc.expression.begin.join(method_call.loc.expression)
146
+ node.source_range.begin.join(method_call.source_range)
147
147
  end
148
148
  end
149
149
 
@@ -48,7 +48,7 @@ module RuboCop
48
48
  task_name = task_method.arguments[0]
49
49
  task_dependency = correct_task_dependency(task_name)
50
50
 
51
- corrector.replace(task_name.loc.expression, task_dependency)
51
+ corrector.replace(task_name, task_dependency)
52
52
  end
53
53
  end
54
54
  end
@@ -52,7 +52,7 @@ module RuboCop
52
52
  return if within_shadowing_method?(node)
53
53
 
54
54
  add_offense(node, message: build_message(node)) do |corrector|
55
- corrector.replace(node.source_range, node_replacement(node))
55
+ corrector.replace(node, node_replacement(node))
56
56
  end
57
57
  end
58
58
 
@@ -62,7 +62,7 @@ module RuboCop
62
62
  elsif prv_sib
63
63
  corrector.remove(range_between(node_end(prv_sib), node_end(allow_nil)))
64
64
  else
65
- corrector.remove(allow_nil.loc.expression)
65
+ corrector.remove(allow_nil)
66
66
  end
67
67
  end
68
68
  end
@@ -87,11 +87,11 @@ module RuboCop
87
87
  end
88
88
 
89
89
  def node_beg(node)
90
- node.loc.expression.begin_pos
90
+ node.source_range.begin_pos
91
91
  end
92
92
 
93
93
  def node_end(node)
94
- node.loc.expression.end_pos
94
+ node.source_range.end_pos
95
95
  end
96
96
  end
97
97
  end
@@ -40,7 +40,7 @@ module RuboCop
40
40
  def on_send(node)
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
- add_offense(foreign_key_pair.loc.expression) do |corrector|
43
+ add_offense(foreign_key_pair.source_range) do |corrector|
44
44
  range = range_with_surrounding_space(foreign_key_pair.source_range, side: :left)
45
45
  range = range_with_surrounding_comma(range, :left)
46
46
 
@@ -89,7 +89,7 @@ module RuboCop
89
89
  private
90
90
 
91
91
  def autocorrect(corrector, send_node, node)
92
- corrector.remove(send_node.receiver.source_range)
92
+ corrector.remove(send_node.receiver)
93
93
  corrector.remove(send_node.loc.dot)
94
94
  corrector.remove(block_argument_range(send_node)) unless node.numblock_type?
95
95
  end
@@ -18,6 +18,8 @@ module RuboCop
18
18
  # # good
19
19
  # has_many :accounts, class_name: 'Account'
20
20
  class ReflectionClassName < Base
21
+ extend AutoCorrector
22
+
21
23
  MSG = 'Use a string value for `class_name`.'
22
24
  RESTRICT_ON_SEND = %i[has_many has_one belongs_to].freeze
23
25
  ALLOWED_REFLECTION_CLASS_TYPES = %i[dstr str sym].freeze
@@ -32,12 +34,18 @@ module RuboCop
32
34
  (pair (sym :class_name) #reflection_class_value?)
33
35
  PATTERN
34
36
 
37
+ def_node_matcher :const_or_string, <<~PATTERN
38
+ {$(const nil? _) (send $(const nil? _) :name) (send $(const nil? _) :to_s)}
39
+ PATTERN
40
+
35
41
  def on_send(node)
36
42
  association_with_reflection(node) do |reflection_class_name|
37
43
  return if reflection_class_name.value.send_type? && reflection_class_name.value.receiver.nil?
38
44
  return if reflection_class_name.value.lvar_type? && str_assigned?(reflection_class_name)
39
45
 
40
- add_offense(reflection_class_name.loc.expression)
46
+ add_offense(reflection_class_name.source_range) do |corrector|
47
+ autocorrect(corrector, reflection_class_name)
48
+ end
41
49
  end
42
50
  end
43
51
 
@@ -64,6 +72,14 @@ module RuboCop
64
72
  !ALLOWED_REFLECTION_CLASS_TYPES.include?(class_value.type)
65
73
  end
66
74
  end
75
+
76
+ def autocorrect(corrector, class_config)
77
+ class_value = class_config.value
78
+ replacement = const_or_string(class_value)
79
+ return unless replacement.present?
80
+
81
+ corrector.replace(class_value, replacement.source.inspect)
82
+ end
67
83
  end
68
84
  end
69
85
  end
@@ -78,7 +78,7 @@ module RuboCop
78
78
  indent = ' ' * node.loc.column
79
79
  new_code = ["def self.#{const_name.downcase}", "#{indent}#{value.source}", 'end'].join("\n#{indent}")
80
80
 
81
- corrector.replace(node.source_range, new_code)
81
+ corrector.replace(node, new_code)
82
82
  end
83
83
 
84
84
  def message(method_name)
@@ -86,7 +86,7 @@ module RuboCop
86
86
  end
87
87
 
88
88
  def offense_range(name, value)
89
- range_between(name.loc.expression.begin_pos, value.loc.expression.end_pos)
89
+ range_between(name.source_range.begin_pos, value.source_range.end_pos)
90
90
  end
91
91
 
92
92
  def nested_relative_date(node, &callback)