rubocop-rails 2.18.0 → 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 (60) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +22 -2
  3. data/config/default.yml +12 -13
  4. data/lib/rubocop/cop/mixin/enforce_superclass.rb +1 -1
  5. data/lib/rubocop/cop/mixin/index_method.rb +3 -3
  6. data/lib/rubocop/cop/rails/action_order.rb +5 -6
  7. data/lib/rubocop/cop/rails/active_record_callbacks_order.rb +6 -3
  8. data/lib/rubocop/cop/rails/add_column_index.rb +2 -2
  9. data/lib/rubocop/cop/rails/application_job.rb +1 -1
  10. data/lib/rubocop/cop/rails/arel_star.rb +1 -1
  11. data/lib/rubocop/cop/rails/assert_not.rb +1 -1
  12. data/lib/rubocop/cop/rails/belongs_to.rb +1 -1
  13. data/lib/rubocop/cop/rails/blank.rb +4 -4
  14. data/lib/rubocop/cop/rails/compact_blank.rb +2 -2
  15. data/lib/rubocop/cop/rails/content_tag.rb +1 -1
  16. data/lib/rubocop/cop/rails/create_table_with_timestamps.rb +16 -3
  17. data/lib/rubocop/cop/rails/delegate.rb +17 -3
  18. data/lib/rubocop/cop/rails/delegate_allow_blank.rb +1 -1
  19. data/lib/rubocop/cop/rails/duration_arithmetic.rb +1 -1
  20. data/lib/rubocop/cop/rails/dynamic_find_by.rb +1 -1
  21. data/lib/rubocop/cop/rails/eager_evaluation_log_message.rb +1 -1
  22. data/lib/rubocop/cop/rails/enum_hash.rb +1 -1
  23. data/lib/rubocop/cop/rails/environment_comparison.rb +1 -1
  24. data/lib/rubocop/cop/rails/file_path.rb +31 -15
  25. data/lib/rubocop/cop/rails/find_by_id.rb +2 -2
  26. data/lib/rubocop/cop/rails/find_each.rb +6 -2
  27. data/lib/rubocop/cop/rails/http_positional_arguments.rb +18 -2
  28. data/lib/rubocop/cop/rails/http_status.rb +1 -1
  29. data/lib/rubocop/cop/rails/link_to_blank.rb +1 -1
  30. data/lib/rubocop/cop/rails/mailer_name.rb +1 -1
  31. data/lib/rubocop/cop/rails/output.rb +3 -2
  32. data/lib/rubocop/cop/rails/output_safety.rb +5 -1
  33. data/lib/rubocop/cop/rails/pluck.rb +1 -1
  34. data/lib/rubocop/cop/rails/pluck_id.rb +1 -1
  35. data/lib/rubocop/cop/rails/presence.rb +1 -1
  36. data/lib/rubocop/cop/rails/present.rb +4 -4
  37. data/lib/rubocop/cop/rails/rake_environment.rb +1 -1
  38. data/lib/rubocop/cop/rails/read_write_attribute.rb +1 -1
  39. data/lib/rubocop/cop/rails/redundant_allow_nil.rb +3 -3
  40. data/lib/rubocop/cop/rails/redundant_foreign_key.rb +1 -1
  41. data/lib/rubocop/cop/rails/redundant_receiver_in_with_options.rb +1 -1
  42. data/lib/rubocop/cop/rails/reflection_class_name.rb +17 -1
  43. data/lib/rubocop/cop/rails/relative_date_constant.rb +2 -2
  44. data/lib/rubocop/cop/rails/response_parsed_body.rb +3 -3
  45. data/lib/rubocop/cop/rails/root_join_chain.rb +1 -1
  46. data/lib/rubocop/cop/rails/root_pathname_methods.rb +1 -1
  47. data/lib/rubocop/cop/rails/safe_navigation.rb +1 -1
  48. data/lib/rubocop/cop/rails/three_state_boolean_column.rb +71 -0
  49. data/lib/rubocop/cop/rails/time_zone.rb +2 -2
  50. data/lib/rubocop/cop/rails/unique_validation_without_index.rb +1 -1
  51. data/lib/rubocop/cop/rails/validation.rb +1 -1
  52. data/lib/rubocop/cop/rails/where_equals.rb +1 -1
  53. data/lib/rubocop/cop/rails/where_exists.rb +1 -1
  54. data/lib/rubocop/cop/rails/where_missing.rb +3 -3
  55. data/lib/rubocop/cop/rails/where_not.rb +1 -1
  56. data/lib/rubocop/cop/rails/where_not_with_multiple_conditions.rb +2 -2
  57. data/lib/rubocop/cop/rails_cops.rb +1 -0
  58. data/lib/rubocop/rails/version.rb +1 -1
  59. data/lib/rubocop-rails.rb +1 -0
  60. metadata +5 -4
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8f1cbc229165ee81ea84fc26d1c6482f917d8e8177827b139cf36974acff0176
4
- data.tar.gz: 23cefe2f0434e5ef4c86856221f1336bfc55ffbacfd09f2dc9a24552b633d355
3
+ metadata.gz: 327dd4bed957b6be1d52e47a9087f43abf7f7361ddaf8b0c3b13dbb0bf7bbb52
4
+ data.tar.gz: cf2c5747f8abab6e65ff8ffc9d31693c42c0515e8751a1d5b0651c12c7ceb93a
5
5
  SHA512:
6
- metadata.gz: 59f9af07f060ff82a64bbf9db4af4d8ebb56dfada8310073bca25fde87736ef8fa0891e6f3ba997e8b847eef6218d93f25739b8022a8cb68e9aae970e8b2c674
7
- data.tar.gz: a4415117082d7ccaeb8349f1ee31c9dba95bb6ea54bed77b176bcdd59b03cf4e2702f99c05414ff1e9028c48f96dce2f729eb2a2b98f91183cba3cb143e08894
6
+ metadata.gz: 4114a576ae595944cd0ec1b673e8f706fa975a643fb9d56e25b5498b7964f5141e2724aeb2dc24c6b63f6d501c7e1a85469a32333be69862e054fdb10874f09c
7
+ data.tar.gz: c87e88b3de8ea166a68a0be6a08e70e387790b3d705648145a8d769978f1c92e03ea18fe510b1ce5543c6f1fefe59be1f0fd583ba392dd2274b1dde58a21ca61
data/README.md CHANGED
@@ -12,7 +12,7 @@ Note: This repository manages rubocop-rails gem (>= 2.0.0). rubocop-rails gem (<
12
12
  Just install the `rubocop-rails` gem
13
13
 
14
14
  ```sh
15
- gem install rubocop-rails
15
+ $ gem install rubocop-rails
16
16
  ```
17
17
 
18
18
  or if you use bundler put this in your `Gemfile`
@@ -48,7 +48,7 @@ cops together with the standard cops.
48
48
  ### Command line
49
49
 
50
50
  ```sh
51
- rubocop --require rubocop-rails
51
+ $ rubocop --require rubocop-rails
52
52
  ```
53
53
 
54
54
  Note: `--rails` option is required while `rubocop` command supports `--rails` option.
@@ -61,6 +61,26 @@ RuboCop::RakeTask.new do |task|
61
61
  end
62
62
  ```
63
63
 
64
+ ## Rails configuration tip
65
+
66
+ If you are using Rails 6.1 or newer, add the following `config.generators.after_generate` setting to
67
+ your config/application.rb to apply RuboCop autocorrection to code generated by `bin/rails g`.
68
+
69
+ ```ruby
70
+ # config/application.rb
71
+ module YourCoolApp
72
+ class Application < Rails::Application
73
+ config.generators.after_generate do |files|
74
+ system("bundle exec rubocop -A --fail-level=E #{files.shelljoin}", exception: true)
75
+ end
76
+ end
77
+ end
78
+ ```
79
+
80
+ It uses `rubocop -A` to apply `Style/FrozenStringLiteralComment` and other unsafe autocorretion cops.
81
+ `rubocop -A` is unsafe autocorrection, but code generated by default is simple and less likely to
82
+ be incompatible with `rubocop -A`. If you have problems you can replace it with `rubocop -a` instead.
83
+
64
84
  ## The Cops
65
85
 
66
86
  All cops are located under
data/config/default.yml CHANGED
@@ -53,8 +53,6 @@ Rails:
53
53
 
54
54
  Rails/ActionControllerFlashBeforeRender:
55
55
  Description: 'Use `flash.now` instead of `flash` before `render`.'
56
- StyleGuide: 'https://rails.rubystyle.guide/#flash-before-render'
57
- Reference: 'https://api.rubyonrails.org/classes/ActionController/FlashBeforeRender.html'
58
56
  Enabled: 'pending'
59
57
  SafeAutoCorrect: false
60
58
  VersionAdded: '2.16'
@@ -462,8 +460,9 @@ Rails/FindEach:
462
460
  Description: 'Prefer all.find_each over all.each.'
463
461
  StyleGuide: 'https://rails.rubystyle.guide#find-each'
464
462
  Enabled: true
463
+ Safe: false
465
464
  VersionAdded: '0.30'
466
- VersionChanged: '2.9'
465
+ VersionChanged: '2.19'
467
466
  Include:
468
467
  - app/models/**/*.rb
469
468
  AllowedMethods:
@@ -844,8 +843,9 @@ Rails/RequireDependency:
844
843
  Rails/ResponseParsedBody:
845
844
  Description: Prefer `response.parsed_body` to `JSON.parse(response.body)`.
846
845
  Enabled: pending
847
- SafeAutoCorrect: false
846
+ Safe: false
848
847
  VersionAdded: '2.18'
848
+ VersionChanged: '2.19'
849
849
  Include:
850
850
  - spec/controllers/**/*.rb
851
851
  - spec/requests/**/*.rb
@@ -997,6 +997,14 @@ Rails/TableNameAssignment:
997
997
  Include:
998
998
  - app/models/**/*.rb
999
999
 
1000
+ Rails/ThreeStateBooleanColumn:
1001
+ Description: 'Add a default value and a `NOT NULL` constraint to boolean columns.'
1002
+ StyleGuide: 'https://rails.rubystyle.guide/#three-state-boolean'
1003
+ Enabled: pending
1004
+ VersionAdded: '2.19'
1005
+ Include:
1006
+ - db/**/*.rb
1007
+
1000
1008
  Rails/TimeZone:
1001
1009
  Description: 'Checks the correct usage of time zone aware methods.'
1002
1010
  StyleGuide: 'https://rails.rubystyle.guide#time'
@@ -1144,15 +1152,6 @@ Style/FormatStringToken:
1144
1152
  AllowedMethods:
1145
1153
  - redirect
1146
1154
 
1147
- Style/InverseMethods:
1148
- # `InverseMethods` are methods that can be inverted by a not (`not` or `!`)
1149
- # The relationship of inverse methods only needs to be defined in one direction.
1150
- # Keys and values both need to be defined as symbols.
1151
- InverseMethods:
1152
- :present?: :blank?
1153
- :include?: :exclude?
1154
- :valid?: :invalid?
1155
-
1156
1155
  Style/SymbolProc:
1157
1156
  AllowedMethods:
1158
1157
  - define_method
@@ -32,7 +32,7 @@ module RuboCop
32
32
 
33
33
  def register_offense(offense_node)
34
34
  add_offense(offense_node) do |corrector|
35
- corrector.replace(offense_node.source_range, self.class::SUPERCLASS)
35
+ corrector.replace(offense_node, self.class::SUPERCLASS)
36
36
  end
37
37
  end
38
38
  end
@@ -138,7 +138,7 @@ module RuboCop
138
138
  end
139
139
 
140
140
  def strip_prefix_and_suffix(node, corrector)
141
- expression = node.loc.expression
141
+ expression = node.source_range
142
142
  corrector.remove_leading(expression, leading)
143
143
  corrector.remove_trailing(expression, trailing)
144
144
  end
@@ -153,11 +153,11 @@ module RuboCop
153
153
  end
154
154
 
155
155
  def set_new_arg_name(transformed_argname, corrector)
156
- corrector.replace(block_node.arguments.loc.expression, "|#{transformed_argname}|")
156
+ corrector.replace(block_node.arguments, "|#{transformed_argname}|")
157
157
  end
158
158
 
159
159
  def set_new_body_expression(transforming_body_expr, corrector)
160
- corrector.replace(block_node.body.loc.expression, transforming_body_expr.loc.expression.source)
160
+ corrector.replace(block_node.body, transforming_body_expr.source)
161
161
  end
162
162
  end
163
163
  end
@@ -92,12 +92,11 @@ module RuboCop
92
92
  end
93
93
 
94
94
  def range_with_comments(node)
95
- ranges = [
96
- node,
97
- *processed_source.ast_with_comments[node]
98
- ].map do |element|
99
- element.location.expression
100
- end
95
+ # rubocop:todo InternalAffairs/LocationExpression
96
+ # Using `RuboCop::Ext::Comment#source_range` requires RuboCop > 1.46,
97
+ # which introduces https://github.com/rubocop/rubocop/pull/11630.
98
+ ranges = [node, *processed_source.ast_with_comments[node]].map { |comment| comment.loc.expression }
99
+ # rubocop:enable InternalAffairs/LocationExpression
101
100
  ranges.reduce do |result, range|
102
101
  add_range(result, range)
103
102
  end
@@ -104,7 +104,7 @@ module RuboCop
104
104
  end
105
105
 
106
106
  def end_position_for(node)
107
- end_line = buffer.line_for_position(node.loc.expression.end_pos)
107
+ end_line = buffer.line_for_position(node.source_range.end_pos)
108
108
  buffer.line_range(end_line).end_pos
109
109
  end
110
110
 
@@ -112,8 +112,7 @@ module RuboCop
112
112
  annotation_line = node.first_line - 1
113
113
  first_comment = nil
114
114
 
115
- processed_source.comments_before_line(annotation_line)
116
- .reverse_each do |comment|
115
+ processed_source.each_comment_in_lines(0..annotation_line).reverse_each do |comment|
117
116
  if comment.location.line == annotation_line && !inline_comment?(comment)
118
117
  first_comment = comment
119
118
  annotation_line -= 1
@@ -124,7 +123,11 @@ module RuboCop
124
123
  end
125
124
 
126
125
  def inline_comment?(comment)
126
+ # rubocop:todo InternalAffairs/LocationExpression
127
+ # Using `RuboCop::Ext::Comment#source_range` requires RuboCop > 1.46,
128
+ # which introduces https://github.com/rubocop/rubocop/pull/11630.
127
129
  !comment_line?(comment.loc.expression.source_line)
130
+ # rubocop:enable InternalAffairs/LocationExpression
128
131
  end
129
132
 
130
133
  def start_line_position(node)
@@ -42,7 +42,7 @@ module RuboCop
42
42
  add_index_opts = ''
43
43
 
44
44
  if value.hash_type?
45
- hash = value.loc.expression.adjust(begin_pos: 1, end_pos: -1).source.strip
45
+ hash = value.source_range.adjust(begin_pos: 1, end_pos: -1).source.strip
46
46
  add_index_opts = ", #{hash}"
47
47
  end
48
48
 
@@ -53,7 +53,7 @@ module RuboCop
53
53
  private
54
54
 
55
55
  def index_range(pair_node)
56
- range_with_surrounding_comma(range_with_surrounding_space(pair_node.loc.expression, side: :left), :left)
56
+ range_with_surrounding_comma(range_with_surrounding_space(pair_node.source_range, side: :left), :left)
57
57
  end
58
58
  end
59
59
  end
@@ -36,7 +36,7 @@ module RuboCop
36
36
 
37
37
  def autocorrect(node)
38
38
  lambda do |corrector|
39
- corrector.replace(node.source_range, self.class::SUPERCLASS)
39
+ corrector.replace(node, self.class::SUPERCLASS)
40
40
  end
41
41
  end
42
42
  end
@@ -38,7 +38,7 @@ module RuboCop
38
38
  return unless (star = star_bracket?(node))
39
39
 
40
40
  add_offense(star) do |corrector|
41
- corrector.replace(star.loc.expression, 'Arel.star')
41
+ corrector.replace(star, 'Arel.star')
42
42
  end
43
43
  end
44
44
  end
@@ -25,7 +25,7 @@ module RuboCop
25
25
  return unless offensive?(node)
26
26
 
27
27
  add_offense(node) do |corrector|
28
- expression = node.loc.expression
28
+ expression = node.source_range
29
29
 
30
30
  corrector.replace(expression, corrected_source(expression.source))
31
31
  end
@@ -80,7 +80,7 @@ module RuboCop
80
80
  end
81
81
 
82
82
  add_offense(node.loc.selector, message: message) do |corrector|
83
- corrector.replace(option_node.loc.expression, replacement)
83
+ corrector.replace(option_node, replacement)
84
84
  end
85
85
  end
86
86
  end
@@ -142,10 +142,10 @@ module RuboCop
142
142
 
143
143
  if method_call
144
144
  corrector.replace(node.loc.keyword, 'if')
145
- range = method_call.loc.expression
145
+ range = method_call.source_range
146
146
  else
147
147
  variable1, _variable2 = nil_or_empty?(node) || not_present?(node)
148
- range = node.loc.expression
148
+ range = node.source_range
149
149
  end
150
150
 
151
151
  corrector.replace(range, replacement(variable1))
@@ -153,9 +153,9 @@ module RuboCop
153
153
 
154
154
  def unless_condition(node, method_call)
155
155
  if node.modifier_form?
156
- node.loc.keyword.join(node.loc.expression.end)
156
+ node.loc.keyword.join(node.source_range.end)
157
157
  else
158
- node.loc.expression.begin.join(method_call.loc.expression)
158
+ node.source_range.begin.join(method_call.source_range)
159
159
  end
160
160
  end
161
161
 
@@ -94,9 +94,9 @@ module RuboCop
94
94
 
95
95
  def offense_range(node)
96
96
  end_pos = if node.parent&.block_type? && node.parent&.send_node == node
97
- node.parent.loc.expression.end_pos
97
+ node.parent.source_range.end_pos
98
98
  else
99
- node.loc.expression.end_pos
99
+ node.source_range.end_pos
100
100
  end
101
101
 
102
102
  range_between(node.loc.selector.begin_pos, end_pos)
@@ -85,7 +85,7 @@ module RuboCop
85
85
  end
86
86
 
87
87
  def correction_range(node)
88
- range_between(node.loc.selector.begin_pos, node.loc.expression.end_pos)
88
+ range_between(node.loc.selector.begin_pos, node.source_range.end_pos)
89
89
  end
90
90
  end
91
91
  end
@@ -3,10 +3,12 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Rails
6
- # Checks the migration for which timestamps are not included
7
- # when creating a new table.
6
+ # Checks the migration for which timestamps are not included when creating a new table.
8
7
  # In many cases, timestamps are useful information and should be added.
9
8
  #
9
+ # NOTE: Allow `timestamps` not written when `id: false` because this emphasizes respecting
10
+ # user's editing intentions.
11
+ #
10
12
  # @example
11
13
  # # bad
12
14
  # create_table :users
@@ -40,12 +42,23 @@ module RuboCop
40
42
  #
41
43
  # t.datetime :updated_at, default: -> { 'CURRENT_TIMESTAMP' }
42
44
  # end
45
+ #
46
+ # # good
47
+ # create_table :users, articles, id: false do |t|
48
+ # t.integer :user_id
49
+ # t.integer :article_id
50
+ # end
51
+ #
43
52
  class CreateTableWithTimestamps < Base
44
53
  include ActiveRecordMigrationsHelper
45
54
 
46
55
  MSG = 'Add timestamps when creating a new table.'
47
56
  RESTRICT_ON_SEND = %i[create_table].freeze
48
57
 
58
+ def_node_search :use_id_false_option?, <<~PATTERN
59
+ (pair (sym :id) (false))
60
+ PATTERN
61
+
49
62
  def_node_matcher :create_table_with_timestamps_proc?, <<~PATTERN
50
63
  (send nil? :create_table (sym _) ... (block-pass (sym :timestamps)))
51
64
  PATTERN
@@ -61,7 +74,7 @@ module RuboCop
61
74
  PATTERN
62
75
 
63
76
  def on_send(node)
64
- return unless node.command?(:create_table)
77
+ return if !node.command?(:create_table) || use_id_false_option?(node)
65
78
 
66
79
  parent = node.parent
67
80
 
@@ -24,6 +24,14 @@ module RuboCop
24
24
  # # good
25
25
  # delegate :bar, to: :foo
26
26
  #
27
+ # # bad
28
+ # def bar
29
+ # self.bar
30
+ # end
31
+ #
32
+ # # good
33
+ # delegate :bar, to: :self
34
+ #
27
35
  # # good
28
36
  # def bar
29
37
  # foo&.bar
@@ -60,7 +68,7 @@ module RuboCop
60
68
 
61
69
  def_node_matcher :delegate?, <<~PATTERN
62
70
  (def _method_name _args
63
- (send (send nil? _) _ ...))
71
+ (send {(send nil? _) (self)} _ ...))
64
72
  PATTERN
65
73
 
66
74
  def on_def(node)
@@ -74,10 +82,14 @@ module RuboCop
74
82
 
75
83
  def register_offense(node)
76
84
  add_offense(node.loc.keyword) do |corrector|
77
- delegation = ["delegate :#{node.body.method_name}", "to: :#{node.body.receiver.method_name}"]
85
+ body = node.body
86
+
87
+ receiver = body.receiver.self_type? ? 'self' : ":#{body.receiver.method_name}"
88
+
89
+ delegation = ["delegate :#{body.method_name}", "to: #{receiver}"]
78
90
  delegation << ['prefix: true'] if node.method?(prefixed_method_name(node.body))
79
91
 
80
- corrector.replace(node.source_range, delegation.join(', '))
92
+ corrector.replace(node, delegation.join(', '))
81
93
  end
82
94
  end
83
95
 
@@ -106,6 +118,8 @@ module RuboCop
106
118
  end
107
119
 
108
120
  def prefixed_method_name(body)
121
+ return '' if body.receiver.self_type?
122
+
109
123
  [body.receiver.method_name, body.method_name].join('_').to_sym
110
124
  end
111
125
 
@@ -27,7 +27,7 @@ module RuboCop
27
27
  return unless (offending_node = allow_blank_option(node))
28
28
 
29
29
  add_offense(offending_node) do |corrector|
30
- corrector.replace(offending_node.key.source_range, 'allow_nil')
30
+ corrector.replace(offending_node.key, 'allow_nil')
31
31
  end
32
32
  end
33
33
  end
@@ -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
@@ -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
@@ -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
 
@@ -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) ||
@@ -43,7 +43,7 @@ module RuboCop
43
43
 
44
44
  def on_block(node)
45
45
  pluck_candidate?(node) do |argument, key|
46
- next unless use_one_block_argument?(argument)
46
+ next if key.regexp_type? || !use_one_block_argument?(argument)
47
47
 
48
48
  match = if node.block_type?
49
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
 
@@ -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)
@@ -6,9 +6,9 @@ module RuboCop
6
6
  # Prefer `response.parsed_body` to `JSON.parse(response.body)`.
7
7
  #
8
8
  # @safety
9
- # This cop's autocorrection is unsafe because Content-Type may not be `application/json`. For example, the
10
- # proprietary Content-Type provided by corporate entities such as `application/vnd.github+json` is not
11
- # supported at `response.parsed_body` by default, so you still have to use `JSON.parse(response.body)` there.
9
+ # This cop is unsafe because Content-Type may not be `application/json`. For example, the proprietary
10
+ # Content-Type provided by corporate entities such as `application/vnd.github+json` is not supported at
11
+ # `response.parsed_body` by default, so you still have to use `JSON.parse(response.body)` there.
12
12
  #
13
13
  # @example
14
14
  # # bad
@@ -39,7 +39,7 @@ module RuboCop
39
39
  def on_send(node)
40
40
  evidence(node) do |rails_node, args|
41
41
  add_offense(node, message: format(MSG, root: rails_node.source)) do |corrector|
42
- range = range_between(rails_node.loc.selector.end_pos, node.loc.expression.end_pos)
42
+ range = range_between(rails_node.loc.selector.end_pos, node.source_range.end_pos)
43
43
  replacement = ".join(#{args.map(&:source).join(', ')})"
44
44
 
45
45
  corrector.replace(range, replacement)
@@ -184,7 +184,7 @@ module RuboCop
184
184
  end
185
185
 
186
186
  def build_path_glob_replacement(path, method)
187
- receiver = range_between(path.loc.expression.begin_pos, path.children.first.loc.selector.end_pos).source
187
+ receiver = range_between(path.source_range.begin_pos, path.children.first.loc.selector.end_pos).source
188
188
 
189
189
  argument = path.arguments.one? ? path.first_argument.source : join_arguments(path.arguments)
190
190
 
@@ -73,7 +73,7 @@ module RuboCop
73
73
  method = method_node.source[1..]
74
74
 
75
75
  range = if node.receiver
76
- range_between(node.loc.dot.begin_pos, node.loc.expression.end_pos)
76
+ range_between(node.loc.dot.begin_pos, node.source_range.end_pos)
77
77
  else
78
78
  corrector.insert_before(node, 'self')
79
79
  node
@@ -0,0 +1,71 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Rails
6
+ # Enforces that boolean columns are created with default values (`false` or `true`) and
7
+ # `NOT NULL` constraint.
8
+ #
9
+ # @example
10
+ # # bad
11
+ # add_column :users, :active, :boolean
12
+ # t.column :active, :boolean
13
+ # t.boolean :active
14
+ #
15
+ # # good
16
+ # add_column :users, :active, :boolean, default: true, null: false
17
+ # t.column :active, :boolean, default: true, null: false
18
+ # t.boolean :active, default: true, null: false
19
+ #
20
+ class ThreeStateBooleanColumn < Base
21
+ MSG = 'Boolean columns should always have a default value and a `NOT NULL` constraint.'
22
+
23
+ RESTRICT_ON_SEND = %i[add_column column boolean].freeze
24
+
25
+ def_node_matcher :three_state_boolean?, <<~PATTERN
26
+ {
27
+ (send nil? :add_column _ $_ {(sym :boolean) (str "boolean")} $_ ?)
28
+ (send !nil? :column $_ {(sym :boolean) (str "boolean")} $_ ?)
29
+ (send !nil? :boolean $_ $_ ?)
30
+ }
31
+ PATTERN
32
+
33
+ def_node_matcher :required_options?, <<~PATTERN
34
+ (hash <(pair (sym :default) !nil?) (pair (sym :null) false) ...>)
35
+ PATTERN
36
+
37
+ def_node_search :change_column_null?, <<~PATTERN
38
+ (send nil? :change_column_null {(sym %1) (str %1)} {(sym %2) (str %2)} false)
39
+ PATTERN
40
+
41
+ def on_send(node)
42
+ three_state_boolean?(node) do |column_node, options_node|
43
+ options_node = options_node.first
44
+
45
+ return if required_options?(options_node)
46
+
47
+ def_node = node.each_ancestor(:def, :defs).first
48
+ table_node = table_node(node)
49
+ return if def_node && change_column_null?(def_node, table_node.value, column_node.value)
50
+
51
+ add_offense(node)
52
+ end
53
+ end
54
+
55
+ private
56
+
57
+ def table_node(node)
58
+ case node.method_name
59
+ when :add_column
60
+ node.first_argument
61
+ when :column, :boolean
62
+ ancestor = node.each_ancestor(:block).find do |n|
63
+ n.method?(:create_table) || n.method?(:change_table)
64
+ end
65
+ ancestor&.send_node&.first_argument
66
+ end
67
+ end
68
+ end
69
+ end
70
+ end
71
+ end
@@ -70,7 +70,7 @@ module RuboCop
70
70
 
71
71
  def autocorrect(corrector, node)
72
72
  # add `.zone`: `Time.at` => `Time.zone.at`
73
- corrector.insert_after(node.children[0].source_range, '.zone')
73
+ corrector.insert_after(node.children[0], '.zone')
74
74
 
75
75
  case node.method_name
76
76
  when :current
@@ -81,7 +81,7 @@ module RuboCop
81
81
  end
82
82
 
83
83
  # prefer `Time` over `DateTime` class
84
- corrector.replace(node.children.first.source_range, 'Time') if strict?
84
+ corrector.replace(node.children.first, 'Time') if strict?
85
85
  remove_redundant_in_time_zone(corrector, node)
86
86
  end
87
87
 
@@ -4,7 +4,7 @@ module RuboCop
4
4
  module Cop
5
5
  module Rails
6
6
  # When you define a uniqueness validation in Active Record model,
7
- # you also should add a unique index for the column. There are two reasons
7
+ # you also should add a unique index for the column. There are two reasons.
8
8
  # First, duplicated records may occur even if Active Record's validation
9
9
  # is defined.
10
10
  # Second, it will cause slow queries. The validation executes a `SELECT`
@@ -102,7 +102,7 @@ module RuboCop
102
102
  end
103
103
 
104
104
  def correct_validate_type_for_hash(corrector, node, arguments)
105
- corrector.replace(arguments.loc.expression, "#{validate_type(node)}: #{braced_options(arguments)}")
105
+ corrector.replace(arguments, "#{validate_type(node)}: #{braced_options(arguments)}")
106
106
  end
107
107
 
108
108
  def correct_validate_type_for_array(corrector, node, arguments, loc)
@@ -65,7 +65,7 @@ module RuboCop
65
65
  private
66
66
 
67
67
  def offense_range(node)
68
- range_between(node.loc.selector.begin_pos, node.loc.expression.end_pos)
68
+ range_between(node.loc.selector.begin_pos, node.source_range.end_pos)
69
69
  end
70
70
 
71
71
  def extract_column_and_value(template_node, value_node)
@@ -105,7 +105,7 @@ module RuboCop
105
105
  if exists_style?
106
106
  node.receiver.loc.selector.join(node.loc.selector)
107
107
  elsif where_style?
108
- node.loc.selector.with(end_pos: node.loc.expression.end_pos)
108
+ node.loc.selector.with(end_pos: node.source_range.end_pos)
109
109
  end
110
110
  end
111
111
 
@@ -43,7 +43,7 @@ module RuboCop
43
43
  next unless root_receiver == root_receiver(where_node)
44
44
  next unless same_relationship?(where_argument, node.first_argument)
45
45
 
46
- range = range_between(node.loc.selector.begin_pos, node.loc.expression.end_pos)
46
+ range = range_between(node.loc.selector.begin_pos, node.source_range.end_pos)
47
47
  register_offense(node, where_node, where_argument, range)
48
48
  break
49
49
  end
@@ -83,9 +83,9 @@ module RuboCop
83
83
 
84
84
  def replace_range(child)
85
85
  if (right_sibling = child.right_sibling)
86
- range_between(child.loc.expression.begin_pos, right_sibling.loc.expression.begin_pos)
86
+ range_between(child.source_range.begin_pos, right_sibling.source_range.begin_pos)
87
87
  else
88
- range_between(child.left_sibling.loc.expression.end_pos, child.loc.expression.end_pos)
88
+ range_between(child.left_sibling.source_range.end_pos, child.source_range.end_pos)
89
89
  end
90
90
  end
91
91
 
@@ -64,7 +64,7 @@ module RuboCop
64
64
  private
65
65
 
66
66
  def offense_range(node)
67
- range_between(node.loc.selector.begin_pos, node.loc.expression.end_pos)
67
+ range_between(node.loc.selector.begin_pos, node.source_range.end_pos)
68
68
  end
69
69
 
70
70
  def extract_column_and_value(template_node, value_node)
@@ -32,10 +32,10 @@ module RuboCop
32
32
 
33
33
  def on_send(node)
34
34
  where_not_call?(node) do |args|
35
- next unless args[0].hash_type?
35
+ next unless args[0]&.hash_type?
36
36
  next unless multiple_arguments_hash? args[0]
37
37
 
38
- range = node.receiver.loc.selector.with(end_pos: node.loc.expression.end_pos)
38
+ range = node.receiver.loc.selector.with(end_pos: node.source_range.end_pos)
39
39
 
40
40
  add_offense(range)
41
41
  end
@@ -115,6 +115,7 @@ require_relative 'rails/skips_model_validations'
115
115
  require_relative 'rails/squished_sql_heredocs'
116
116
  require_relative 'rails/strip_heredoc'
117
117
  require_relative 'rails/table_name_assignment'
118
+ require_relative 'rails/three_state_boolean_column'
118
119
  require_relative 'rails/time_zone'
119
120
  require_relative 'rails/time_zone_assignment'
120
121
  require_relative 'rails/to_formatted_s'
@@ -4,7 +4,7 @@ module RuboCop
4
4
  module Rails
5
5
  # This module holds the RuboCop Rails version information.
6
6
  module Version
7
- STRING = '2.18.0'
7
+ STRING = '2.19.0'
8
8
 
9
9
  def self.document_version
10
10
  STRING.match('\d+\.\d+').to_s
data/lib/rubocop-rails.rb CHANGED
@@ -3,6 +3,7 @@
3
3
  require 'rubocop'
4
4
  require 'rack/utils'
5
5
  require 'active_support/inflector'
6
+ require 'active_support/core_ext/object/blank'
6
7
 
7
8
  require_relative 'rubocop/rails'
8
9
  require_relative 'rubocop/rails/version'
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rubocop-rails
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.18.0
4
+ version: 2.19.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Bozhidar Batsov
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2023-02-25 00:00:00.000000000 Z
13
+ date: 2023-04-07 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: activesupport
@@ -189,6 +189,7 @@ files:
189
189
  - lib/rubocop/cop/rails/squished_sql_heredocs.rb
190
190
  - lib/rubocop/cop/rails/strip_heredoc.rb
191
191
  - lib/rubocop/cop/rails/table_name_assignment.rb
192
+ - lib/rubocop/cop/rails/three_state_boolean_column.rb
192
193
  - lib/rubocop/cop/rails/time_zone.rb
193
194
  - lib/rubocop/cop/rails/time_zone_assignment.rb
194
195
  - lib/rubocop/cop/rails/to_formatted_s.rb
@@ -218,7 +219,7 @@ metadata:
218
219
  homepage_uri: https://docs.rubocop.org/rubocop-rails/
219
220
  changelog_uri: https://github.com/rubocop/rubocop-rails/blob/master/CHANGELOG.md
220
221
  source_code_uri: https://github.com/rubocop/rubocop-rails/
221
- documentation_uri: https://docs.rubocop.org/rubocop-rails/2.18/
222
+ documentation_uri: https://docs.rubocop.org/rubocop-rails/2.19/
222
223
  bug_tracker_uri: https://github.com/rubocop/rubocop-rails/issues
223
224
  rubygems_mfa_required: 'true'
224
225
  post_install_message:
@@ -236,7 +237,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
236
237
  - !ruby/object:Gem::Version
237
238
  version: '0'
238
239
  requirements: []
239
- rubygems_version: 3.4.1
240
+ rubygems_version: 3.5.0.dev
240
241
  signing_key:
241
242
  specification_version: 4
242
243
  summary: Automatic Rails code style checking tool.