rubocop 1.63.0 → 1.64.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 (56) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/config/default.yml +18 -3
  4. data/lib/rubocop/cached_data.rb +11 -3
  5. data/lib/rubocop/cli/command/show_docs_url.rb +2 -2
  6. data/lib/rubocop/cli.rb +4 -0
  7. data/lib/rubocop/config.rb +2 -3
  8. data/lib/rubocop/cop/base.rb +9 -14
  9. data/lib/rubocop/cop/bundler/gem_version.rb +3 -5
  10. data/lib/rubocop/cop/documentation.rb +16 -6
  11. data/lib/rubocop/cop/gemspec/dependency_version.rb +3 -5
  12. data/lib/rubocop/cop/internal_affairs/example_description.rb +1 -1
  13. data/lib/rubocop/cop/layout/comment_indentation.rb +1 -1
  14. data/lib/rubocop/cop/layout/empty_comment.rb +3 -1
  15. data/lib/rubocop/cop/layout/first_array_element_indentation.rb +2 -0
  16. data/lib/rubocop/cop/lint/assignment_in_condition.rb +3 -1
  17. data/lib/rubocop/cop/lint/deprecated_class_methods.rb +1 -1
  18. data/lib/rubocop/cop/lint/empty_conditional_body.rb +1 -1
  19. data/lib/rubocop/cop/lint/mixed_case_range.rb +9 -4
  20. data/lib/rubocop/cop/lint/non_deterministic_require_order.rb +1 -1
  21. data/lib/rubocop/cop/lint/unreachable_code.rb +4 -2
  22. data/lib/rubocop/cop/lint/unreachable_loop.rb +8 -2
  23. data/lib/rubocop/cop/metrics/utils/code_length_calculator.rb +5 -5
  24. data/lib/rubocop/cop/mixin/hash_shorthand_syntax.rb +9 -2
  25. data/lib/rubocop/cop/security/compound_hash.rb +2 -2
  26. data/lib/rubocop/cop/style/access_modifier_declarations.rb +50 -0
  27. data/lib/rubocop/cop/style/arguments_forwarding.rb +5 -2
  28. data/lib/rubocop/cop/style/conditional_assignment.rb +1 -1
  29. data/lib/rubocop/cop/style/copyright.rb +10 -8
  30. data/lib/rubocop/cop/style/documentation_method.rb +20 -0
  31. data/lib/rubocop/cop/style/eval_with_location.rb +1 -1
  32. data/lib/rubocop/cop/style/hash_syntax.rb +18 -0
  33. data/lib/rubocop/cop/style/if_with_boolean_literal_branches.rb +5 -3
  34. data/lib/rubocop/cop/style/map_into_array.rb +3 -3
  35. data/lib/rubocop/cop/style/numeric_predicate.rb +10 -2
  36. data/lib/rubocop/cop/style/one_line_conditional.rb +1 -1
  37. data/lib/rubocop/cop/style/redundant_line_continuation.rb +3 -1
  38. data/lib/rubocop/cop/style/require_order.rb +1 -1
  39. data/lib/rubocop/cop/style/send.rb +4 -4
  40. data/lib/rubocop/cop/style/send_with_literal_method_name.rb +83 -0
  41. data/lib/rubocop/cop/style/special_global_vars.rb +1 -2
  42. data/lib/rubocop/cop/style/super_arguments.rb +137 -0
  43. data/lib/rubocop/cop/style/symbol_proc.rb +32 -5
  44. data/lib/rubocop/cop/style/top_level_method_definition.rb +1 -1
  45. data/lib/rubocop/formatter/disabled_config_formatter.rb +13 -9
  46. data/lib/rubocop/formatter/formatter_set.rb +7 -1
  47. data/lib/rubocop/lockfile.rb +25 -6
  48. data/lib/rubocop/lsp/routes.rb +9 -12
  49. data/lib/rubocop/lsp/server.rb +2 -0
  50. data/lib/rubocop/lsp.rb +9 -2
  51. data/lib/rubocop/options.rb +3 -3
  52. data/lib/rubocop/rake_task.rb +1 -1
  53. data/lib/rubocop/runner.rb +5 -4
  54. data/lib/rubocop/version.rb +4 -4
  55. data/lib/rubocop.rb +2 -0
  56. metadata +6 -4
@@ -61,7 +61,7 @@ module RuboCop
61
61
  raise Warning, AUTOCORRECT_EMPTY_WARNING if autocorrect_notice.empty?
62
62
 
63
63
  regex = Regexp.new(notice)
64
- return if autocorrect_notice&.match?(regex)
64
+ return if autocorrect_notice.gsub(/^# */, '').match?(regex)
65
65
 
66
66
  raise Warning, "AutocorrectNotice '#{autocorrect_notice}' must match Notice /#{notice}/"
67
67
  end
@@ -77,26 +77,28 @@ module RuboCop
77
77
  return false if token_index >= processed_source.tokens.size
78
78
 
79
79
  token = processed_source.tokens[token_index]
80
- token.comment? && /^#!.*$/.match?(token.text)
80
+ token.comment? && /\A#!.*\z/.match?(token.text)
81
81
  end
82
82
 
83
83
  def encoding_token?(processed_source, token_index)
84
84
  return false if token_index >= processed_source.tokens.size
85
85
 
86
86
  token = processed_source.tokens[token_index]
87
- token.comment? && /^#.*coding\s?[:=]\s?(?:UTF|utf)-8/.match?(token.text)
87
+ token.comment? && /\A#.*coding\s?[:=]\s?(?:UTF|utf)-8/.match?(token.text)
88
88
  end
89
89
 
90
90
  def notice_found?(processed_source)
91
- notice_found = false
92
- notice_regexp = Regexp.new(notice)
91
+ notice_regexp = Regexp.new(notice.lines.map(&:strip).join)
92
+ multiline_notice = +''
93
93
  processed_source.tokens.each do |token|
94
94
  break unless token.comment?
95
95
 
96
- notice_found = notice_regexp.match?(token.text)
97
- break if notice_found
96
+ multiline_notice << token.text.sub(/\A# */, '')
97
+
98
+ break if notice_regexp.match?(token.text)
98
99
  end
99
- notice_found
100
+
101
+ multiline_notice.match?(notice_regexp)
100
102
  end
101
103
  end
102
104
  end
@@ -95,6 +95,17 @@ module RuboCop
95
95
  # end
96
96
  # end
97
97
  #
98
+ # @example AllowedMethods: ['method_missing', 'respond_to_missing?']
99
+ #
100
+ # # good
101
+ # class Foo
102
+ # def method_missing(name, *args)
103
+ # end
104
+ #
105
+ # def respond_to_missing?(symbol, include_private)
106
+ # end
107
+ # end
108
+ #
98
109
  class DocumentationMethod < Base
99
110
  include DocumentationComment
100
111
  include DefNode
@@ -119,6 +130,7 @@ module RuboCop
119
130
  def check(node)
120
131
  return if non_public?(node) && !require_for_non_public_methods?
121
132
  return if documentation_comment?(node)
133
+ return if method_allowed?(node)
122
134
 
123
135
  add_offense(node)
124
136
  end
@@ -126,6 +138,14 @@ module RuboCop
126
138
  def require_for_non_public_methods?
127
139
  cop_config['RequireForNonPublicMethods']
128
140
  end
141
+
142
+ def method_allowed?(node)
143
+ allowed_methods.include?(node.method_name)
144
+ end
145
+
146
+ def allowed_methods
147
+ @allowed_methods ||= cop_config.fetch('AllowedMethods', []).map(&:to_sym)
148
+ end
129
149
  end
130
150
  end
131
151
  end
@@ -141,7 +141,7 @@ module RuboCop
141
141
  end
142
142
 
143
143
  def check_file(node, file_node)
144
- return true if special_file_keyword?(file_node)
144
+ return if special_file_keyword?(file_node)
145
145
 
146
146
  message = format(MSG_INCORRECT_FILE,
147
147
  method_name: node.method_name,
@@ -29,6 +29,8 @@ module RuboCop
29
29
  # * never - forces use of explicit hash literal value
30
30
  # * either - accepts both shorthand and explicit use of hash literal value
31
31
  # * consistent - forces use of the 3.1 syntax only if all values can be omitted in the hash
32
+ # * either_consistent - accepts both shorthand and explicit use of hash literal value,
33
+ # but they must be consistent
32
34
  #
33
35
  # @example EnforcedStyle: ruby19 (default)
34
36
  # # bad
@@ -110,6 +112,22 @@ module RuboCop
110
112
  # # good - can't omit `baz`
111
113
  # {foo: foo, bar: baz}
112
114
  #
115
+ # @example EnforcedShorthandSyntax: either_consistent
116
+ #
117
+ # # good - `foo` and `bar` values can be omitted, but they are consistent, so it's accepted
118
+ # {foo: foo, bar: bar}
119
+ #
120
+ # # bad - `bar` value can be omitted
121
+ # {foo:, bar: bar}
122
+ #
123
+ # # bad - mixed syntaxes
124
+ # {foo:, bar: baz}
125
+ #
126
+ # # good
127
+ # {foo:, bar:}
128
+ #
129
+ # # good - can't omit `baz`
130
+ # {foo: foo, bar: baz}
113
131
  class HashSyntax < Base
114
132
  include ConfigurableEnforcedStyle
115
133
  include HashShorthandSyntax
@@ -112,9 +112,11 @@ module RuboCop
112
112
  end
113
113
 
114
114
  def message(node, keyword)
115
- message_template = node.elsif? ? MSG_FOR_ELSIF : MSG
116
-
117
- format(message_template, keyword: keyword)
115
+ if node.elsif?
116
+ MSG_FOR_ELSIF
117
+ else
118
+ format(MSG, keyword: keyword)
119
+ end
118
120
  end
119
121
 
120
122
  def return_boolean_value?(condition)
@@ -20,8 +20,8 @@ module RuboCop
20
20
  #
21
21
  # [source,ruby]
22
22
  # ----
23
- # @dest = []
24
- # src.each { |e| @dest << e * 2 } # `src` method may mutate `@dest`
23
+ # ret = []
24
+ # src.each { |e| ret << e * 2 } # `<<` method may mutate `ret`
25
25
  #
26
26
  # dest = []
27
27
  # src.each { |e| dest << transform(e, dest) } # `transform` method may mutate `dest`
@@ -57,7 +57,7 @@ module RuboCop
57
57
  def_node_matcher :each_block_with_push?, <<-PATTERN
58
58
  [
59
59
  ^({begin kwbegin} ...)
60
- ({block numblock} (send _ :each) _
60
+ ({block numblock} (send !{nil? self} :each) _
61
61
  (send (lvar _) {:<< :push :append} _))
62
62
  ]
63
63
  PATTERN
@@ -118,12 +118,14 @@ module RuboCop
118
118
 
119
119
  return unless numeric && operator && replacement_supported?(operator)
120
120
 
121
- [numeric, replacement(numeric, operator)]
121
+ [numeric, replacement(node, numeric, operator)]
122
122
  end
123
123
 
124
- def replacement(numeric, operation)
124
+ def replacement(node, numeric, operation)
125
125
  if style == :predicate
126
126
  [parenthesized_source(numeric), REPLACEMENTS.invert[operation.to_s]].join('.')
127
+ elsif negated?(node)
128
+ "(#{numeric.source} #{REPLACEMENTS[operation.to_s]} 0)"
127
129
  else
128
130
  [numeric.source, REPLACEMENTS[operation.to_s], 0].join(' ')
129
131
  end
@@ -157,6 +159,12 @@ module RuboCop
157
159
  end
158
160
  end
159
161
 
162
+ def negated?(node)
163
+ return false unless (parent = node.parent)
164
+
165
+ parent.send_type? && parent.method?(:!)
166
+ end
167
+
160
168
  # @!method predicate(node)
161
169
  def_node_matcher :predicate, <<~PATTERN
162
170
  (send $(...) ${:zero? :positive? :negative?})
@@ -75,7 +75,7 @@ module RuboCop
75
75
  end
76
76
 
77
77
  def always_multiline?
78
- @config.for_cop('Style/OneLineConditional')['AlwaysCorrectToMultiline']
78
+ cop_config['AlwaysCorrectToMultiline']
79
79
  end
80
80
 
81
81
  def cannot_replace_to_ternary?(node)
@@ -137,7 +137,9 @@ module RuboCop
137
137
  # do_something \
138
138
  # argument
139
139
  def method_with_argument?(current_token, next_token)
140
- current_token.type == :tIDENTIFIER && ARGUMENT_TYPES.include?(next_token.type)
140
+ return false if current_token.type != :tIDENTIFIER && current_token.type != :kRETURN
141
+
142
+ ARGUMENT_TYPES.include?(next_token.type)
141
143
  end
142
144
 
143
145
  # rubocop:disable Metrics/AbcSize
@@ -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
@@ -7,12 +7,12 @@ module RuboCop
7
7
  #
8
8
  # @example
9
9
  # # bad
10
- # Foo.send(:bar)
11
- # quuz.send(:fred)
10
+ # Foo.send(bar)
11
+ # quuz.send(fred)
12
12
  #
13
13
  # # good
14
- # Foo.__send__(:bar)
15
- # quuz.public_send(:fred)
14
+ # Foo.__send__(bar)
15
+ # quuz.public_send(fred)
16
16
  class Send < Base
17
17
  MSG = 'Prefer `Object#__send__` or `Object#public_send` to `send`.'
18
18
  RESTRICT_ON_SEND = %i[send].freeze
@@ -0,0 +1,83 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Style
6
+ # Detects the use of the `public_send` method with a literal method name argument.
7
+ # Since the `send` method can be used to call private methods, by default,
8
+ # only the `public_send` method is detected.
9
+ #
10
+ # @safety
11
+ # This cop is not safe because it can incorrectly detect based on the receiver.
12
+ # Additionally, when `AllowSend` is set to `true`, it cannot determine whether
13
+ # the `send` method being detected is calling a private method.
14
+ #
15
+ # @example
16
+ # # bad
17
+ # obj.public_send(:method_name)
18
+ # obj.public_send('method_name')
19
+ #
20
+ # # good
21
+ # obj.method_name
22
+ #
23
+ # @example AllowSend: true (default)
24
+ # # good
25
+ # obj.send(:method_name)
26
+ # obj.send('method_name')
27
+ # obj.__send__(:method_name)
28
+ # obj.__send__('method_name')
29
+ #
30
+ # @example AllowSend: false
31
+ # # bad
32
+ # obj.send(:method_name)
33
+ # obj.send('method_name')
34
+ # obj.__send__(:method_name)
35
+ # obj.__send__('method_name')
36
+ #
37
+ # # good
38
+ # obj.method_name
39
+ #
40
+ class SendWithLiteralMethodName < Base
41
+ extend AutoCorrector
42
+
43
+ MSG = 'Use `%<method_name>s` method call directly instead.'
44
+ RESTRICT_ON_SEND = %i[public_send send __send__].freeze
45
+ STATIC_METHOD_NAME_NODE_TYPES = %i[sym str].freeze
46
+
47
+ # rubocop:disable Metrics/AbcSize
48
+ def on_send(node)
49
+ return if allow_send? && !node.method?(:public_send)
50
+ return unless (first_argument = node.first_argument)
51
+ return unless STATIC_METHOD_NAME_NODE_TYPES.include?(first_argument.type)
52
+
53
+ offense_range = offense_range(node)
54
+ method_name = first_argument.value
55
+
56
+ add_offense(offense_range, message: format(MSG, method_name: method_name)) do |corrector|
57
+ if node.arguments.one?
58
+ corrector.replace(offense_range, method_name)
59
+ else
60
+ corrector.replace(node.loc.selector, method_name)
61
+ corrector.remove(removal_argument_range(first_argument, node.arguments[1]))
62
+ end
63
+ end
64
+ end
65
+ # rubocop:enable Metrics/AbcSize
66
+
67
+ private
68
+
69
+ def allow_send?
70
+ !!cop_config['AllowSend']
71
+ end
72
+
73
+ def offense_range(node)
74
+ node.loc.selector.join(node.source_range.end)
75
+ end
76
+
77
+ def removal_argument_range(first_argument, second_argument)
78
+ first_argument.source_range.begin.join(second_argument.source_range.begin)
79
+ end
80
+ end
81
+ end
82
+ end
83
+ end
@@ -58,9 +58,8 @@ module RuboCop
58
58
  #
59
59
  # @example EnforcedStyle: use_builtin_english_names
60
60
  #
61
- # Like `use_perl_names` but allows builtin global vars.
62
- #
63
61
  # # good
62
+ # # Like `use_perl_names` but allows builtin global vars.
64
63
  # puts $LOAD_PATH
65
64
  # puts $LOADED_FEATURES
66
65
  # puts $PROGRAM_NAME
@@ -0,0 +1,137 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Style
6
+ # Checks for redundant argument forwarding when calling super
7
+ # with arguments identical to the method definition.
8
+ #
9
+ # @example
10
+ # # bad
11
+ # def method(*args, **kwargs)
12
+ # super(*args, **kwargs)
13
+ # end
14
+ #
15
+ # # good - implicitly passing all arguments
16
+ # def method(*args, **kwargs)
17
+ # super
18
+ # end
19
+ #
20
+ # # good - forwarding a subset of the arguments
21
+ # def method(*args, **kwargs)
22
+ # super(*args)
23
+ # end
24
+ #
25
+ # # good - forwarding no arguments
26
+ # def method(*args, **kwargs)
27
+ # super()
28
+ # end
29
+ class SuperArguments < Base
30
+ extend AutoCorrector
31
+
32
+ DEF_TYPES = %i[def defs].freeze
33
+
34
+ MSG = 'Call `super` without arguments and parentheses when the signature is identical.'
35
+
36
+ def on_super(super_node)
37
+ def_node = super_node.ancestors.find do |node|
38
+ # You can't implicitly call super when dynamically defining methods
39
+ break if define_method?(node)
40
+
41
+ break node if DEF_TYPES.include?(node.type)
42
+ end
43
+ return unless def_node
44
+ return unless arguments_identical?(def_node.arguments.argument_list, super_node.arguments)
45
+
46
+ add_offense(super_node) { |corrector| corrector.replace(super_node, 'super') }
47
+ end
48
+
49
+ private
50
+
51
+ # rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
52
+ def arguments_identical?(def_args, super_args)
53
+ super_args = preprocess_super_args(super_args)
54
+ return false if def_args.size != super_args.size
55
+
56
+ def_args.zip(super_args).each do |def_arg, super_arg|
57
+ next if positional_arg_same?(def_arg, super_arg)
58
+ next if positional_rest_arg_same(def_arg, super_arg)
59
+ next if keyword_arg_same?(def_arg, super_arg)
60
+ next if keyword_rest_arg_same?(def_arg, super_arg)
61
+ next if block_arg_same?(def_arg, super_arg)
62
+ next if forward_arg_same?(def_arg, super_arg)
63
+
64
+ return false
65
+ end
66
+ true
67
+ end
68
+ # rubocop:enable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
69
+
70
+ def positional_arg_same?(def_arg, super_arg)
71
+ return false unless def_arg.arg_type? || def_arg.optarg_type?
72
+ return false unless super_arg.lvar_type?
73
+
74
+ def_arg.name == super_arg.children.first
75
+ end
76
+
77
+ def positional_rest_arg_same(def_arg, super_arg)
78
+ return false unless def_arg.restarg_type?
79
+ # anonymous forwarding
80
+ return true if def_arg.name.nil? && super_arg.forwarded_restarg_type?
81
+ return false unless super_arg.splat_type?
82
+ return false unless (lvar_node = super_arg.children.first).lvar_type?
83
+
84
+ def_arg.name == lvar_node.children.first
85
+ end
86
+
87
+ def keyword_arg_same?(def_arg, super_arg)
88
+ return false unless def_arg.kwarg_type? || def_arg.kwoptarg_type?
89
+ return false unless (pair_node = super_arg).pair_type?
90
+ return false unless (sym_node = pair_node.key).sym_type?
91
+ return false unless (lvar_node = pair_node.value).lvar_type?
92
+ return false unless sym_node.source == lvar_node.source
93
+
94
+ def_arg.name == sym_node.value
95
+ end
96
+
97
+ def keyword_rest_arg_same?(def_arg, super_arg)
98
+ return false unless def_arg.kwrestarg_type?
99
+ # anonymous forwarding
100
+ return true if def_arg.name.nil? && super_arg.forwarded_kwrestarg_type?
101
+ return false unless super_arg.kwsplat_type?
102
+ return false unless (lvar_node = super_arg.children.first).lvar_type?
103
+
104
+ def_arg.name == lvar_node.children.first
105
+ end
106
+
107
+ def block_arg_same?(def_arg, super_arg)
108
+ return false unless def_arg.blockarg_type? && super_arg.block_pass_type?
109
+ # anonymous forwarding
110
+ return true if (block_pass_child = super_arg.children.first).nil? && def_arg.name.nil?
111
+
112
+ def_arg.name == block_pass_child.children.first
113
+ end
114
+
115
+ def forward_arg_same?(def_arg, super_arg)
116
+ def_arg.forward_arg_type? && super_arg.forwarded_args_type?
117
+ end
118
+
119
+ def define_method?(node)
120
+ return false unless node.block_type?
121
+
122
+ node.method?(:define_method) || node.method?(:define_singleton_method)
123
+ end
124
+
125
+ def preprocess_super_args(super_args)
126
+ super_args.flat_map do |node|
127
+ if node.hash_type? && !node.braces?
128
+ node.children
129
+ else
130
+ node
131
+ end
132
+ end
133
+ end
134
+ end
135
+ end
136
+ end
137
+ end
@@ -120,6 +120,23 @@ module RuboCop
120
120
  # # good
121
121
  # something.map { |s| s.upcase }
122
122
  #
123
+ # @example AllCops:ActiveSupportExtensionsEnabled: false (default)
124
+ # # bad
125
+ # ->(x) { x.foo }
126
+ # proc { |x| x.foo }
127
+ # Proc.new { |x| x.foo }
128
+ #
129
+ # # good
130
+ # lambda(&:foo)
131
+ # proc(&:foo)
132
+ # Proc.new(&:foo)
133
+ #
134
+ # @example AllCops:ActiveSupportExtensionsEnabled: true
135
+ # # good
136
+ # ->(x) { x.foo }
137
+ # proc { |x| x.foo }
138
+ # Proc.new { |x| x.foo }
139
+ #
123
140
  class SymbolProc < Base
124
141
  include CommentsHelp
125
142
  include RangeHelp
@@ -129,6 +146,7 @@ module RuboCop
129
146
 
130
147
  MSG = 'Pass `&:%<method>s` as an argument to `%<block_method>s` instead of a block.'
131
148
  SUPER_TYPES = %i[super zsuper].freeze
149
+ LAMBDA_OR_PROC = %i[lambda proc].freeze
132
150
 
133
151
  # @!method proc_node?(node)
134
152
  def_node_matcher :proc_node?, '(send (const {nil? cbase} :Proc) :new)'
@@ -151,13 +169,12 @@ module RuboCop
151
169
  # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
152
170
  def on_block(node)
153
171
  symbol_proc?(node) do |dispatch_node, arguments_node, method_name|
154
- # TODO: Rails-specific handling that we should probably make
155
- # configurable - https://github.com/rubocop/rubocop/issues/1485
156
- # we should allow lambdas & procs
157
- return if proc_node?(dispatch_node)
172
+ if active_support_extensions_enabled?
173
+ return if proc_node?(dispatch_node)
174
+ return if LAMBDA_OR_PROC.include?(dispatch_node.method_name)
175
+ end
158
176
  return if unsafe_hash_usage?(dispatch_node)
159
177
  return if unsafe_array_usage?(dispatch_node)
160
- return if %i[lambda proc].include?(dispatch_node.method_name)
161
178
  return if allowed_method_name?(dispatch_node.method_name)
162
179
  return if allow_if_method_has_argument?(node.send_node)
163
180
  return if node.block_type? && destructuring_block_argument?(arguments_node)
@@ -206,6 +223,8 @@ module RuboCop
206
223
  end
207
224
 
208
225
  def autocorrect_without_args(corrector, node)
226
+ autocorrect_lambda_block(corrector, node) if node.send_node.lambda_literal?
227
+
209
228
  corrector.replace(block_range_with_space(node), "(&:#{node.body.method_name})")
210
229
  end
211
230
 
@@ -218,6 +237,14 @@ module RuboCop
218
237
  corrector.remove(block_range_with_space(node))
219
238
  end
220
239
 
240
+ def autocorrect_lambda_block(corrector, node)
241
+ send_node_loc = node.send_node.loc
242
+ corrector.replace(send_node_loc.selector, 'lambda')
243
+
244
+ range = range_between(send_node_loc.selector.end_pos, node.loc.begin.end_pos - 2)
245
+ corrector.remove(range)
246
+ end
247
+
221
248
  def block_range_with_space(node)
222
249
  block_range = range_between(begin_pos_for_replacement(node), node.loc.end.end_pos)
223
250
  range_with_surrounding_space(block_range, side: :left)
@@ -77,7 +77,7 @@ module RuboCop
77
77
 
78
78
  # @!method define_method_block?(node)
79
79
  def_node_matcher :define_method_block?, <<~PATTERN
80
- ({block numblock} (send _ {:define_method} _) ...)
80
+ ({block numblock} (send _ :define_method _) ...)
81
81
  PATTERN
82
82
  end
83
83
  end
@@ -116,20 +116,24 @@ module RuboCop
116
116
  def set_max(cfg, cop_name)
117
117
  return unless cfg[:exclude_limit]
118
118
 
119
- max_set_in_user_config =
120
- @config_for_pwd.for_cop(cop_name)['Max'] != default_config(cop_name)['Max']
121
- if !max_set_in_user_config &&
122
- # In case auto_gen_only_exclude is set, only modify the maximum if the files are not
123
- # excluded one by one.
124
- (!@options[:auto_gen_only_exclude] ||
125
- @files_with_offenses[cop_name].size > @exclude_limit)
126
- cfg.merge!(cfg[:exclude_limit])
127
- end
119
+ cfg.merge!(cfg[:exclude_limit]) if should_set_max?(cop_name)
128
120
 
129
121
  # Remove already used exclude_limit.
130
122
  cfg.reject! { |key| key == :exclude_limit }
131
123
  end
132
124
 
125
+ def should_set_max?(cop_name)
126
+ max_set_in_user_config =
127
+ @config_for_pwd.for_cop(cop_name)['Max'] != default_config(cop_name)['Max']
128
+
129
+ max_allowed = !max_set_in_user_config && !no_exclude_limit?
130
+ return false unless max_allowed
131
+
132
+ # In case auto_gen_only_exclude is set, only modify the maximum if the files are not
133
+ # excluded one by one.
134
+ !@options[:auto_gen_only_exclude] || @files_with_offenses[cop_name].size > @exclude_limit
135
+ end
136
+
133
137
  def output_cop_comments(output_buffer, cfg, cop_name, offense_count)
134
138
  output_buffer.puts "# Offense count: #{offense_count}" if show_offense_counts?
135
139
 
@@ -27,6 +27,7 @@ module RuboCop
27
27
  '[t]ap' => 'TapFormatter',
28
28
  '[w]orst' => 'WorstOffendersFormatter'
29
29
  }.freeze
30
+ BUILTIN_FORMATTER_NAMES = BUILTIN_FORMATTERS_FOR_KEYS.keys.map { |key| key.delete('[]') }
30
31
 
31
32
  FORMATTER_APIS = %i[started finished].freeze
32
33
 
@@ -88,7 +89,12 @@ module RuboCop
88
89
  /^\[#{specified_key}\]/.match?(key) || specified_key == key.delete('[]')
89
90
  end
90
91
 
91
- raise %(No formatter for "#{specified_key}") if matching_keys.empty?
92
+ if matching_keys.empty?
93
+ similar_name = NameSimilarity.find_similar_name(specified_key, BUILTIN_FORMATTER_NAMES)
94
+ suggestion = %( Did you mean? "#{similar_name}") if similar_name
95
+
96
+ raise Rainbow(%(Formatter "#{specified_key}" not found.#{suggestion})).red
97
+ end
92
98
 
93
99
  raise %(Cannot determine formatter for "#{specified_key}") if matching_keys.size > 1
94
100
 
@@ -1,5 +1,13 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ begin
4
+ # We might not be running with `bundle exec`, so we need to pull in Bundler ourselves,
5
+ # in order to use `Bundler::LockfileParser`.
6
+ require 'bundler'
7
+ rescue LoadError
8
+ nil
9
+ end
10
+
3
11
  module RuboCop
4
12
  # Encapsulation of a lockfile for use when checking for gems.
5
13
  # Does not actually resolve gems, just parses the lockfile.
@@ -7,7 +15,11 @@ module RuboCop
7
15
  class Lockfile
8
16
  # @param [String, Pathname, nil] lockfile_path
9
17
  def initialize(lockfile_path = nil)
10
- lockfile_path ||= defined?(Bundler) ? Bundler.default_lockfile : nil
18
+ lockfile_path ||= begin
19
+ ::Bundler.default_lockfile if bundler_lock_parser_defined?
20
+ rescue ::Bundler::GemfileNotFound
21
+ nil # We might not be a folder with a Gemfile, but that's okay.
22
+ end
11
23
 
12
24
  @lockfile_path = lockfile_path
13
25
  end
@@ -59,12 +71,19 @@ module RuboCop
59
71
  # @return [Bundler::LockfileParser, nil]
60
72
  def parser
61
73
  return @parser if defined?(@parser)
62
- return unless @lockfile_path
63
74
 
64
- lockfile = Bundler.read_file(@lockfile_path)
65
- @parser = lockfile ? Bundler::LockfileParser.new(lockfile) : nil
66
- rescue Bundler::BundlerError
67
- nil
75
+ @parser = if @lockfile_path && File.exist?(@lockfile_path) && bundler_lock_parser_defined?
76
+ begin
77
+ lockfile = ::Bundler.read_file(@lockfile_path)
78
+ ::Bundler::LockfileParser.new(lockfile) if lockfile
79
+ rescue ::Bundler::BundlerError
80
+ nil
81
+ end
82
+ end
83
+ end
84
+
85
+ def bundler_lock_parser_defined?
86
+ Object.const_defined?(:Bundler) && Bundler.const_defined?(:LockfileParser)
68
87
  end
69
88
  end
70
89
  end