rubocop-rails 2.14.2 → 2.19.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 (142) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE.txt +1 -1
  3. data/README.md +23 -2
  4. data/config/default.yml +190 -12
  5. data/config/obsoletion.yml +10 -0
  6. data/lib/rubocop/cop/mixin/active_record_helper.rb +3 -6
  7. data/lib/rubocop/cop/mixin/active_record_migrations_helper.rb +1 -3
  8. data/lib/rubocop/cop/mixin/enforce_superclass.rb +1 -1
  9. data/lib/rubocop/cop/mixin/index_method.rb +7 -17
  10. data/lib/rubocop/cop/mixin/migrations_helper.rb +1 -1
  11. data/lib/rubocop/cop/rails/action_controller_flash_before_render.rb +112 -0
  12. data/lib/rubocop/cop/rails/action_controller_test_case.rb +2 -2
  13. data/lib/rubocop/cop/rails/action_filter.rb +2 -2
  14. data/lib/rubocop/cop/rails/action_order.rb +116 -0
  15. data/lib/rubocop/cop/rails/active_record_aliases.rb +3 -4
  16. data/lib/rubocop/cop/rails/active_record_callbacks_order.rb +7 -4
  17. data/lib/rubocop/cop/rails/active_record_override.rb +2 -5
  18. data/lib/rubocop/cop/rails/active_support_aliases.rb +1 -1
  19. data/lib/rubocop/cop/rails/active_support_on_load.rb +70 -0
  20. data/lib/rubocop/cop/rails/add_column_index.rb +3 -6
  21. data/lib/rubocop/cop/rails/after_commit_override.rb +1 -1
  22. data/lib/rubocop/cop/rails/application_controller.rb +2 -2
  23. data/lib/rubocop/cop/rails/application_job.rb +3 -3
  24. data/lib/rubocop/cop/rails/application_mailer.rb +2 -2
  25. data/lib/rubocop/cop/rails/application_record.rb +2 -2
  26. data/lib/rubocop/cop/rails/arel_star.rb +2 -2
  27. data/lib/rubocop/cop/rails/assert_not.rb +1 -1
  28. data/lib/rubocop/cop/rails/attribute_default_block_value.rb +1 -1
  29. data/lib/rubocop/cop/rails/belongs_to.rb +2 -5
  30. data/lib/rubocop/cop/rails/blank.rb +10 -11
  31. data/lib/rubocop/cop/rails/bulk_change_table.rb +8 -25
  32. data/lib/rubocop/cop/rails/compact_blank.rb +6 -2
  33. data/lib/rubocop/cop/rails/content_tag.rb +6 -7
  34. data/lib/rubocop/cop/rails/create_table_with_timestamps.rb +16 -3
  35. data/lib/rubocop/cop/rails/date.rb +12 -17
  36. data/lib/rubocop/cop/rails/default_scope.rb +1 -1
  37. data/lib/rubocop/cop/rails/delegate.rb +24 -18
  38. data/lib/rubocop/cop/rails/delegate_allow_blank.rb +2 -2
  39. data/lib/rubocop/cop/rails/deprecated_active_model_errors_methods.rb +63 -3
  40. data/lib/rubocop/cop/rails/dot_separated_keys.rb +71 -0
  41. data/lib/rubocop/cop/rails/duplicate_association.rb +2 -2
  42. data/lib/rubocop/cop/rails/duplicate_scope.rb +1 -1
  43. data/lib/rubocop/cop/rails/duration_arithmetic.rb +4 -4
  44. data/lib/rubocop/cop/rails/dynamic_find_by.rb +26 -14
  45. data/lib/rubocop/cop/rails/eager_evaluation_log_message.rb +6 -2
  46. data/lib/rubocop/cop/rails/enum_hash.rb +3 -4
  47. data/lib/rubocop/cop/rails/enum_uniqueness.rb +3 -6
  48. data/lib/rubocop/cop/rails/environment_comparison.rb +3 -4
  49. data/lib/rubocop/cop/rails/environment_variable_access.rb +1 -1
  50. data/lib/rubocop/cop/rails/exit.rb +1 -1
  51. data/lib/rubocop/cop/rails/expanded_date_range.rb +39 -23
  52. data/lib/rubocop/cop/rails/file_path.rb +41 -24
  53. data/lib/rubocop/cop/rails/find_by.rb +1 -1
  54. data/lib/rubocop/cop/rails/find_by_id.rb +3 -3
  55. data/lib/rubocop/cop/rails/find_each.rb +14 -4
  56. data/lib/rubocop/cop/rails/freeze_time.rb +79 -0
  57. data/lib/rubocop/cop/rails/has_and_belongs_to_many.rb +1 -1
  58. data/lib/rubocop/cop/rails/has_many_or_has_one_dependent.rb +14 -8
  59. data/lib/rubocop/cop/rails/helper_instance_variable.rb +3 -3
  60. data/lib/rubocop/cop/rails/http_positional_arguments.rb +23 -12
  61. data/lib/rubocop/cop/rails/http_status.rb +6 -11
  62. data/lib/rubocop/cop/rails/i18n_lazy_lookup.rb +3 -1
  63. data/lib/rubocop/cop/rails/i18n_locale_assignment.rb +1 -1
  64. data/lib/rubocop/cop/rails/i18n_locale_texts.rb +2 -2
  65. data/lib/rubocop/cop/rails/ignored_columns_assignment.rb +50 -0
  66. data/lib/rubocop/cop/rails/ignored_skip_action_filter_option.rb +5 -14
  67. data/lib/rubocop/cop/rails/index_by.rb +2 -2
  68. data/lib/rubocop/cop/rails/index_with.rb +2 -2
  69. data/lib/rubocop/cop/rails/inquiry.rb +1 -1
  70. data/lib/rubocop/cop/rails/inverse_of.rb +4 -10
  71. data/lib/rubocop/cop/rails/lexically_scoped_action_filter.rb +22 -16
  72. data/lib/rubocop/cop/rails/link_to_blank.rb +2 -5
  73. data/lib/rubocop/cop/rails/mailer_name.rb +5 -5
  74. data/lib/rubocop/cop/rails/match_route.rb +1 -1
  75. data/lib/rubocop/cop/rails/migration_class_name.rb +2 -2
  76. data/lib/rubocop/cop/rails/negate_include.rb +2 -2
  77. data/lib/rubocop/cop/rails/not_null_column.rb +10 -7
  78. data/lib/rubocop/cop/rails/order_by_id.rb +2 -3
  79. data/lib/rubocop/cop/rails/output.rb +7 -9
  80. data/lib/rubocop/cop/rails/output_safety.rb +6 -2
  81. data/lib/rubocop/cop/rails/pick.rb +1 -1
  82. data/lib/rubocop/cop/rails/pluck.rb +45 -13
  83. data/lib/rubocop/cop/rails/pluck_id.rb +2 -2
  84. data/lib/rubocop/cop/rails/pluck_in_where.rb +1 -1
  85. data/lib/rubocop/cop/rails/pluralization_grammar.rb +2 -3
  86. data/lib/rubocop/cop/rails/presence.rb +22 -13
  87. data/lib/rubocop/cop/rails/present.rb +10 -13
  88. data/lib/rubocop/cop/rails/rake_environment.rb +3 -3
  89. data/lib/rubocop/cop/rails/read_write_attribute.rb +2 -2
  90. data/lib/rubocop/cop/rails/redundant_allow_nil.rb +5 -7
  91. data/lib/rubocop/cop/rails/redundant_foreign_key.rb +3 -3
  92. data/lib/rubocop/cop/rails/redundant_presence_validation_on_belongs_to.rb +3 -3
  93. data/lib/rubocop/cop/rails/redundant_receiver_in_with_options.rb +31 -27
  94. data/lib/rubocop/cop/rails/redundant_travel_back.rb +1 -1
  95. data/lib/rubocop/cop/rails/reflection_class_name.rb +35 -2
  96. data/lib/rubocop/cop/rails/refute_methods.rb +1 -5
  97. data/lib/rubocop/cop/rails/relative_date_constant.rb +5 -8
  98. data/lib/rubocop/cop/rails/render_inline.rb +1 -1
  99. data/lib/rubocop/cop/rails/render_plain_text.rb +1 -1
  100. data/lib/rubocop/cop/rails/request_referer.rb +2 -3
  101. data/lib/rubocop/cop/rails/require_dependency.rb +2 -2
  102. data/lib/rubocop/cop/rails/response_parsed_body.rb +57 -0
  103. data/lib/rubocop/cop/rails/reversible_migration.rb +15 -63
  104. data/lib/rubocop/cop/rails/reversible_migration_method_definition.rb +5 -6
  105. data/lib/rubocop/cop/rails/root_join_chain.rb +1 -1
  106. data/lib/rubocop/cop/rails/root_pathname_methods.rb +238 -0
  107. data/lib/rubocop/cop/rails/root_public_path.rb +59 -0
  108. data/lib/rubocop/cop/rails/safe_navigation.rb +8 -13
  109. data/lib/rubocop/cop/rails/safe_navigation_with_blank.rb +2 -4
  110. data/lib/rubocop/cop/rails/save_bang.rb +12 -24
  111. data/lib/rubocop/cop/rails/schema_comment.rb +1 -1
  112. data/lib/rubocop/cop/rails/scope_args.rb +1 -1
  113. data/lib/rubocop/cop/rails/short_i18n.rb +3 -6
  114. data/lib/rubocop/cop/rails/skips_model_validations.rb +3 -4
  115. data/lib/rubocop/cop/rails/squished_sql_heredocs.rb +10 -7
  116. data/lib/rubocop/cop/rails/strip_heredoc.rb +56 -0
  117. data/lib/rubocop/cop/rails/table_name_assignment.rb +1 -1
  118. data/lib/rubocop/cop/rails/three_state_boolean_column.rb +73 -0
  119. data/lib/rubocop/cop/rails/time_zone.rb +34 -32
  120. data/lib/rubocop/cop/rails/time_zone_assignment.rb +4 -4
  121. data/lib/rubocop/cop/rails/to_formatted_s.rb +46 -0
  122. data/lib/rubocop/cop/rails/to_s_with_argument.rb +78 -0
  123. data/lib/rubocop/cop/rails/top_level_hash_with_indifferent_access.rb +49 -0
  124. data/lib/rubocop/cop/rails/transaction_exit_statement.rb +17 -12
  125. data/lib/rubocop/cop/rails/uniq_before_pluck.rb +3 -6
  126. data/lib/rubocop/cop/rails/unique_validation_without_index.rb +14 -7
  127. data/lib/rubocop/cop/rails/unknown_env.rb +3 -5
  128. data/lib/rubocop/cop/rails/unused_ignored_columns.rb +7 -2
  129. data/lib/rubocop/cop/rails/validation.rb +5 -13
  130. data/lib/rubocop/cop/rails/where_equals.rb +2 -2
  131. data/lib/rubocop/cop/rails/where_exists.rb +3 -3
  132. data/lib/rubocop/cop/rails/where_missing.rb +118 -0
  133. data/lib/rubocop/cop/rails/where_not.rb +2 -2
  134. data/lib/rubocop/cop/rails/where_not_with_multiple_conditions.rb +55 -0
  135. data/lib/rubocop/cop/rails_cops.rb +16 -0
  136. data/lib/rubocop/rails/schema_loader/schema.rb +8 -5
  137. data/lib/rubocop/rails/version.rb +1 -1
  138. data/lib/rubocop/rails.rb +1 -1
  139. data/lib/rubocop-rails.rb +19 -0
  140. metadata +23 -9
  141. data/bin/console +0 -11
  142. data/bin/setup +0 -7
@@ -3,7 +3,7 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Rails
6
- # This cop checks for add_column call with NOT NULL constraint
6
+ # Checks for add_column call with NOT NULL constraint
7
7
  # in migration file.
8
8
  #
9
9
  # @example
@@ -21,7 +21,7 @@ module RuboCop
21
21
  RESTRICT_ON_SEND = %i[add_column add_reference].freeze
22
22
 
23
23
  def_node_matcher :add_not_null_column?, <<~PATTERN
24
- (send nil? :add_column _ _ _ (hash $...))
24
+ (send nil? :add_column _ _ $_ (hash $...))
25
25
  PATTERN
26
26
 
27
27
  def_node_matcher :add_not_null_reference?, <<~PATTERN
@@ -44,17 +44,20 @@ module RuboCop
44
44
  private
45
45
 
46
46
  def check_add_column(node)
47
- pairs = add_not_null_column?(node)
48
- check_pairs(pairs)
47
+ add_not_null_column?(node) do |type, pairs|
48
+ return if type.value == :virtual || type.value == 'virtual'
49
+
50
+ check_pairs(pairs)
51
+ end
49
52
  end
50
53
 
51
54
  def check_add_reference(node)
52
- pairs = add_not_null_reference?(node)
53
- check_pairs(pairs)
55
+ add_not_null_reference?(node) do |pairs|
56
+ check_pairs(pairs)
57
+ end
54
58
  end
55
59
 
56
60
  def check_pairs(pairs)
57
- return unless pairs
58
61
  return if pairs.any? { |pair| default_option?(pair) }
59
62
 
60
63
  null_false = pairs.find { |pair| null_false?(pair) }
@@ -3,7 +3,7 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Rails
6
- # This cop checks for places where ordering by `id` column is used.
6
+ # Checks for places where ordering by `id` column is used.
7
7
  #
8
8
  # Don't use the `id` column for ordering. The sequence of ids is not guaranteed
9
9
  # to be in any particular order, despite often (incidentally) being chronological.
@@ -23,8 +23,7 @@ module RuboCop
23
23
  class OrderById < Base
24
24
  include RangeHelp
25
25
 
26
- MSG = 'Do not use the `id` column for ordering. '\
27
- 'Use a timestamp column to order chronologically.'
26
+ MSG = 'Do not use the `id` column for ordering. Use a timestamp column to order chronologically.'
28
27
  RESTRICT_ON_SEND = %i[order].freeze
29
28
 
30
29
  def_node_matcher :order_by_id?, <<~PATTERN
@@ -3,7 +3,7 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Rails
6
- # This cop checks for the use of output calls like puts and print
6
+ # Checks for the use of output calls like puts and print
7
7
  #
8
8
  # @safety
9
9
  # This cop's autocorrection is unsafe because depending on the Rails log level configuration,
@@ -21,11 +21,8 @@ module RuboCop
21
21
  include RangeHelp
22
22
  extend AutoCorrector
23
23
 
24
- MSG = 'Do not write to stdout. ' \
25
- "Use Rails's logger if you want to log."
26
- RESTRICT_ON_SEND = %i[
27
- ap p pp pretty_print print puts binwrite syswrite write write_nonblock
28
- ].freeze
24
+ MSG = "Do not write to stdout. Use Rails's logger if you want to log."
25
+ RESTRICT_ON_SEND = %i[ap p pp pretty_print print puts binwrite syswrite write write_nonblock].freeze
29
26
 
30
27
  def_node_matcher :output?, <<~PATTERN
31
28
  (send nil? {:ap :p :pp :pretty_print :print :puts} ...)
@@ -35,14 +32,15 @@ module RuboCop
35
32
  (send
36
33
  {
37
34
  (gvar #match_gvar?)
38
- {(const nil? :STDOUT) (const nil? :STDERR)}
35
+ (const {nil? cbase} {:STDOUT :STDERR})
39
36
  }
40
37
  {:binwrite :syswrite :write :write_nonblock}
41
38
  ...)
42
39
  PATTERN
43
40
 
44
41
  def on_send(node)
45
- return unless (output?(node) || io_output?(node)) && node.arguments?
42
+ return if node.parent&.call_type?
43
+ return unless output?(node) || io_output?(node)
46
44
 
47
45
  range = offense_range(node)
48
46
 
@@ -59,7 +57,7 @@ module RuboCop
59
57
 
60
58
  def offense_range(node)
61
59
  if node.receiver
62
- 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)
63
61
  else
64
62
  node.loc.selector
65
63
  end
@@ -3,7 +3,7 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Rails
6
- # This cop checks for the use of output safety calls like `html_safe`,
6
+ # Checks for the use of output safety calls like `html_safe`,
7
7
  # `raw`, and `safe_concat`. These methods do not escape content. They
8
8
  # simply return a SafeBuffer containing the content as is. Instead,
9
9
  # use `safe_join` to join content and escape it and concat to
@@ -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) ||
@@ -3,7 +3,7 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Rails
6
- # This cop enforces the use of `pick` over `pluck(...).first`.
6
+ # Enforces the use of `pick` over `pluck(...).first`.
7
7
  #
8
8
  # Using `pluck` followed by `first` creates an intermediate array, which
9
9
  # `pick` avoids. When called on an Active Record relation, `pick` adds a
@@ -3,12 +3,24 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Rails
6
- # This cop enforces the use of `pluck` over `map`.
6
+ # Enforces the use of `pluck` over `map`.
7
7
  #
8
8
  # `pluck` can be used instead of `map` to extract a single key from each
9
9
  # element in an enumerable. When called on an Active Record relation, it
10
10
  # results in a more efficient query that only selects the necessary key.
11
11
  #
12
+ # @safety
13
+ # This cop is unsafe because model can use column aliases.
14
+ #
15
+ # [source,ruby]
16
+ # ----
17
+ # # Original code
18
+ # User.select('name AS nickname').map { |user| user[:nickname] } # => array of nicknames
19
+ #
20
+ # # After autocorrection
21
+ # User.select('name AS nickname').pluck(:nickname) # => raises ActiveRecord::StatementInvalid
22
+ # ----
23
+ #
12
24
  # @example
13
25
  # # bad
14
26
  # Post.published.map { |post| post[:title] }
@@ -21,42 +33,62 @@ module RuboCop
21
33
  extend AutoCorrector
22
34
  extend TargetRailsVersion
23
35
 
24
- MSG = 'Prefer `pluck(:%<value>s)` over `%<current>s`.'
36
+ MSG = 'Prefer `%<replacement>s` over `%<current>s`.'
25
37
 
26
38
  minimum_target_rails_version 5.0
27
39
 
28
40
  def_node_matcher :pluck_candidate?, <<~PATTERN
29
- ({block numblock} (send _ {:map :collect}) $_argument (send (lvar $_element) :[] (sym $_value)))
41
+ ({block numblock} (send _ {:map :collect}) $_argument (send lvar :[] $_key))
30
42
  PATTERN
31
43
 
32
44
  def on_block(node)
33
- pluck_candidate?(node) do |argument, element, value|
45
+ pluck_candidate?(node) do |argument, key|
46
+ next if key.regexp_type? || !use_one_block_argument?(argument)
47
+
34
48
  match = if node.block_type?
35
- argument.children.first.source.to_sym == element
49
+ block_argument = argument.children.first.source
50
+ use_block_argument_in_key?(block_argument, key)
36
51
  else # numblock
37
- argument == 1 && element == :_1
52
+ argument == 1 && use_block_argument_in_key?('_1', key)
38
53
  end
39
54
  next unless match
40
55
 
41
- message = message(value, node)
42
-
43
- add_offense(offense_range(node), message: message) do |corrector|
44
- corrector.replace(offense_range(node), "pluck(:#{value})")
45
- end
56
+ register_offense(node, key)
46
57
  end
47
58
  end
48
59
  alias on_numblock on_block
49
60
 
50
61
  private
51
62
 
63
+ def use_one_block_argument?(argument)
64
+ return true if argument == 1 # Checks for numbered argument `_1`.
65
+
66
+ argument.respond_to?(:one?) && argument.one?
67
+ end
68
+
69
+ def use_block_argument_in_key?(block_argument, key)
70
+ return false if block_argument == key.source
71
+
72
+ key.each_descendant(:lvar).none? { |lvar| block_argument == lvar.source }
73
+ end
74
+
52
75
  def offense_range(node)
53
76
  node.send_node.loc.selector.join(node.loc.end)
54
77
  end
55
78
 
56
- def message(value, node)
79
+ def register_offense(node, key)
80
+ replacement = "pluck(#{key.source})"
81
+ message = message(replacement, node)
82
+
83
+ add_offense(offense_range(node), message: message) do |corrector|
84
+ corrector.replace(offense_range(node), replacement)
85
+ end
86
+ end
87
+
88
+ def message(replacement, node)
57
89
  current = offense_range(node).source
58
90
 
59
- format(MSG, value: value, current: current)
91
+ format(MSG, replacement: replacement, current: current)
60
92
  end
61
93
  end
62
94
  end
@@ -3,7 +3,7 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Rails
6
- # This cop enforces the use of `ids` over `pluck(:id)` and `pluck(primary_key)`.
6
+ # Enforces the use of `ids` over `pluck(:id)` and `pluck(primary_key)`.
7
7
  #
8
8
  # @safety
9
9
  # This cop is unsafe if the receiver object is not an Active Record object.
@@ -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
@@ -3,7 +3,7 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Rails
6
- # This cop identifies places where `pluck` is used in `where` query methods
6
+ # Identifies places where `pluck` is used in `where` query methods
7
7
  # and can be replaced with `select`.
8
8
  #
9
9
  # Since `pluck` is an eager method and hits the database immediately,
@@ -3,7 +3,7 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Rails
6
- # This cop checks for correct grammar when using ActiveSupport's
6
+ # Checks for correct grammar when using ActiveSupport's
7
7
  # core extensions to the numeric classes.
8
8
  #
9
9
  # @example
@@ -94,8 +94,7 @@ module RuboCop
94
94
  end
95
95
 
96
96
  def duration_method?(method_name)
97
- SINGULAR_DURATION_METHODS.key?(method_name) ||
98
- PLURAL_DURATION_METHODS.key?(method_name)
97
+ SINGULAR_DURATION_METHODS.key?(method_name) || PLURAL_DURATION_METHODS.key?(method_name)
99
98
  end
100
99
  end
101
100
  end
@@ -3,7 +3,7 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Rails
6
- # This cop checks code that can be written more easily using
6
+ # Checks code that can be written more easily using
7
7
  # `Object#presence` defined by Active Support.
8
8
  #
9
9
  # @example
@@ -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))
96
+ corrector.replace(node, replacement(receiver, other, node.left_sibling))
97
97
  end
98
98
  end
99
99
 
@@ -106,12 +106,20 @@ module RuboCop
106
106
  end
107
107
 
108
108
  def message(node, receiver, other)
109
- format(MSG,
110
- prefer: replacement(receiver, other),
111
- current: node.source)
109
+ prefer = replacement(receiver, other, node.left_sibling).gsub(/^\s*|\n/, '')
110
+ current = current(node).gsub(/^\s*|\n/, '')
111
+ format(MSG, prefer: prefer, current: current)
112
112
  end
113
113
 
114
- def replacement(receiver, other)
114
+ def current(node)
115
+ if !node.ternary? && node.source.include?("\n")
116
+ "#{node.loc.keyword.with(end_pos: node.condition.loc.selector.end_pos).source} ... end"
117
+ else
118
+ node.source.gsub(/\n\s*/, ' ')
119
+ end
120
+ end
121
+
122
+ def replacement(receiver, other, left_sibling)
115
123
  or_source = if other&.send_type?
116
124
  build_source_for_or_method(other)
117
125
  elsif other.nil? || other.nil_type?
@@ -120,23 +128,24 @@ module RuboCop
120
128
  " || #{other.source}"
121
129
  end
122
130
 
123
- "#{receiver.source}.presence" + or_source
131
+ replaced = "#{receiver.source}.presence#{or_source}"
132
+ left_sibling ? "(#{replaced})" : replaced
124
133
  end
125
134
 
126
135
  def build_source_for_or_method(other)
127
- if other.parenthesized? || other.method?('[]') || !other.arguments?
136
+ if other.parenthesized? || other.method?('[]') || other.arithmetic_operation? || !other.arguments?
128
137
  " || #{other.source}"
129
138
  else
130
- method = range_between(
131
- other.source_range.begin_pos,
132
- other.first_argument.source_range.begin_pos - 1
133
- ).source
134
-
139
+ method = method_range(other).source
135
140
  arguments = other.arguments.map(&:source).join(', ')
136
141
 
137
142
  " || #{method}(#{arguments})"
138
143
  end
139
144
  end
145
+
146
+ def method_range(node)
147
+ range_between(node.source_range.begin_pos, node.first_argument.source_range.begin_pos - 1)
148
+ end
140
149
  end
141
150
  end
142
151
  end
@@ -3,13 +3,13 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Rails
6
- # This cop checks for code that can be written with simpler conditionals
6
+ # Checks for code that can be written with simpler conditionals
7
7
  # using `Object#present?` defined by Active Support.
8
8
  #
9
9
  # Interaction with `Style/UnlessElse`:
10
10
  # The configuration of `NotBlank` will not produce an offense in the
11
- # context of `unless else` if `Style/UnlessElse` is inabled. This is
12
- # to prevent interference between the auto-correction of the two cops.
11
+ # context of `unless else` if `Style/UnlessElse` is enabled. This is
12
+ # to prevent interference between the autocorrection of the two cops.
13
13
  #
14
14
  # @example NotNilAndNotEmpty: true (default)
15
15
  # # Converts usages of `!nil? && !empty?` to `present?`
@@ -47,10 +47,8 @@ module RuboCop
47
47
  extend AutoCorrector
48
48
 
49
49
  MSG_NOT_BLANK = 'Use `%<prefer>s` instead of `%<current>s`.'
50
- MSG_EXISTS_AND_NOT_EMPTY = 'Use `%<prefer>s` instead of ' \
51
- '`%<current>s`.'
52
- MSG_UNLESS_BLANK = 'Use `if %<prefer>s` instead of ' \
53
- '`%<current>s`.'
50
+ MSG_EXISTS_AND_NOT_EMPTY = 'Use `%<prefer>s` instead of `%<current>s`.'
51
+ MSG_UNLESS_BLANK = 'Use `if %<prefer>s` instead of `%<current>s`.'
54
52
  RESTRICT_ON_SEND = %i[!].freeze
55
53
 
56
54
  def_node_matcher :exists_and_not_empty?, <<~PATTERN
@@ -118,8 +116,7 @@ module RuboCop
118
116
 
119
117
  unless_blank?(node) do |method_call, receiver|
120
118
  range = unless_condition(node, method_call)
121
- msg = format(MSG_UNLESS_BLANK, prefer: replacement(receiver),
122
- current: range.source)
119
+ msg = format(MSG_UNLESS_BLANK, prefer: replacement(receiver), current: range.source)
123
120
  add_offense(range, message: msg) do |corrector|
124
121
  autocorrect(corrector, node)
125
122
  end
@@ -131,10 +128,10 @@ module RuboCop
131
128
 
132
129
  if method_call
133
130
  corrector.replace(node.loc.keyword, 'if')
134
- range = method_call.loc.expression
131
+ range = method_call.source_range
135
132
  else
136
133
  variable1, _variable2 = exists_and_not_empty?(node) || not_blank?(node)
137
- range = node.loc.expression
134
+ range = node.source_range
138
135
  end
139
136
 
140
137
  corrector.replace(range, replacement(variable1))
@@ -144,9 +141,9 @@ module RuboCop
144
141
 
145
142
  def unless_condition(node, method_call)
146
143
  if node.modifier_form?
147
- node.loc.keyword.join(node.loc.expression.end)
144
+ node.loc.keyword.join(node.source_range.end)
148
145
  else
149
- node.loc.expression.begin.join(method_call.loc.expression)
146
+ node.source_range.begin.join(method_call.source_range)
150
147
  end
151
148
  end
152
149
 
@@ -3,7 +3,7 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Rails
6
- # This cop checks for Rake tasks without the `:environment` task
6
+ # Checks for Rake tasks without the `:environment` task
7
7
  # dependency. The `:environment` task loads application code for other
8
8
  # Rake tasks. Without it, tasks cannot make use of application code like
9
9
  # models.
@@ -39,7 +39,7 @@ module RuboCop
39
39
  (block $(send nil? :task ...) ...)
40
40
  PATTERN
41
41
 
42
- def on_block(node)
42
+ def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler
43
43
  task_definition?(node) do |task_method|
44
44
  return if task_name(task_method) == :default
45
45
  return if with_dependencies?(task_method)
@@ -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
@@ -3,7 +3,7 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Rails
6
- # This cop checks for the use of the `read_attribute` or `write_attribute`
6
+ # Checks for the use of the `read_attribute` or `write_attribute`
7
7
  # methods and recommends square brackets instead.
8
8
  #
9
9
  # If an attribute is missing from the instance (for example, when
@@ -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
 
@@ -30,11 +30,9 @@ module RuboCop
30
30
  include RangeHelp
31
31
  extend AutoCorrector
32
32
 
33
- MSG_SAME =
34
- '`allow_nil` is redundant when `allow_blank` has the same value.'
33
+ MSG_SAME = '`allow_nil` is redundant when `allow_blank` has the same value.'
35
34
 
36
- MSG_ALLOW_NIL_FALSE =
37
- '`allow_nil: false` is redundant when `allow_blank` is true.'
35
+ MSG_ALLOW_NIL_FALSE = '`allow_nil: false` is redundant when `allow_blank` is true.'
38
36
 
39
37
  RESTRICT_ON_SEND = %i[validates].freeze
40
38
 
@@ -64,7 +62,7 @@ module RuboCop
64
62
  elsif prv_sib
65
63
  corrector.remove(range_between(node_end(prv_sib), node_end(allow_nil)))
66
64
  else
67
- corrector.remove(allow_nil.loc.expression)
65
+ corrector.remove(allow_nil)
68
66
  end
69
67
  end
70
68
  end
@@ -89,11 +87,11 @@ module RuboCop
89
87
  end
90
88
 
91
89
  def node_beg(node)
92
- node.loc.expression.begin_pos
90
+ node.source_range.begin_pos
93
91
  end
94
92
 
95
93
  def node_end(node)
96
- node.loc.expression.end_pos
94
+ node.source_range.end_pos
97
95
  end
98
96
  end
99
97
  end
@@ -3,7 +3,7 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Rails
6
- # This cop detects cases where the `:foreign_key` option on associations
6
+ # Detects cases where the `:foreign_key` option on associations
7
7
  # is redundant.
8
8
  #
9
9
  # @example
@@ -40,8 +40,8 @@ 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|
44
- range = range_with_surrounding_space(range: foreign_key_pair.source_range, side: :left)
43
+ add_offense(foreign_key_pair.source_range) do |corrector|
44
+ range = range_with_surrounding_space(foreign_key_pair.source_range, side: :left)
45
45
  range = range_with_surrounding_comma(range, :left)
46
46
 
47
47
  corrector.remove(range)
@@ -143,7 +143,7 @@ module RuboCop
143
143
  def_node_matcher :belongs_to_without_fk?, <<~PATTERN
144
144
  {
145
145
  (send nil? :belongs_to (sym %1)) # belongs_to :user
146
- (send nil? :belongs_to (sym %1) !hash) # belongs_to :user, -> { not_deleted }
146
+ (send nil? :belongs_to (sym %1) !hash ...) # belongs_to :user, -> { not_deleted }
147
147
  (send nil? :belongs_to (sym %1) !(hash <(pair (sym :foreign_key) _) ...>))
148
148
  }
149
149
  PATTERN
@@ -217,7 +217,7 @@ module RuboCop
217
217
  keys.each do |key|
218
218
  key_node = node.arguments.find { |arg| arg.value == key }
219
219
  key_range = range_with_surrounding_space(
220
- range: range_with_surrounding_comma(key_node.source_range, :right),
220
+ range_with_surrounding_comma(key_node.source_range, :right),
221
221
  side: :right
222
222
  )
223
223
  corrector.remove(key_range)
@@ -226,7 +226,7 @@ module RuboCop
226
226
 
227
227
  def remove_presence_option(corrector, presence)
228
228
  range = range_with_surrounding_comma(
229
- range_with_surrounding_space(range: presence.source_range, side: :left),
229
+ range_with_surrounding_space(presence.source_range, side: :left),
230
230
  :left
231
231
  )
232
232
  corrector.remove(range)
@@ -3,7 +3,7 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Rails
6
- # This cop checks for redundant receiver in `with_options`.
6
+ # Checks for redundant receiver in `with_options`.
7
7
  # Receiver is implicit from Rails 4.2 or higher.
8
8
  #
9
9
  # @example
@@ -60,15 +60,6 @@ module RuboCop
60
60
 
61
61
  MSG = 'Redundant receiver in `with_options`.'
62
62
 
63
- def_node_matcher :with_options?, <<~PATTERN
64
- (block
65
- (send nil? :with_options
66
- (...))
67
- (args
68
- $_arg)
69
- $_body)
70
- PATTERN
71
-
72
63
  def_node_search :all_block_nodes_in, <<~PATTERN
73
64
  (block ...)
74
65
  PATTERN
@@ -78,29 +69,42 @@ module RuboCop
78
69
  PATTERN
79
70
 
80
71
  def on_block(node)
81
- with_options?(node) do |arg, body|
82
- return if body.nil?
83
- return unless all_block_nodes_in(body).count.zero?
84
-
85
- send_nodes = all_send_nodes_in(body)
86
-
87
- if send_nodes.all? { |n| same_value?(arg, n.receiver) }
88
- send_nodes.each do |send_node|
89
- receiver = send_node.receiver
90
- add_offense(receiver.source_range) do |corrector|
91
- autocorrect(corrector, send_node)
92
- end
93
- end
72
+ return unless node.method?(:with_options)
73
+ return unless (body = node.body)
74
+ return unless all_block_nodes_in(body).count.zero?
75
+
76
+ send_nodes = all_send_nodes_in(body)
77
+ return unless redundant_receiver?(send_nodes, node)
78
+
79
+ send_nodes.each do |send_node|
80
+ receiver = send_node.receiver
81
+ add_offense(receiver.source_range) do |corrector|
82
+ autocorrect(corrector, send_node, node)
94
83
  end
95
84
  end
96
85
  end
97
86
 
87
+ alias on_numblock on_block
88
+
98
89
  private
99
90
 
100
- def autocorrect(corrector, node)
101
- corrector.remove(node.receiver.source_range)
102
- corrector.remove(node.loc.dot)
103
- corrector.remove(block_argument_range(node))
91
+ def autocorrect(corrector, send_node, node)
92
+ corrector.remove(send_node.receiver)
93
+ corrector.remove(send_node.loc.dot)
94
+ corrector.remove(block_argument_range(send_node)) unless node.numblock_type?
95
+ end
96
+
97
+ def redundant_receiver?(send_nodes, node)
98
+ proc = if node.numblock_type?
99
+ ->(n) { n.receiver.lvar_type? && n.receiver.source == '_1' }
100
+ else
101
+ return false if node.arguments.empty?
102
+
103
+ arg = node.arguments.first
104
+ ->(n) { same_value?(arg, n.receiver) }
105
+ end
106
+
107
+ send_nodes.all?(&proc)
104
108
  end
105
109
 
106
110
  def block_argument_range(node)
@@ -3,7 +3,7 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Rails
6
- # This cop checks for redundant `travel_back` calls.
6
+ # Checks for redundant `travel_back` calls.
7
7
  # Since Rails 5.2, `travel_back` is automatically called at the end of the test.
8
8
  #
9
9
  # @example