rubocop 1.62.1 → 1.63.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (44) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/config/default.yml +23 -3
  4. data/lib/rubocop/config.rb +33 -10
  5. data/lib/rubocop/config_obsoletion.rb +1 -1
  6. data/lib/rubocop/cop/base.rb +37 -0
  7. data/lib/rubocop/cop/internal_affairs/example_description.rb +1 -0
  8. data/lib/rubocop/cop/lint/assignment_in_condition.rb +2 -2
  9. data/lib/rubocop/cop/lint/debugger.rb +27 -2
  10. data/lib/rubocop/cop/lint/empty_conditional_body.rb +1 -1
  11. data/lib/rubocop/cop/lint/non_deterministic_require_order.rb +1 -1
  12. data/lib/rubocop/cop/lint/redundant_with_index.rb +3 -0
  13. data/lib/rubocop/cop/mixin/code_length.rb +12 -1
  14. data/lib/rubocop/cop/mixin/method_complexity.rb +15 -6
  15. data/lib/rubocop/cop/mixin/safe_assignment.rb +1 -1
  16. data/lib/rubocop/cop/naming/block_forwarding.rb +31 -12
  17. data/lib/rubocop/cop/naming/file_name.rb +2 -2
  18. data/lib/rubocop/cop/naming/inclusive_language.rb +1 -2
  19. data/lib/rubocop/cop/style/alias.rb +1 -0
  20. data/lib/rubocop/cop/style/collection_compact.rb +3 -3
  21. data/lib/rubocop/cop/style/copyright.rb +16 -11
  22. data/lib/rubocop/cop/style/eval_with_location.rb +3 -1
  23. data/lib/rubocop/cop/style/exact_regexp_match.rb +2 -1
  24. data/lib/rubocop/cop/style/format_string.rb +9 -9
  25. data/lib/rubocop/cop/style/map_into_array.rb +175 -0
  26. data/lib/rubocop/cop/style/map_to_hash.rb +1 -1
  27. data/lib/rubocop/cop/style/map_to_set.rb +1 -1
  28. data/lib/rubocop/cop/style/redundant_argument.rb +24 -1
  29. data/lib/rubocop/cop/style/redundant_current_directory_in_path.rb +1 -1
  30. data/lib/rubocop/cop/style/redundant_each.rb +1 -1
  31. data/lib/rubocop/cop/style/redundant_filter_chain.rb +1 -1
  32. data/lib/rubocop/cop/style/redundant_line_continuation.rb +8 -14
  33. data/lib/rubocop/cop/style/redundant_percent_q.rb +1 -1
  34. data/lib/rubocop/cop/style/require_order.rb +1 -1
  35. data/lib/rubocop/cop/team.rb +3 -0
  36. data/lib/rubocop/formatter/clang_style_formatter.rb +3 -7
  37. data/lib/rubocop/formatter/tap_formatter.rb +3 -7
  38. data/lib/rubocop/lockfile.rb +46 -7
  39. data/lib/rubocop/rspec/expect_offense.rb +8 -0
  40. data/lib/rubocop/rspec/shared_contexts.rb +13 -1
  41. data/lib/rubocop/runner.rb +3 -0
  42. data/lib/rubocop/version.rb +2 -2
  43. data/lib/rubocop.rb +1 -0
  44. metadata +5 -4
@@ -25,27 +25,27 @@ module RuboCop
25
25
  #
26
26
  # @example EnforcedStyle: format (default)
27
27
  # # bad
28
- # puts sprintf('%10s', 'hoge')
29
- # puts '%10s' % 'hoge'
28
+ # puts sprintf('%10s', 'foo')
29
+ # puts '%10s' % 'foo'
30
30
  #
31
31
  # # good
32
- # puts format('%10s', 'hoge')
32
+ # puts format('%10s', 'foo')
33
33
  #
34
34
  # @example EnforcedStyle: sprintf
35
35
  # # bad
36
- # puts format('%10s', 'hoge')
37
- # puts '%10s' % 'hoge'
36
+ # puts format('%10s', 'foo')
37
+ # puts '%10s' % 'foo'
38
38
  #
39
39
  # # good
40
- # puts sprintf('%10s', 'hoge')
40
+ # puts sprintf('%10s', 'foo')
41
41
  #
42
42
  # @example EnforcedStyle: percent
43
43
  # # bad
44
- # puts format('%10s', 'hoge')
45
- # puts sprintf('%10s', 'hoge')
44
+ # puts format('%10s', 'foo')
45
+ # puts sprintf('%10s', 'foo')
46
46
  #
47
47
  # # good
48
- # puts '%10s' % 'hoge'
48
+ # puts '%10s' % 'foo'
49
49
  #
50
50
  class FormatString < Base
51
51
  include ConfigurableEnforcedStyle
@@ -0,0 +1,175 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Style
6
+ # Checks for usages of `each` with `<<`, `push`, or `append` which
7
+ # can be replaced by `map`.
8
+ #
9
+ # If `PreferredMethods` is configured for `map` in `Style/CollectionMethods`,
10
+ # this cop uses the specified method for replacement.
11
+ #
12
+ # NOTE: The return value of `Enumerable#each` is `self`, whereas the
13
+ # return value of `Enumerable#map` is an `Array`. They are not autocorrected
14
+ # when a return value could be used because these types differ.
15
+ #
16
+ # NOTE: It only detects when the mapping destination is a local variable
17
+ # initialized as an empty array and referred to only by the pushing operation.
18
+ # This is because, if not, it's challenging to statically guarantee that the
19
+ # mapping destination variable remains an empty array:
20
+ #
21
+ # [source,ruby]
22
+ # ----
23
+ # @dest = []
24
+ # src.each { |e| @dest << e * 2 } # `src` method may mutate `@dest`
25
+ #
26
+ # dest = []
27
+ # src.each { |e| dest << transform(e, dest) } # `transform` method may mutate `dest`
28
+ # ----
29
+ #
30
+ # @safety
31
+ # This cop is unsafe because not all objects that have an `each`
32
+ # method also have a `map` method (e.g. `ENV`). Additionally, for calls
33
+ # with a block, not all objects that have a `map` method return an array
34
+ # (e.g. `Enumerator::Lazy`).
35
+ #
36
+ # @example
37
+ # # bad
38
+ # dest = []
39
+ # src.each { |e| dest << e * 2 }
40
+ # dest
41
+ #
42
+ # # good
43
+ # dest = src.map { |e| e * 2 }
44
+ #
45
+ # # good - contains another operation
46
+ # dest = []
47
+ # src.each { |e| dest << e * 2; puts e }
48
+ # dest
49
+ #
50
+ class MapIntoArray < Base
51
+ include RangeHelp
52
+ extend AutoCorrector
53
+
54
+ MSG = 'Use `%<new_method_name>s` instead of `each` to map elements into an array.'
55
+
56
+ # @!method each_block_with_push?(node)
57
+ def_node_matcher :each_block_with_push?, <<-PATTERN
58
+ [
59
+ ^({begin kwbegin} ...)
60
+ ({block numblock} (send _ :each) _
61
+ (send (lvar _) {:<< :push :append} _))
62
+ ]
63
+ PATTERN
64
+
65
+ # @!method empty_array_asgn?(node)
66
+ def_node_matcher :empty_array_asgn?, '(lvasgn _ (array))'
67
+
68
+ # @!method lvar_ref?(node, name)
69
+ def_node_matcher :lvar_ref?, '(lvar %1)'
70
+
71
+ def self.joining_forces
72
+ VariableForce
73
+ end
74
+
75
+ def after_leaving_scope(scope, _variable_table)
76
+ (@scopes ||= []) << scope
77
+ end
78
+
79
+ def on_block(node)
80
+ return unless each_block_with_push?(node)
81
+
82
+ dest_var = find_dest_var(node)
83
+ return unless (asgn = find_closest_assignment(node, dest_var))
84
+ return unless empty_array_asgn?(asgn)
85
+ return unless dest_used_only_for_mapping?(node, dest_var, asgn)
86
+
87
+ register_offense(node, dest_var, asgn)
88
+ end
89
+
90
+ alias on_numblock on_block
91
+
92
+ private
93
+
94
+ def find_dest_var(block)
95
+ node = block.body.receiver
96
+ name = node.children.first
97
+
98
+ candidates = @scopes.lazy.filter_map { |s| s.variables[name] }
99
+ candidates.find { |v| v.references.any? { |n| n.node.equal?(node) } }
100
+ end
101
+
102
+ def find_closest_assignment(block, dest_var)
103
+ dest_var.assignments.reverse_each.lazy.map(&:node).find do |node|
104
+ node.source_range.end_pos < block.source_range.begin_pos
105
+ end
106
+ end
107
+
108
+ def dest_used_only_for_mapping?(block, dest_var, asgn)
109
+ range = asgn.source_range.join(block.source_range)
110
+
111
+ asgn.parent.equal?(block.parent) &&
112
+ dest_var.references.one? { |r| range.contains?(r.node.source_range) } &&
113
+ dest_var.assignments.one? { |a| range.contains?(a.node.source_range) }
114
+ end
115
+
116
+ def register_offense(block, dest_var, asgn)
117
+ add_offense(block, message: format(MSG, new_method_name: new_method_name)) do |corrector|
118
+ next if return_value_used?(block)
119
+
120
+ corrector.replace(block.send_node.selector, new_method_name)
121
+ remove_assignment(corrector, asgn)
122
+ correct_push_node(corrector, block.body)
123
+ correct_return_value_handling(corrector, block, dest_var)
124
+ end
125
+ end
126
+
127
+ def new_method_name
128
+ default = 'map'
129
+ alternative = config.for_cop('Style/CollectionMethods').dig('PreferredMethods', default)
130
+ alternative || default
131
+ end
132
+
133
+ def return_value_used?(node)
134
+ parent = node.parent
135
+
136
+ case parent&.type
137
+ when nil
138
+ false
139
+ when :begin, :kwbegin
140
+ !node.right_sibling && return_value_used?(parent)
141
+ when :block, :numblock
142
+ !parent.void_context?
143
+ else
144
+ true
145
+ end
146
+ end
147
+
148
+ def remove_assignment(corrector, asgn)
149
+ range = range_with_surrounding_space(asgn.source_range, side: :right)
150
+ range = range_with_surrounding_space(range, side: :right, newlines: false)
151
+
152
+ corrector.remove(range)
153
+ end
154
+
155
+ def correct_push_node(corrector, push_node)
156
+ range = push_node.source_range
157
+ arg_range = push_node.first_argument.source_range
158
+
159
+ corrector.remove(range_between(range.begin_pos, arg_range.begin_pos))
160
+ corrector.remove(range_between(arg_range.end_pos, range.end_pos))
161
+ end
162
+
163
+ def correct_return_value_handling(corrector, block, dest_var)
164
+ next_node = block.right_sibling
165
+
166
+ if lvar_ref?(next_node, dest_var.name)
167
+ corrector.remove(range_with_surrounding_space(next_node.source_range, side: :left))
168
+ end
169
+
170
+ corrector.insert_before(block, "#{dest_var.name} = ")
171
+ end
172
+ end
173
+ end
174
+ end
175
+ end
@@ -55,7 +55,7 @@ module RuboCop
55
55
  message = format(MSG, method: map_node.loc.selector.source, dot: to_h_node.loc.dot.source)
56
56
  add_offense(map_node.loc.selector, message: message) do |corrector|
57
57
  # If the `to_h` call already has a block, do not autocorrect.
58
- next if to_h_node.block_node
58
+ next if to_h_node.block_literal?
59
59
 
60
60
  autocorrect(corrector, to_h_node, map_node)
61
61
  end
@@ -44,7 +44,7 @@ module RuboCop
44
44
  message = format(MSG, method: map_node.loc.selector.source)
45
45
  add_offense(map_node.loc.selector, message: message) do |corrector|
46
46
  # If the `to_set` call already has a block, do not autocorrect.
47
- next if to_set_node.block_node
47
+ next if to_set_node.block_literal?
48
48
 
49
49
  autocorrect(corrector, to_set_node, map_node)
50
50
  end
@@ -81,7 +81,13 @@ module RuboCop
81
81
  redundant_argument = redundant_arg_for_method(node.method_name.to_s)
82
82
  return false if redundant_argument.nil?
83
83
 
84
- node.first_argument.source.sub(/\A'/, '"').sub(/'\z/, '"') == redundant_argument
84
+ target_argument = if node.first_argument.respond_to?(:value)
85
+ node.first_argument.value
86
+ else
87
+ node.first_argument
88
+ end
89
+
90
+ argument_matched?(target_argument, redundant_argument)
85
91
  end
86
92
 
87
93
  def redundant_arg_for_method(method_name)
@@ -98,6 +104,23 @@ module RuboCop
98
104
  range_with_surrounding_space(node.first_argument.source_range, newlines: false)
99
105
  end
100
106
  end
107
+
108
+ def argument_matched?(target_argument, redundant_argument)
109
+ argument = if target_argument.is_a?(AST::Node)
110
+ target_argument.source
111
+ elsif exclude_cntrl_character?(target_argument, redundant_argument)
112
+ target_argument.inspect
113
+ else
114
+ target_argument.to_s
115
+ end
116
+
117
+ argument == redundant_argument
118
+ end
119
+
120
+ def exclude_cntrl_character?(target_argument, redundant_argument)
121
+ !target_argument.to_s.sub(/\A'/, '"').sub(/'\z/, '"').match?(/[[:cntrl:]]/) ||
122
+ !redundant_argument.match?(/[[:cntrl:]]/)
123
+ end
101
124
  end
102
125
  end
103
126
  end
@@ -18,10 +18,10 @@ module RuboCop
18
18
  extend AutoCorrector
19
19
 
20
20
  MSG = 'Remove the redundant current directory path.'
21
+ RESTRICT_ON_SEND = %i[require_relative].freeze
21
22
  CURRENT_DIRECTORY_PATH = './'
22
23
 
23
24
  def on_send(node)
24
- return unless node.method?(:require_relative)
25
25
  return unless (first_argument = node.first_argument)
26
26
  return unless first_argument.str_content&.start_with?(CURRENT_DIRECTORY_PATH)
27
27
  return unless (index = first_argument.source.index(CURRENT_DIRECTORY_PATH))
@@ -86,7 +86,7 @@ module RuboCop
86
86
  def range(node)
87
87
  return node.selector unless node.method?(:each)
88
88
 
89
- if node.parent.call_type?
89
+ if node.parent&.call_type?
90
90
  node.selector.join(node.parent.loc.dot)
91
91
  else
92
92
  node.loc.dot.join(node.selector)
@@ -79,7 +79,7 @@ module RuboCop
79
79
  private_constant :REPLACEMENT_METHODS
80
80
 
81
81
  def on_send(node)
82
- return if node.arguments? || node.block_node
82
+ return if node.arguments? || node.block_literal?
83
83
 
84
84
  select_predicate?(node) do |select_node, filter_method|
85
85
  return if RAILS_METHODS.include?(filter_method) && !active_support_extensions_enabled?
@@ -72,7 +72,7 @@ module RuboCop
72
72
  ALLOWED_STRING_TOKENS = %i[tSTRING tSTRING_CONTENT].freeze
73
73
  ARGUMENT_TYPES = %i[
74
74
  kFALSE kNIL kSELF kTRUE tCONSTANT tCVAR tFLOAT tGVAR tIDENTIFIER tINTEGER tIVAR
75
- tLABEL tLBRACK tLCURLY tLPAREN_ARG tSTRING tSTRING_BEG tSYMBOL tXSTRING_BEG
75
+ tLBRACK tLCURLY tLPAREN_ARG tSTRING tSTRING_BEG tSYMBOL tXSTRING_BEG
76
76
  ].freeze
77
77
 
78
78
  def on_new_investigation
@@ -124,10 +124,8 @@ module RuboCop
124
124
  return true unless (node = find_node_for_line(range.line))
125
125
  return false if argument_newline?(node)
126
126
 
127
- continuation_node = node.parent || node
128
- return false if allowed_type?(node) || allowed_type?(continuation_node)
129
-
130
- continuation_node.source.include?("\n") || continuation_node.source.include?("\\\n")
127
+ source = node.parent ? node.parent.source : node.source
128
+ parse(source.gsub("\\\n", "\n")).valid_syntax?
131
129
  end
132
130
 
133
131
  def inside_string_literal?(range, token)
@@ -142,22 +140,22 @@ module RuboCop
142
140
  current_token.type == :tIDENTIFIER && ARGUMENT_TYPES.include?(next_token.type)
143
141
  end
144
142
 
145
- # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
143
+ # rubocop:disable Metrics/AbcSize
146
144
  def argument_newline?(node)
147
145
  node = node.to_a.last if node.assignment?
148
146
  return false if node.parenthesized_call?
149
147
 
150
148
  node = node.children.first if node.root? && node.begin_type?
151
149
 
152
- if argument_is_method?(node) || node.begin_type?
153
- argument_newline?(node.children.first)
150
+ if argument_is_method?(node)
151
+ argument_newline?(node.first_argument)
154
152
  else
155
153
  return false unless method_call_with_arguments?(node)
156
154
 
157
- !same_line?(node, node.first_argument)
155
+ node.loc.selector.line != node.first_argument.loc.line
158
156
  end
159
157
  end
160
- # rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
158
+ # rubocop:enable Metrics/AbcSize
161
159
 
162
160
  def find_node_for_line(line)
163
161
  processed_source.ast.each_node do |node|
@@ -165,10 +163,6 @@ module RuboCop
165
163
  end
166
164
  end
167
165
 
168
- def allowed_type?(node)
169
- node.and_type? || node.or_type? || (node.if_type? && node.ternary?)
170
- end
171
-
172
166
  def same_line?(node, line)
173
167
  return false unless (source_range = node.source_range)
174
168
 
@@ -53,7 +53,7 @@ module RuboCop
53
53
  return if interpolated_quotes?(node) || allowed_percent_q?(node)
54
54
 
55
55
  add_offense(node) do |corrector|
56
- delimiter = /^%Q[^"]+$|'/.match?(node.source) ? QUOTE : SINGLE_QUOTE
56
+ delimiter = /\A%Q[^"]+\z|'/.match?(node.source) ? QUOTE : SINGLE_QUOTE
57
57
 
58
58
  corrector.replace(node.loc.begin, delimiter)
59
59
  corrector.replace(node.loc.end, delimiter)
@@ -131,7 +131,7 @@ module RuboCop
131
131
  end
132
132
 
133
133
  def in_same_section?(node1, node2)
134
- !node1.source_range.with(end_pos: node2.source_range.end_pos).source.include?("\n\n")
134
+ !node1.source_range.join(node2.source_range.end).source.include?("\n\n")
135
135
  end
136
136
  end
137
137
  end
@@ -174,6 +174,9 @@ module RuboCop
174
174
  end
175
175
 
176
176
  def support_target_rails_version?(cop)
177
+ # In this case, the rails version was already checked by `#excluded_file?`
178
+ return true if defined?(RuboCop::Rails::TargetRailsVersion::USES_REQUIRES_GEM_API)
179
+
177
180
  return true unless cop.class.respond_to?(:support_target_rails_version?)
178
181
 
179
182
  cop.class.support_target_rails_version?(cop.target_rails_version)
@@ -24,14 +24,10 @@ module RuboCop
24
24
  message: message(offense)
25
25
  )
26
26
 
27
- begin
28
- return unless valid_line?(offense)
27
+ return unless valid_line?(offense)
29
28
 
30
- report_line(offense.location)
31
- report_highlighted_area(offense.highlighted_area)
32
- rescue IndexError
33
- # range is not on a valid line; perhaps the source file is empty
34
- end
29
+ report_line(offense.location)
30
+ report_highlighted_area(offense.highlighted_area)
35
31
  end
36
32
 
37
33
  def valid_line?(offense)
@@ -53,14 +53,10 @@ module RuboCop
53
53
  message: message(offense)
54
54
  )
55
55
 
56
- begin
57
- return unless valid_line?(offense)
56
+ return unless valid_line?(offense)
58
57
 
59
- report_line(offense.location)
60
- report_highlighted_area(offense.highlighted_area)
61
- rescue IndexError
62
- # range is not on a valid line; perhaps the source file is empty
63
- end
58
+ report_line(offense.location)
59
+ report_highlighted_area(offense.highlighted_area)
64
60
  end
65
61
 
66
62
  def annotate_message(msg)
@@ -1,18 +1,33 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ begin
4
+ require 'bundler'
5
+ rescue LoadError
6
+ nil
7
+ end
8
+
3
9
  module RuboCop
4
10
  # Encapsulation of a lockfile for use when checking for gems.
5
11
  # Does not actually resolve gems, just parses the lockfile.
6
12
  # @api private
7
13
  class Lockfile
8
- # Gems that the bundle depends on
14
+ # @param [String, Pathname, nil] lockfile_path
15
+ def initialize(lockfile_path = nil)
16
+ lockfile_path ||= defined?(Bundler) ? Bundler.default_lockfile : nil
17
+
18
+ @lockfile_path = lockfile_path
19
+ end
20
+
21
+ # Gems that the bundle directly depends on.
22
+ # @return [Array<Bundler::Dependency>, nil]
9
23
  def dependencies
10
24
  return [] unless parser
11
25
 
12
26
  parser.dependencies.values
13
27
  end
14
28
 
15
- # All activated gems, including transitive dependencies
29
+ # All activated gems, including transitive dependencies.
30
+ # @return [Array<Bundler::Dependency>, nil]
16
31
  def gems
17
32
  return [] unless parser
18
33
 
@@ -21,20 +36,44 @@ module RuboCop
21
36
  parser.dependencies.values.concat(parser.specs.flat_map(&:dependencies))
22
37
  end
23
38
 
39
+ # Returns the locked versions of gems from this lockfile.
40
+ # @param [Boolean] include_transitive_dependencies: When false, only direct dependencies
41
+ # are returned, i.e. those listed explicitly in the `Gemfile`.
42
+ # @returns [Hash{String => Gem::Version}] The locked gem versions, keyed by the gems' names.
43
+ def gem_versions(include_transitive_dependencies: true)
44
+ return {} unless parser
45
+
46
+ all_gem_versions = parser.specs.to_h { |spec| [spec.name, spec.version] }
47
+
48
+ if include_transitive_dependencies
49
+ all_gem_versions
50
+ else
51
+ direct_dep_names = parser.dependencies.keys
52
+ all_gem_versions.slice(*direct_dep_names)
53
+ end
54
+ end
55
+
56
+ # Whether this lockfile includes the named gem, directly or indirectly.
57
+ # @param [String] name
58
+ # @return [Boolean]
24
59
  def includes_gem?(name)
25
60
  gems.any? { |gem| gem.name == name }
26
61
  end
27
62
 
28
63
  private
29
64
 
65
+ # @return [Bundler::LockfileParser, nil]
30
66
  def parser
31
- return unless defined?(Bundler) && Bundler.default_lockfile
32
67
  return @parser if defined?(@parser)
33
68
 
34
- lockfile = Bundler.read_file(Bundler.default_lockfile)
35
- @parser = lockfile ? Bundler::LockfileParser.new(lockfile) : nil
36
- rescue Bundler::BundlerError
37
- nil
69
+ @parser = if defined?(::Bundler) && @lockfile_path
70
+ begin
71
+ lockfile = ::Bundler.read_file(@lockfile_path)
72
+ lockfile ? ::Bundler::LockfileParser.new(lockfile) : nil
73
+ rescue ::Bundler::BundlerError
74
+ nil
75
+ end
76
+ end
38
77
  end
39
78
  end
40
79
  end
@@ -111,6 +111,7 @@ module RuboCop
111
111
  source
112
112
  end
113
113
 
114
+ # rubocop:disable Metrics/AbcSize
114
115
  def expect_offense(source, file = nil, severity: nil, chomp: false, **replacements)
115
116
  expected_annotations = parse_annotations(source, **replacements)
116
117
  source = expected_annotations.plain_source
@@ -123,8 +124,15 @@ module RuboCop
123
124
  expect(actual_annotations).to eq(expected_annotations), ''
124
125
  expect(@offenses.map(&:severity).uniq).to eq([severity]) if severity
125
126
 
127
+ # Validate that all offenses have a range that formatters can display
128
+ expect do
129
+ @offenses.each { |offense| offense.location.source_line }
130
+ end.not_to raise_error, 'One of the offenses has a misconstructed range, for ' \
131
+ 'example if the offense is on line 1 and the source is empty'
132
+
126
133
  @offenses
127
134
  end
135
+ # rubocop:enable Metrics/AbcSize
128
136
 
129
137
  # rubocop:disable Metrics/AbcSize, Metrics/MethodLength, Metrics/CyclomaticComplexity
130
138
  def expect_correction(correction, loop: true, source: nil)
@@ -110,7 +110,19 @@ RSpec.shared_context 'config' do # rubocop:disable Metrics/BlockLength
110
110
  let(:config) do
111
111
  hash = { 'AllCops' => all_cops_config, cop_class.cop_name => cur_cop_config }.merge!(other_cops)
112
112
 
113
- RuboCop::Config.new(hash, "#{Dir.pwd}/.rubocop.yml")
113
+ config = RuboCop::Config.new(hash, "#{Dir.pwd}/.rubocop.yml")
114
+
115
+ rails_version_in_gemfile = Gem::Version.new(
116
+ rails_version || RuboCop::Config::DEFAULT_RAILS_VERSION
117
+ )
118
+
119
+ allow(config).to receive(:gem_versions_in_target).and_return(
120
+ {
121
+ 'railties' => rails_version_in_gemfile
122
+ }
123
+ )
124
+
125
+ config
114
126
  end
115
127
 
116
128
  let(:cop) { cop_class.new(config, cop_options) }
@@ -20,6 +20,9 @@ module RuboCop
20
20
  message = 'Infinite loop detected'
21
21
  message += " in #{path}" if path
22
22
  message += " and caused by #{root_cause}" if root_cause
23
+ message += ' Hint: Please update to the latest RuboCop version if not already in use,'
24
+ message += ' and report a bug if the issue still occurs on this version.'
25
+ message += ' Please check the latest version at https://rubygems.org/gems/rubocop'
23
26
  super(message)
24
27
  end
25
28
  end
@@ -3,7 +3,7 @@
3
3
  module RuboCop
4
4
  # This module holds the RuboCop version information.
5
5
  module Version
6
- STRING = '1.62.1'
6
+ STRING = '1.63.1'
7
7
 
8
8
  MSG = '%<version>s (using %<parser_version>s, ' \
9
9
  'rubocop-ast %<rubocop_ast_version>s, ' \
@@ -11,7 +11,7 @@ module RuboCop
11
11
 
12
12
  CANONICAL_FEATURE_NAMES = {
13
13
  'Rspec' => 'RSpec', 'Graphql' => 'GraphQL', 'Md' => 'Markdown', 'Factory_bot' => 'FactoryBot',
14
- 'Thread_safety' => 'ThreadSafety'
14
+ 'Thread_safety' => 'ThreadSafety', 'Rspec_rails' => 'RSpecRails'
15
15
  }.freeze
16
16
  EXTENSION_PATH_NAMES = {
17
17
  'rubocop-md' => 'markdown', 'rubocop-factory_bot' => 'factory_bot'
data/lib/rubocop.rb CHANGED
@@ -557,6 +557,7 @@ require_relative 'rubocop/cop/style/lambda'
557
557
  require_relative 'rubocop/cop/style/lambda_call'
558
558
  require_relative 'rubocop/cop/style/line_end_concatenation'
559
559
  require_relative 'rubocop/cop/style/magic_comment_format'
560
+ require_relative 'rubocop/cop/style/map_into_array'
560
561
  require_relative 'rubocop/cop/style/map_to_hash'
561
562
  require_relative 'rubocop/cop/style/map_to_set'
562
563
  require_relative 'rubocop/cop/style/method_call_without_args_parentheses'
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rubocop
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.62.1
4
+ version: 1.63.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Bozhidar Batsov
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: exe
12
12
  cert_chain: []
13
- date: 2024-03-11 00:00:00.000000000 Z
13
+ date: 2024-04-10 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: json
@@ -778,6 +778,7 @@ files:
778
778
  - lib/rubocop/cop/style/line_end_concatenation.rb
779
779
  - lib/rubocop/cop/style/magic_comment_format.rb
780
780
  - lib/rubocop/cop/style/map_compact_with_conditional_block.rb
781
+ - lib/rubocop/cop/style/map_into_array.rb
781
782
  - lib/rubocop/cop/style/map_to_hash.rb
782
783
  - lib/rubocop/cop/style/map_to_set.rb
783
784
  - lib/rubocop/cop/style/method_call_with_args_parentheses.rb
@@ -1031,9 +1032,9 @@ licenses:
1031
1032
  - MIT
1032
1033
  metadata:
1033
1034
  homepage_uri: https://rubocop.org/
1034
- changelog_uri: https://github.com/rubocop/rubocop/releases/tag/v1.62.1
1035
+ changelog_uri: https://github.com/rubocop/rubocop/releases/tag/v1.63.1
1035
1036
  source_code_uri: https://github.com/rubocop/rubocop/
1036
- documentation_uri: https://docs.rubocop.org/rubocop/1.62/
1037
+ documentation_uri: https://docs.rubocop.org/rubocop/1.63/
1037
1038
  bug_tracker_uri: https://github.com/rubocop/rubocop/issues
1038
1039
  rubygems_mfa_required: 'true'
1039
1040
  post_install_message: