rubocop-rails 2.15.2 → 2.17.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 (74) hide show
  1. checksums.yaml +4 -4
  2. data/config/default.yml +120 -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 +99 -0
  8. data/lib/rubocop/cop/rails/action_controller_test_case.rb +1 -1
  9. data/lib/rubocop/cop/rails/action_filter.rb +1 -1
  10. data/lib/rubocop/cop/rails/action_order.rb +81 -0
  11. data/lib/rubocop/cop/rails/active_record_aliases.rb +1 -4
  12. data/lib/rubocop/cop/rails/active_record_override.rb +2 -5
  13. data/lib/rubocop/cop/rails/active_support_on_load.rb +70 -0
  14. data/lib/rubocop/cop/rails/add_column_index.rb +1 -4
  15. data/lib/rubocop/cop/rails/blank.rb +1 -2
  16. data/lib/rubocop/cop/rails/bulk_change_table.rb +6 -20
  17. data/lib/rubocop/cop/rails/compact_blank.rb +5 -1
  18. data/lib/rubocop/cop/rails/content_tag.rb +3 -4
  19. data/lib/rubocop/cop/rails/date.rb +4 -9
  20. data/lib/rubocop/cop/rails/delegate.rb +2 -5
  21. data/lib/rubocop/cop/rails/deprecated_active_model_errors_methods.rb +17 -13
  22. data/lib/rubocop/cop/rails/dot_separated_keys.rb +1 -1
  23. data/lib/rubocop/cop/rails/dynamic_find_by.rb +8 -6
  24. data/lib/rubocop/cop/rails/eager_evaluation_log_message.rb +4 -0
  25. data/lib/rubocop/cop/rails/enum_uniqueness.rb +2 -5
  26. data/lib/rubocop/cop/rails/environment_comparison.rb +1 -2
  27. data/lib/rubocop/cop/rails/file_path.rb +2 -4
  28. data/lib/rubocop/cop/rails/find_each.rb +8 -2
  29. data/lib/rubocop/cop/rails/freeze_time.rb +74 -0
  30. data/lib/rubocop/cop/rails/has_many_or_has_one_dependent.rb +1 -3
  31. data/lib/rubocop/cop/rails/http_positional_arguments.rb +4 -9
  32. data/lib/rubocop/cop/rails/http_status.rb +11 -11
  33. data/lib/rubocop/cop/rails/ignored_columns_assignment.rb +50 -0
  34. data/lib/rubocop/cop/rails/ignored_skip_action_filter_option.rb +3 -10
  35. data/lib/rubocop/cop/rails/inverse_of.rb +3 -6
  36. data/lib/rubocop/cop/rails/lexically_scoped_action_filter.rb +2 -6
  37. data/lib/rubocop/cop/rails/link_to_blank.rb +1 -4
  38. data/lib/rubocop/cop/rails/output.rb +2 -5
  39. data/lib/rubocop/cop/rails/pluck.rb +8 -7
  40. data/lib/rubocop/cop/rails/pluralization_grammar.rb +1 -2
  41. data/lib/rubocop/cop/rails/presence.rb +21 -12
  42. data/lib/rubocop/cop/rails/present.rb +3 -6
  43. data/lib/rubocop/cop/rails/rake_environment.rb +1 -1
  44. data/lib/rubocop/cop/rails/redundant_allow_nil.rb +2 -4
  45. data/lib/rubocop/cop/rails/redundant_foreign_key.rb +1 -1
  46. data/lib/rubocop/cop/rails/redundant_presence_validation_on_belongs_to.rb +3 -3
  47. data/lib/rubocop/cop/rails/redundant_receiver_in_with_options.rb +30 -26
  48. data/lib/rubocop/cop/rails/reflection_class_name.rb +17 -0
  49. data/lib/rubocop/cop/rails/refute_methods.rb +1 -5
  50. data/lib/rubocop/cop/rails/relative_date_constant.rb +2 -5
  51. data/lib/rubocop/cop/rails/request_referer.rb +1 -2
  52. data/lib/rubocop/cop/rails/reversible_migration.rb +10 -33
  53. data/lib/rubocop/cop/rails/reversible_migration_method_definition.rb +1 -2
  54. data/lib/rubocop/cop/rails/root_pathname_methods.rb +214 -0
  55. data/lib/rubocop/cop/rails/safe_navigation_with_blank.rb +1 -3
  56. data/lib/rubocop/cop/rails/save_bang.rb +10 -22
  57. data/lib/rubocop/cop/rails/short_i18n.rb +1 -4
  58. data/lib/rubocop/cop/rails/skips_model_validations.rb +1 -2
  59. data/lib/rubocop/cop/rails/squished_sql_heredocs.rb +1 -5
  60. data/lib/rubocop/cop/rails/time_zone.rb +10 -21
  61. data/lib/rubocop/cop/rails/to_s_with_argument.rb +41 -0
  62. data/lib/rubocop/cop/rails/top_level_hash_with_indifferent_access.rb +49 -0
  63. data/lib/rubocop/cop/rails/uniq_before_pluck.rb +3 -6
  64. data/lib/rubocop/cop/rails/unique_validation_without_index.rb +1 -3
  65. data/lib/rubocop/cop/rails/unknown_env.rb +2 -4
  66. data/lib/rubocop/cop/rails/validation.rb +4 -12
  67. data/lib/rubocop/cop/rails/where_missing.rb +111 -0
  68. data/lib/rubocop/cop/rails/where_not_with_multiple_conditions.rb +55 -0
  69. data/lib/rubocop/cop/rails_cops.rb +10 -0
  70. data/lib/rubocop/rails/version.rb +1 -1
  71. data/lib/rubocop-rails.rb +10 -0
  72. metadata +16 -8
  73. data/bin/console +0 -11
  74. data/bin/setup +0 -7
@@ -111,25 +111,13 @@ module RuboCop
111
111
  remove_timestamps
112
112
  ].freeze
113
113
 
114
- MYSQL_COMBINABLE_TRANSFORMATIONS = %i[
115
- rename
116
- index
117
- remove_index
118
- ].freeze
114
+ MYSQL_COMBINABLE_TRANSFORMATIONS = %i[rename index remove_index].freeze
119
115
 
120
- MYSQL_COMBINABLE_ALTER_METHODS = %i[
121
- rename_column
122
- add_index
123
- remove_index
124
- ].freeze
116
+ MYSQL_COMBINABLE_ALTER_METHODS = %i[rename_column add_index remove_index].freeze
125
117
 
126
- POSTGRESQL_COMBINABLE_TRANSFORMATIONS = %i[
127
- change_default
128
- ].freeze
118
+ POSTGRESQL_COMBINABLE_TRANSFORMATIONS = %i[change_default].freeze
129
119
 
130
- POSTGRESQL_COMBINABLE_ALTER_METHODS = %i[
131
- change_column_default
132
- ].freeze
120
+ POSTGRESQL_COMBINABLE_ALTER_METHODS = %i[change_column_default].freeze
133
121
 
134
122
  def on_def(node)
135
123
  return unless support_bulk_alter?
@@ -186,8 +174,7 @@ module RuboCop
186
174
  options = node.arguments[1]
187
175
  return false unless options
188
176
 
189
- options.hash_type? &&
190
- options.keys.any? { |key| key.sym_type? && key.value == :bulk }
177
+ options.hash_type? && options.keys.any? { |key| key.sym_type? && key.value == :bulk }
191
178
  end
192
179
 
193
180
  def database
@@ -237,8 +224,7 @@ module RuboCop
237
224
  end
238
225
 
239
226
  def call_to_combinable_alter_method?(child_node)
240
- child_node.send_type? &&
241
- combinable_alter_methods.include?(child_node.method_name)
227
+ child_node.send_type? && combinable_alter_methods.include?(child_node.method_name)
242
228
  end
243
229
 
244
230
  def combinable_alter_methods
@@ -93,7 +93,11 @@ module RuboCop
93
93
  end
94
94
 
95
95
  def offense_range(node)
96
- end_pos = node.parent&.block_type? ? node.parent.loc.expression.end_pos : node.loc.expression.end_pos
96
+ end_pos = if node.parent&.block_type? && node.parent&.send_node == node
97
+ node.parent.loc.expression.end_pos
98
+ else
99
+ node.loc.expression.end_pos
100
+ end
97
101
 
98
102
  range_between(node.loc.selector.begin_pos, end_pos)
99
103
  end
@@ -37,9 +37,7 @@ module RuboCop
37
37
  return if node.arguments.count >= 3
38
38
 
39
39
  first_argument = node.first_argument
40
- return if !first_argument ||
41
- allowed_argument?(first_argument) ||
42
- corrected_ancestor?(node)
40
+ return if !first_argument || allowed_argument?(first_argument) || corrected_ancestor?(node)
43
41
 
44
42
  preferred_method = node.first_argument.value.to_s.underscore
45
43
  message = format(MSG, preferred_method: preferred_method, current_argument: first_argument.source)
@@ -58,7 +56,8 @@ module RuboCop
58
56
  argument.send_type? ||
59
57
  argument.const_type? ||
60
58
  argument.splat_type? ||
61
- allowed_name?(argument)
59
+ allowed_name?(argument) ||
60
+ !argument.respond_to?(:value)
62
61
  end
63
62
 
64
63
  def register_offense(node, message, preferred_method)
@@ -53,22 +53,17 @@ module RuboCop
53
53
  class Date < Base
54
54
  include ConfigurableEnforcedStyle
55
55
 
56
- MSG = 'Do not use `Date.%<method_called>s` without zone. Use ' \
57
- '`Time.zone.%<day>s` instead.'
56
+ MSG = 'Do not use `Date.%<method_called>s` without zone. Use `Time.zone.%<day>s` instead.'
58
57
 
59
- MSG_SEND = 'Do not use `%<method>s` on Date objects, because they ' \
60
- 'know nothing about the time zone in use.'
58
+ MSG_SEND = 'Do not use `%<method>s` on Date objects, because they know nothing about the time zone in use.'
61
59
 
62
60
  RESTRICT_ON_SEND = %i[to_time to_time_in_current_zone].freeze
63
61
 
64
62
  BAD_DAYS = %i[today current yesterday tomorrow].freeze
65
63
 
66
- DEPRECATED_METHODS = [
67
- { deprecated: 'to_time_in_current_zone', relevant: 'in_time_zone' }
68
- ].freeze
64
+ DEPRECATED_METHODS = [{ deprecated: 'to_time_in_current_zone', relevant: 'in_time_zone' }].freeze
69
65
 
70
- DEPRECATED_MSG = '`%<deprecated>s` is deprecated. ' \
71
- 'Use `%<relevant>s` instead.'
66
+ DEPRECATED_MSG = '`%<deprecated>s` is deprecated. Use `%<relevant>s` instead.'
72
67
 
73
68
  def on_const(node)
74
69
  mod, klass = *node.children
@@ -93,15 +93,12 @@ module RuboCop
93
93
  return false if arg_array.size != argument_array.size
94
94
 
95
95
  arg_array.zip(argument_array).all? do |arg, argument|
96
- arg.arg_type? &&
97
- argument.lvar_type? &&
98
- arg.children == argument.children
96
+ arg.arg_type? && argument.lvar_type? && arg.children == argument.children
99
97
  end
100
98
  end
101
99
 
102
100
  def method_name_matches?(method_name, body)
103
- method_name == body.method_name ||
104
- (include_prefix_case? && method_name == prefixed_method_name(body))
101
+ method_name == body.method_name || (include_prefix_case? && method_name == prefixed_method_name(body))
105
102
  end
106
103
 
107
104
  def include_prefix_case?
@@ -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
 
@@ -22,19 +22,23 @@ module RuboCop
22
22
  # User.find_by(name: name, email: email)
23
23
  # User.find_by!(email: email)
24
24
  #
25
- # @example AllowedMethods: find_by_sql
25
+ # @example AllowedMethods: ['find_by_sql', 'find_by_token_for'] (default)
26
26
  # # bad
27
27
  # User.find_by_query(users_query)
28
+ # User.find_by_token_for(:password_reset, token)
28
29
  #
29
30
  # # good
30
31
  # User.find_by_sql(users_sql)
32
+ # User.find_by_token_for(:password_reset, token)
31
33
  #
32
- # @example AllowedReceivers: Gem::Specification
34
+ # @example AllowedReceivers: ['Gem::Specification', 'page'] (default)
33
35
  # # bad
34
36
  # Specification.find_by_name('backend').gem_dir
37
+ # page.find_by_id('a_dom_id').click
35
38
  #
36
39
  # # good
37
40
  # Gem::Specification.find_by_name('backend').gem_dir
41
+ # page.find_by_id('a_dom_id').click
38
42
  class DynamicFindBy < Base
39
43
  include ActiveRecordHelper
40
44
  extend AutoCorrector
@@ -70,8 +74,7 @@ module RuboCop
70
74
  end
71
75
 
72
76
  def allowed_invocation?(node)
73
- allowed_method?(node) || allowed_receiver?(node) ||
74
- whitelisted?(node)
77
+ allowed_method?(node) || allowed_receiver?(node) || whitelisted?(node)
75
78
  end
76
79
 
77
80
  def allowed_method?(node)
@@ -95,8 +98,7 @@ module RuboCop
95
98
  end
96
99
 
97
100
  def autocorrect_method_name(corrector, node)
98
- corrector.replace(node.loc.selector,
99
- static_method_name(node.method_name.to_s))
101
+ corrector.replace(node.loc.selector, static_method_name(node.method_name.to_s))
100
102
  end
101
103
 
102
104
  def autocorrect_argument_keywords(corrector, node, keywords)
@@ -37,6 +37,10 @@ module RuboCop
37
37
  )
38
38
  PATTERN
39
39
 
40
+ def self.autocorrect_incompatible_with
41
+ [Style::MethodCallWithArgsParentheses]
42
+ end
43
+
40
44
  def on_send(node)
41
45
  return if node.parent&.block_type?
42
46
 
@@ -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
@@ -12,6 +12,7 @@ module RuboCop
12
12
  # render plain: 'foo/bar', status: 304
13
13
  # redirect_to root_url, status: 301
14
14
  # head 200
15
+ # get '/foobar', to: redirect('/foobar/baz', status: 301)
15
16
  #
16
17
  # # good
17
18
  # render :foo, status: :ok
@@ -19,6 +20,7 @@ module RuboCop
19
20
  # render plain: 'foo/bar', status: :not_modified
20
21
  # redirect_to root_url, status: :moved_permanently
21
22
  # head :ok
23
+ # get '/foobar', to: redirect('/foobar/baz', status: :moved_permanently)
22
24
  #
23
25
  # @example EnforcedStyle: numeric
24
26
  # # bad
@@ -27,6 +29,7 @@ module RuboCop
27
29
  # render plain: 'foo/bar', status: :not_modified
28
30
  # redirect_to root_url, status: :moved_permanently
29
31
  # head :ok
32
+ # get '/foobar', to: redirect('/foobar/baz', status: :moved_permanently)
30
33
  #
31
34
  # # good
32
35
  # render :foo, status: 200
@@ -34,18 +37,20 @@ module RuboCop
34
37
  # render plain: 'foo/bar', status: 304
35
38
  # redirect_to root_url, status: 301
36
39
  # head 200
40
+ # get '/foobar', to: redirect('/foobar/baz', status: 301)
37
41
  #
38
42
  class HttpStatus < Base
39
43
  include ConfigurableEnforcedStyle
40
44
  extend AutoCorrector
41
45
 
42
- RESTRICT_ON_SEND = %i[render redirect_to head].freeze
46
+ RESTRICT_ON_SEND = %i[render redirect_to head redirect].freeze
43
47
 
44
48
  def_node_matcher :http_status, <<~PATTERN
45
49
  {
46
50
  (send nil? {:render :redirect_to} _ $hash)
47
51
  (send nil? {:render :redirect_to} $hash)
48
52
  (send nil? :head ${int sym} ...)
53
+ (send nil? :redirect _ $hash)
49
54
  }
50
55
  PATTERN
51
56
 
@@ -84,10 +89,8 @@ module RuboCop
84
89
 
85
90
  # :nodoc:
86
91
  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.'
92
+ MSG = 'Prefer `%<prefer>s` over `%<current>s` to define HTTP status code.'
93
+ DEFAULT_MSG = 'Prefer `symbolic` over `numeric` to define HTTP status code.'
91
94
 
92
95
  attr_reader :node
93
96
 
@@ -118,17 +121,14 @@ module RuboCop
118
121
  end
119
122
 
120
123
  def custom_http_status_code?
121
- node.int_type? &&
122
- !::Rack::Utils::SYMBOL_TO_STATUS_CODE.value?(number)
124
+ node.int_type? && !::Rack::Utils::SYMBOL_TO_STATUS_CODE.value?(number)
123
125
  end
124
126
  end
125
127
 
126
128
  # :nodoc:
127
129
  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.'
130
+ MSG = 'Prefer `%<prefer>s` over `%<current>s` to define HTTP status code.'
131
+ DEFAULT_MSG = 'Prefer `numeric` over `symbolic` to define HTTP status code.'
132
132
  PERMITTED_STATUS = %i[error success missing redirect].freeze
133
133
 
134
134
  attr_reader :node
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Rails
6
+ # Looks for assignments of `ignored_columns` that may override previous
7
+ # assignments.
8
+ #
9
+ # Overwriting previous assignments is usually a mistake, since it will
10
+ # un-ignore the first set of columns. Since duplicate column names is not
11
+ # a problem, it is better to simply append to the list.
12
+ #
13
+ # @example
14
+ #
15
+ # # bad
16
+ # class User < ActiveRecord::Base
17
+ # self.ignored_columns = [:one]
18
+ # end
19
+ #
20
+ # # bad
21
+ # class User < ActiveRecord::Base
22
+ # self.ignored_columns = [:one, :two]
23
+ # end
24
+ #
25
+ # # good
26
+ # class User < ActiveRecord::Base
27
+ # self.ignored_columns += [:one, :two]
28
+ # end
29
+ #
30
+ # # good
31
+ # class User < ActiveRecord::Base
32
+ # self.ignored_columns += [:one]
33
+ # self.ignored_columns += [:two]
34
+ # end
35
+ #
36
+ class IgnoredColumnsAssignment < Base
37
+ extend AutoCorrector
38
+
39
+ MSG = 'Use `+=` instead of `=`.'
40
+ RESTRICT_ON_SEND = %i[ignored_columns=].freeze
41
+
42
+ def on_send(node)
43
+ add_offense(node.loc.operator) do |corrector|
44
+ corrector.replace(node.loc.operator, '+=')
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
@@ -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