rubocop-rails 2.8.0 → 2.10.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 (102) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE.txt +1 -1
  3. data/README.md +18 -2
  4. data/config/default.yml +101 -5
  5. data/config/obsoletion.yml +7 -0
  6. data/lib/rubocop/cop/mixin/active_record_helper.rb +16 -3
  7. data/lib/rubocop/cop/mixin/enforce_superclass.rb +40 -0
  8. data/lib/rubocop/cop/mixin/index_method.rb +8 -11
  9. data/lib/rubocop/cop/rails/action_filter.rb +10 -14
  10. data/lib/rubocop/cop/rails/active_record_aliases.rb +13 -17
  11. data/lib/rubocop/cop/rails/active_record_callbacks_order.rb +17 -12
  12. data/lib/rubocop/cop/rails/active_record_override.rb +1 -1
  13. data/lib/rubocop/cop/rails/active_support_aliases.rb +12 -21
  14. data/lib/rubocop/cop/rails/after_commit_override.rb +9 -2
  15. data/lib/rubocop/cop/rails/application_controller.rb +3 -7
  16. data/lib/rubocop/cop/rails/application_job.rb +2 -1
  17. data/lib/rubocop/cop/rails/application_mailer.rb +2 -7
  18. data/lib/rubocop/cop/rails/application_record.rb +2 -7
  19. data/lib/rubocop/cop/rails/arel_star.rb +41 -0
  20. data/lib/rubocop/cop/rails/assert_not.rb +8 -10
  21. data/lib/rubocop/cop/rails/attribute_default_block_value.rb +90 -0
  22. data/lib/rubocop/cop/rails/belongs_to.rb +10 -19
  23. data/lib/rubocop/cop/rails/blank.rb +31 -27
  24. data/lib/rubocop/cop/rails/bulk_change_table.rb +1 -1
  25. data/lib/rubocop/cop/rails/content_tag.rb +33 -18
  26. data/lib/rubocop/cop/rails/create_table_with_timestamps.rb +2 -1
  27. data/lib/rubocop/cop/rails/date.rb +10 -11
  28. data/lib/rubocop/cop/rails/default_scope.rb +11 -4
  29. data/lib/rubocop/cop/rails/delegate.rb +9 -9
  30. data/lib/rubocop/cop/rails/delegate_allow_blank.rb +7 -8
  31. data/lib/rubocop/cop/rails/dynamic_find_by.rb +15 -12
  32. data/lib/rubocop/cop/rails/enum_hash.rb +11 -10
  33. data/lib/rubocop/cop/rails/enum_uniqueness.rb +2 -1
  34. data/lib/rubocop/cop/rails/environment_comparison.rb +18 -14
  35. data/lib/rubocop/cop/rails/environment_variable_access.rb +67 -0
  36. data/lib/rubocop/cop/rails/exit.rb +4 -10
  37. data/lib/rubocop/cop/rails/file_path.rb +6 -7
  38. data/lib/rubocop/cop/rails/find_by.rb +13 -13
  39. data/lib/rubocop/cop/rails/find_by_id.rb +12 -21
  40. data/lib/rubocop/cop/rails/find_each.rb +19 -18
  41. data/lib/rubocop/cop/rails/has_and_belongs_to_many.rb +3 -2
  42. data/lib/rubocop/cop/rails/has_many_or_has_one_dependent.rb +37 -6
  43. data/lib/rubocop/cop/rails/helper_instance_variable.rb +29 -3
  44. data/lib/rubocop/cop/rails/http_positional_arguments.rb +32 -21
  45. data/lib/rubocop/cop/rails/http_status.rb +7 -9
  46. data/lib/rubocop/cop/rails/ignored_skip_action_filter_option.rb +8 -6
  47. data/lib/rubocop/cop/rails/index_by.rb +3 -2
  48. data/lib/rubocop/cop/rails/index_with.rb +3 -2
  49. data/lib/rubocop/cop/rails/inquiry.rb +4 -3
  50. data/lib/rubocop/cop/rails/inverse_of.rb +3 -2
  51. data/lib/rubocop/cop/rails/lexically_scoped_action_filter.rb +17 -15
  52. data/lib/rubocop/cop/rails/link_to_blank.rb +25 -23
  53. data/lib/rubocop/cop/rails/mailer_name.rb +19 -13
  54. data/lib/rubocop/cop/rails/match_route.rb +14 -13
  55. data/lib/rubocop/cop/rails/negate_include.rb +10 -8
  56. data/lib/rubocop/cop/rails/not_null_column.rb +2 -1
  57. data/lib/rubocop/cop/rails/order_by_id.rb +1 -2
  58. data/lib/rubocop/cop/rails/output.rb +5 -2
  59. data/lib/rubocop/cop/rails/output_safety.rb +3 -2
  60. data/lib/rubocop/cop/rails/pick.rb +14 -12
  61. data/lib/rubocop/cop/rails/pluck.rb +6 -9
  62. data/lib/rubocop/cop/rails/pluck_id.rb +4 -6
  63. data/lib/rubocop/cop/rails/pluck_in_where.rb +7 -7
  64. data/lib/rubocop/cop/rails/pluralization_grammar.rb +10 -14
  65. data/lib/rubocop/cop/rails/presence.rb +12 -13
  66. data/lib/rubocop/cop/rails/present.rb +30 -24
  67. data/lib/rubocop/cop/rails/rake_environment.rb +8 -10
  68. data/lib/rubocop/cop/rails/read_write_attribute.rb +12 -11
  69. data/lib/rubocop/cop/rails/redundant_allow_nil.rb +29 -31
  70. data/lib/rubocop/cop/rails/redundant_foreign_key.rb +9 -12
  71. data/lib/rubocop/cop/rails/redundant_receiver_in_with_options.rb +11 -10
  72. data/lib/rubocop/cop/rails/reflection_class_name.rb +17 -3
  73. data/lib/rubocop/cop/rails/refute_methods.rb +9 -10
  74. data/lib/rubocop/cop/rails/relative_date_constant.rb +30 -21
  75. data/lib/rubocop/cop/rails/render_inline.rb +2 -1
  76. data/lib/rubocop/cop/rails/render_plain_text.rb +9 -14
  77. data/lib/rubocop/cop/rails/request_referer.rb +7 -7
  78. data/lib/rubocop/cop/rails/require_dependency.rb +38 -0
  79. data/lib/rubocop/cop/rails/reversible_migration.rb +4 -8
  80. data/lib/rubocop/cop/rails/reversible_migration_method_definition.rb +75 -0
  81. data/lib/rubocop/cop/rails/safe_navigation.rb +30 -11
  82. data/lib/rubocop/cop/rails/safe_navigation_with_blank.rb +5 -10
  83. data/lib/rubocop/cop/rails/save_bang.rb +17 -20
  84. data/lib/rubocop/cop/rails/scope_args.rb +2 -1
  85. data/lib/rubocop/cop/rails/short_i18n.rb +7 -9
  86. data/lib/rubocop/cop/rails/skips_model_validations.rb +4 -4
  87. data/lib/rubocop/cop/rails/squished_sql_heredocs.rb +5 -6
  88. data/lib/rubocop/cop/rails/time_zone.rb +35 -25
  89. data/lib/rubocop/cop/rails/time_zone_assignment.rb +37 -0
  90. data/lib/rubocop/cop/rails/uniq_before_pluck.rb +4 -6
  91. data/lib/rubocop/cop/rails/unique_validation_without_index.rb +4 -2
  92. data/lib/rubocop/cop/rails/unknown_env.rb +3 -3
  93. data/lib/rubocop/cop/rails/validation.rb +15 -14
  94. data/lib/rubocop/cop/rails/where_equals.rb +98 -0
  95. data/lib/rubocop/cop/rails/where_exists.rb +19 -13
  96. data/lib/rubocop/cop/rails/where_not.rb +14 -19
  97. data/lib/rubocop/cop/rails_cops.rb +8 -0
  98. data/lib/rubocop/rails.rb +2 -0
  99. data/lib/rubocop/rails/schema_loader.rb +4 -4
  100. data/lib/rubocop/rails/schema_loader/schema.rb +2 -4
  101. data/lib/rubocop/rails/version.rb +5 -1
  102. metadata +29 -14
@@ -12,7 +12,9 @@ module RuboCop
12
12
  #
13
13
  # #good
14
14
  # Book.update!(author: 'Alice')
15
- class ActiveRecordAliases < Cop
15
+ class ActiveRecordAliases < Base
16
+ extend AutoCorrector
17
+
16
18
  MSG = 'Use `%<prefer>s` instead of `%<current>s`.'
17
19
 
18
20
  ALIASES = {
@@ -20,28 +22,22 @@ module RuboCop
20
22
  update_attributes!: :update!
21
23
  }.freeze
22
24
 
25
+ RESTRICT_ON_SEND = ALIASES.keys.freeze
26
+
23
27
  def on_send(node)
24
- ALIASES.each do |bad, good|
25
- next unless node.method?(bad)
28
+ method_name = node.method_name
29
+ alias_method = ALIASES[method_name]
26
30
 
27
- add_offense(node,
28
- message: format(MSG, prefer: good, current: bad),
29
- location: :selector,
30
- severity: :warning)
31
- break
31
+ add_offense(
32
+ node.loc.selector,
33
+ message: format(MSG, prefer: alias_method, current: method_name),
34
+ severity: :warning
35
+ ) do |corrector|
36
+ corrector.replace(node.loc.selector, alias_method)
32
37
  end
33
38
  end
34
39
 
35
40
  alias on_csend on_send
36
-
37
- def autocorrect(node)
38
- lambda do |corrector|
39
- corrector.replace(
40
- node.loc.selector,
41
- ALIASES[node.method_name].to_s
42
- )
43
- end
44
- end
45
41
  end
46
42
  end
47
43
  end
@@ -19,7 +19,9 @@ module RuboCop
19
19
  # after_commit :after_commit_callback
20
20
  # end
21
21
  #
22
- class ActiveRecordCallbacksOrder < Cop
22
+ class ActiveRecordCallbacksOrder < Base
23
+ extend AutoCorrector
24
+
23
25
  MSG = '`%<current>s` is supposed to appear before `%<previous>s`.'
24
26
 
25
27
  CALLBACKS_IN_ORDER = %i[
@@ -55,17 +57,20 @@ module RuboCop
55
57
  index = CALLBACKS_ORDER_MAP[callback]
56
58
 
57
59
  if index < previous_index
58
- message = format(MSG, current: callback,
59
- previous: previous_callback)
60
- add_offense(node, message: message)
60
+ message = format(MSG, current: callback, previous: previous_callback)
61
+ add_offense(node, message: message) do |corrector|
62
+ autocorrect(corrector, node)
63
+ end
61
64
  end
62
65
  previous_index = index
63
66
  previous_callback = callback
64
67
  end
65
68
  end
66
69
 
70
+ private
71
+
67
72
  # Autocorrect by swapping between two nodes autocorrecting them
68
- def autocorrect(node)
73
+ def autocorrect(corrector, node)
69
74
  previous = left_siblings_of(node).reverse_each.find do |sibling|
70
75
  callback?(sibling)
71
76
  end
@@ -73,14 +78,10 @@ module RuboCop
73
78
  current_range = source_range_with_comment(node)
74
79
  previous_range = source_range_with_comment(previous)
75
80
 
76
- lambda do |corrector|
77
- corrector.insert_before(previous_range, current_range.source)
78
- corrector.remove(current_range)
79
- end
81
+ corrector.insert_before(previous_range, current_range.source)
82
+ corrector.remove(current_range)
80
83
  end
81
84
 
82
- private
83
-
84
85
  def defined_callbacks(class_node)
85
86
  class_def = class_node.body
86
87
 
@@ -121,7 +122,7 @@ module RuboCop
121
122
 
122
123
  processed_source.comments_before_line(annotation_line)
123
124
  .reverse_each do |comment|
124
- if comment.location.line == annotation_line
125
+ if comment.location.line == annotation_line && !inline_comment?(comment)
125
126
  first_comment = comment
126
127
  annotation_line -= 1
127
128
  end
@@ -130,6 +131,10 @@ module RuboCop
130
131
  start_line_position(first_comment || node)
131
132
  end
132
133
 
134
+ def inline_comment?(comment)
135
+ !comment_line?(comment.loc.expression.source_line)
136
+ end
137
+
133
138
  def start_line_position(node)
134
139
  buffer.line_range(node.loc.line).begin_pos - 1
135
140
  end
@@ -24,7 +24,7 @@ module RuboCop
24
24
  # end
25
25
  # end
26
26
  #
27
- class ActiveRecordOverride < Cop
27
+ class ActiveRecordOverride < Base
28
28
  MSG =
29
29
  'Use %<prefer>s callbacks instead of overriding the Active Record ' \
30
30
  'method `%<bad>s`.'
@@ -19,8 +19,11 @@ module RuboCop
19
19
  # [1, 2, 'a'].append('b')
20
20
  # [1, 2, 'a'].prepend('b')
21
21
  #
22
- class ActiveSupportAliases < Cop
22
+ class ActiveSupportAliases < Base
23
+ extend AutoCorrector
24
+
23
25
  MSG = 'Use `%<prefer>s` instead of `%<current>s`.'
26
+ RESTRICT_ON_SEND = %i[starts_with? ends_with? append prepend].freeze
24
27
 
25
28
  ALIASES = {
26
29
  starts_with?: {
@@ -39,29 +42,17 @@ module RuboCop
39
42
 
40
43
  def on_send(node)
41
44
  ALIASES.each_key do |aliased_method|
42
- register_offense(node, aliased_method) if
43
- public_send(aliased_method, node)
44
- end
45
- end
45
+ next unless public_send(aliased_method, node)
46
46
 
47
- def autocorrect(node)
48
- return false if append(node)
47
+ preferred_method = ALIASES[aliased_method][:original]
48
+ message = format(MSG, prefer: preferred_method, current: aliased_method)
49
49
 
50
- lambda do |corrector|
51
- method_name = node.loc.selector.source
52
- replacement = ALIASES[method_name.to_sym][:original]
53
- corrector.replace(node.loc.selector, replacement.to_s)
54
- end
55
- end
56
-
57
- private
50
+ add_offense(node, message: message) do |corrector|
51
+ next if append(node)
58
52
 
59
- def register_offense(node, method_name)
60
- add_offense(
61
- node,
62
- message: format(MSG, prefer: ALIASES[method_name][:original],
63
- current: method_name)
64
- )
53
+ corrector.replace(node.loc.selector, preferred_method)
54
+ end
55
+ end
65
56
  end
66
57
  end
67
58
  end
@@ -31,7 +31,7 @@ module RuboCop
31
31
  # after_create_commit :log_create_action
32
32
  # after_update_commit :log_update_action
33
33
  #
34
- class AfterCommitOverride < Cop
34
+ class AfterCommitOverride < Base
35
35
  MSG = 'There can only be one `after_*_commit :%<name>s` hook defined for a model.'
36
36
 
37
37
  AFTER_COMMIT_CALLBACKS = %i[
@@ -59,7 +59,7 @@ module RuboCop
59
59
 
60
60
  def each_after_commit_callback(class_node)
61
61
  class_send_nodes(class_node).each do |node|
62
- yield node if after_commit_callback?(node)
62
+ yield node if after_commit_callback?(node) && named_callback?(node)
63
63
  end
64
64
  end
65
65
 
@@ -78,6 +78,13 @@ module RuboCop
78
78
  def after_commit_callback?(node)
79
79
  AFTER_COMMIT_CALLBACKS.include?(node.method_name)
80
80
  end
81
+
82
+ def named_callback?(node)
83
+ name = node.first_argument
84
+ return false unless name
85
+
86
+ name.sym_type?
87
+ end
81
88
  end
82
89
  end
83
90
  end
@@ -16,7 +16,9 @@ module RuboCop
16
16
  # class MyController < ActionController::Base
17
17
  # # ...
18
18
  # end
19
- class ApplicationController < Cop
19
+ class ApplicationController < Base
20
+ extend AutoCorrector
21
+
20
22
  MSG = 'Controllers should subclass `ApplicationController`.'
21
23
  SUPERCLASS = 'ApplicationController'
22
24
  BASE_PATTERN = '(const (const nil? :ActionController) :Base)'
@@ -24,12 +26,6 @@ module RuboCop
24
26
  # rubocop:disable Layout/ClassStructure
25
27
  include RuboCop::Cop::EnforceSuperclass
26
28
  # rubocop:enable Layout/ClassStructure
27
-
28
- def autocorrect(node)
29
- lambda do |corrector|
30
- corrector.replace(node.source_range, self.class::SUPERCLASS)
31
- end
32
- end
33
29
  end
34
30
  end
35
31
  end
@@ -16,7 +16,8 @@ module RuboCop
16
16
  # class Rails4Job < ActiveJob::Base
17
17
  # # ...
18
18
  # end
19
- class ApplicationJob < Cop
19
+ class ApplicationJob < Base
20
+ extend AutoCorrector
20
21
  extend TargetRailsVersion
21
22
 
22
23
  minimum_target_rails_version 5.0
@@ -16,7 +16,8 @@ module RuboCop
16
16
  # class MyMailer < ActionMailer::Base
17
17
  # # ...
18
18
  # end
19
- class ApplicationMailer < Cop
19
+ class ApplicationMailer < Base
20
+ extend AutoCorrector
20
21
  extend TargetRailsVersion
21
22
 
22
23
  minimum_target_rails_version 5.0
@@ -28,12 +29,6 @@ module RuboCop
28
29
  # rubocop:disable Layout/ClassStructure
29
30
  include RuboCop::Cop::EnforceSuperclass
30
31
  # rubocop:enable Layout/ClassStructure
31
-
32
- def autocorrect(node)
33
- lambda do |corrector|
34
- corrector.replace(node.source_range, self.class::SUPERCLASS)
35
- end
36
- end
37
32
  end
38
33
  end
39
34
  end
@@ -16,7 +16,8 @@ module RuboCop
16
16
  # class Rails4Model < ActiveRecord::Base
17
17
  # # ...
18
18
  # end
19
- class ApplicationRecord < Cop
19
+ class ApplicationRecord < Base
20
+ extend AutoCorrector
20
21
  extend TargetRailsVersion
21
22
 
22
23
  minimum_target_rails_version 5.0
@@ -28,12 +29,6 @@ module RuboCop
28
29
  # rubocop:disable Layout/ClassStructure
29
30
  include RuboCop::Cop::EnforceSuperclass
30
31
  # rubocop:enable Layout/ClassStructure
31
-
32
- def autocorrect(node)
33
- lambda do |corrector|
34
- corrector.replace(node.source_range, self.class::SUPERCLASS)
35
- end
36
- end
37
32
  end
38
33
  end
39
34
  end
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Rails
6
+ # This cop prevents usage of `"*"` on an Arel::Table column reference.
7
+ #
8
+ # Using `arel_table["*"]` causes the outputted string to be a literal
9
+ # quoted asterisk (e.g. <tt>`my_model`.`*`</tt>). This causes the
10
+ # database to look for a column named <tt>`*`</tt> (or `"*"`) as opposed
11
+ # to expanding the column list as one would likely expect.
12
+ #
13
+ # @example
14
+ # # bad
15
+ # MyTable.arel_table["*"]
16
+ #
17
+ # # good
18
+ # MyTable.arel_table[Arel.star]
19
+ #
20
+ class ArelStar < Base
21
+ extend AutoCorrector
22
+
23
+ MSG = 'Use `Arel.star` instead of `"*"` for expanded column lists.'
24
+
25
+ RESTRICT_ON_SEND = %i[[]].freeze
26
+
27
+ def_node_matcher :star_bracket?, <<~PATTERN
28
+ (send {const (send _ :arel_table)} :[] $(str "*"))
29
+ PATTERN
30
+
31
+ def on_send(node)
32
+ return unless (star = star_bracket?(node))
33
+
34
+ add_offense(star) do |corrector|
35
+ corrector.replace(star.loc.expression, 'Arel.star')
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
@@ -13,23 +13,21 @@ module RuboCop
13
13
  # # good
14
14
  # assert_not x
15
15
  #
16
- class AssertNot < RuboCop::Cop::Cop
16
+ class AssertNot < Base
17
+ extend AutoCorrector
18
+
17
19
  MSG = 'Prefer `assert_not` over `assert !`.'
20
+ RESTRICT_ON_SEND = %i[assert].freeze
18
21
 
19
22
  def_node_matcher :offensive?, '(send nil? :assert (send ... :!) ...)'
20
23
 
21
24
  def on_send(node)
22
- add_offense(node) if offensive?(node)
23
- end
25
+ return unless offensive?(node)
24
26
 
25
- def autocorrect(node)
26
- expression = node.loc.expression
27
+ add_offense(node) do |corrector|
28
+ expression = node.loc.expression
27
29
 
28
- lambda do |corrector|
29
- corrector.replace(
30
- expression,
31
- corrected_source(expression.source)
32
- )
30
+ corrector.replace(expression, corrected_source(expression.source))
33
31
  end
34
32
  end
35
33
 
@@ -0,0 +1,90 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Rails
6
+ # This cop looks for `attribute` class methods that specify a `:default` option
7
+ # which value is an array, string literal or method call without a block.
8
+ # It will accept all other values, such as string, symbol, integer and float literals
9
+ # as well as constants.
10
+ #
11
+ # @example
12
+ # # bad
13
+ # class User < ApplicationRecord
14
+ # attribute :confirmed_at, :datetime, default: Time.zone.now
15
+ # end
16
+ #
17
+ # # good
18
+ # class User < ApplicationRecord
19
+ # attribute :confirmed_at, :datetime, default: -> { Time.zone.now }
20
+ # end
21
+ #
22
+ # # bad
23
+ # class User < ApplicationRecord
24
+ # attribute :roles, :string, array: true, default: []
25
+ # end
26
+ #
27
+ # # good
28
+ # class User < ApplicationRecord
29
+ # attribute :roles, :string, array: true, default: -> { [] }
30
+ # end
31
+ #
32
+ # # bad
33
+ # class User < ApplicationRecord
34
+ # attribute :configuration, default: {}
35
+ # end
36
+ #
37
+ # # good
38
+ # class User < ApplicationRecord
39
+ # attribute :configuration, default: -> { {} }
40
+ # end
41
+ #
42
+ # # good
43
+ # class User < ApplicationRecord
44
+ # attribute :role, :string, default: :customer
45
+ # end
46
+ #
47
+ # # good
48
+ # class User < ApplicationRecord
49
+ # attribute :activated, :boolean, default: false
50
+ # end
51
+ #
52
+ # # good
53
+ # class User < ApplicationRecord
54
+ # attribute :login_count, :integer, default: 0
55
+ # end
56
+ #
57
+ # # good
58
+ # class User < ApplicationRecord
59
+ # FOO = 123
60
+ # attribute :custom_attribute, :integer, default: FOO
61
+ # end
62
+ class AttributeDefaultBlockValue < Base
63
+ extend AutoCorrector
64
+
65
+ MSG = 'Pass method in a block to `:default` option.'
66
+ RESTRICT_ON_SEND = %i[attribute].freeze
67
+ TYPE_OFFENDERS = %i[send array hash].freeze
68
+
69
+ def_node_matcher :default_attribute, <<~PATTERN
70
+ (send nil? :attribute _ ?_ (hash <$#attribute ...>))
71
+ PATTERN
72
+
73
+ def_node_matcher :attribute, '(pair (sym :default) $_)'
74
+
75
+ def on_send(node)
76
+ default_attribute(node) do |attribute|
77
+ value = attribute.children.last
78
+ return unless TYPE_OFFENDERS.any?(value.type)
79
+
80
+ add_offense(value) do |corrector|
81
+ expression = default_attribute(node).children.last
82
+
83
+ corrector.replace(value, "-> { #{expression.source} }")
84
+ end
85
+ end
86
+ end
87
+ end
88
+ end
89
+ end
90
+ end