rubocop 1.5.2 → 1.8.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (113) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE.txt +1 -1
  3. data/README.md +3 -2
  4. data/config/default.yml +112 -16
  5. data/config/obsoletion.yml +196 -0
  6. data/lib/rubocop.rb +20 -1
  7. data/lib/rubocop/cli/command/suggest_extensions.rb +16 -44
  8. data/lib/rubocop/comment_config.rb +6 -6
  9. data/lib/rubocop/config.rb +8 -5
  10. data/lib/rubocop/config_loader.rb +11 -7
  11. data/lib/rubocop/config_loader_resolver.rb +21 -4
  12. data/lib/rubocop/config_obsoletion.rb +64 -262
  13. data/lib/rubocop/config_obsoletion/changed_enforced_styles.rb +33 -0
  14. data/lib/rubocop/config_obsoletion/changed_parameter.rb +21 -0
  15. data/lib/rubocop/config_obsoletion/cop_rule.rb +34 -0
  16. data/lib/rubocop/config_obsoletion/extracted_cop.rb +44 -0
  17. data/lib/rubocop/config_obsoletion/parameter_rule.rb +44 -0
  18. data/lib/rubocop/config_obsoletion/removed_cop.rb +41 -0
  19. data/lib/rubocop/config_obsoletion/renamed_cop.rb +34 -0
  20. data/lib/rubocop/config_obsoletion/rule.rb +41 -0
  21. data/lib/rubocop/config_obsoletion/split_cop.rb +27 -0
  22. data/lib/rubocop/config_validator.rb +11 -4
  23. data/lib/rubocop/cop/base.rb +17 -15
  24. data/lib/rubocop/cop/cop.rb +2 -2
  25. data/lib/rubocop/cop/correctors/string_literal_corrector.rb +6 -8
  26. data/lib/rubocop/cop/gemspec/required_ruby_version.rb +3 -2
  27. data/lib/rubocop/cop/internal_affairs.rb +1 -0
  28. data/lib/rubocop/cop/internal_affairs/style_detected_api_use.rb +145 -0
  29. data/lib/rubocop/cop/layout/empty_line_between_defs.rb +19 -3
  30. data/lib/rubocop/cop/layout/empty_lines_around_attribute_accessor.rb +1 -1
  31. data/lib/rubocop/cop/layout/heredoc_argument_closing_parenthesis.rb +14 -0
  32. data/lib/rubocop/cop/layout/line_length.rb +6 -16
  33. data/lib/rubocop/cop/layout/multiline_operation_indentation.rb +2 -2
  34. data/lib/rubocop/cop/layout/rescue_ensure_alignment.rb +3 -10
  35. data/lib/rubocop/cop/layout/space_around_equals_in_parameter_default.rb +1 -0
  36. data/lib/rubocop/cop/layout/space_before_block_braces.rb +2 -0
  37. data/lib/rubocop/cop/layout/space_before_brackets.rb +62 -0
  38. data/lib/rubocop/cop/layout/space_inside_block_braces.rb +13 -10
  39. data/lib/rubocop/cop/layout/space_inside_hash_literal_braces.rb +2 -2
  40. data/lib/rubocop/cop/lint/ambiguous_assignment.rb +59 -0
  41. data/lib/rubocop/cop/lint/binary_operator_with_identical_operands.rb +7 -2
  42. data/lib/rubocop/cop/lint/deprecated_constants.rb +75 -0
  43. data/lib/rubocop/cop/lint/duplicate_branch.rb +64 -2
  44. data/lib/rubocop/cop/lint/lambda_without_literal_block.rb +44 -0
  45. data/lib/rubocop/cop/lint/non_deterministic_require_order.rb +10 -6
  46. data/lib/rubocop/cop/lint/redundant_cop_disable_directive.rb +2 -1
  47. data/lib/rubocop/cop/lint/redundant_dir_glob_sort.rb +50 -0
  48. data/lib/rubocop/cop/lint/redundant_splat_expansion.rb +50 -17
  49. data/lib/rubocop/cop/lint/shadowed_exception.rb +1 -11
  50. data/lib/rubocop/cop/lint/unreachable_loop.rb +17 -0
  51. data/lib/rubocop/cop/metrics/utils/code_length_calculator.rb +1 -1
  52. data/lib/rubocop/cop/migration/department_name.rb +1 -1
  53. data/lib/rubocop/cop/mixin/allowed_identifiers.rb +18 -0
  54. data/lib/rubocop/cop/mixin/comments_help.rb +1 -10
  55. data/lib/rubocop/cop/mixin/first_element_line_break.rb +1 -1
  56. data/lib/rubocop/cop/mixin/string_help.rb +4 -1
  57. data/lib/rubocop/cop/mixin/uncommunicative_name.rb +5 -1
  58. data/lib/rubocop/cop/naming/accessor_method_name.rb +15 -1
  59. data/lib/rubocop/cop/naming/memoized_instance_variable_name.rb +59 -5
  60. data/lib/rubocop/cop/naming/variable_name.rb +2 -0
  61. data/lib/rubocop/cop/naming/variable_number.rb +1 -8
  62. data/lib/rubocop/cop/registry.rb +10 -0
  63. data/lib/rubocop/cop/style/access_modifier_declarations.rb +3 -1
  64. data/lib/rubocop/cop/style/character_literal.rb +10 -11
  65. data/lib/rubocop/cop/style/collection_methods.rb +14 -1
  66. data/lib/rubocop/cop/style/commented_keyword.rb +22 -5
  67. data/lib/rubocop/cop/style/empty_literal.rb +6 -2
  68. data/lib/rubocop/cop/style/endless_method.rb +102 -0
  69. data/lib/rubocop/cop/style/explicit_block_argument.rb +10 -0
  70. data/lib/rubocop/cop/style/float_division.rb +44 -1
  71. data/lib/rubocop/cop/style/for.rb +2 -0
  72. data/lib/rubocop/cop/style/hash_except.rb +95 -0
  73. data/lib/rubocop/cop/style/hash_like_case.rb +2 -1
  74. data/lib/rubocop/cop/style/if_inside_else.rb +8 -3
  75. data/lib/rubocop/cop/style/if_unless_modifier.rb +4 -0
  76. data/lib/rubocop/cop/style/ip_addresses.rb +1 -1
  77. data/lib/rubocop/cop/style/keyword_parameters_order.rb +12 -2
  78. data/lib/rubocop/cop/style/lambda_call.rb +2 -1
  79. data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +7 -0
  80. data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +16 -6
  81. data/lib/rubocop/cop/style/method_def_parentheses.rb +7 -0
  82. data/lib/rubocop/cop/style/multiline_method_signature.rb +26 -1
  83. data/lib/rubocop/cop/style/multiline_when_then.rb +3 -1
  84. data/lib/rubocop/cop/style/mutable_constant.rb +13 -3
  85. data/lib/rubocop/cop/style/nested_parenthesized_calls.rb +4 -0
  86. data/lib/rubocop/cop/style/perl_backrefs.rb +86 -9
  87. data/lib/rubocop/cop/style/raise_args.rb +5 -2
  88. data/lib/rubocop/cop/style/redundant_argument.rb +21 -2
  89. data/lib/rubocop/cop/style/redundant_freeze.rb +8 -4
  90. data/lib/rubocop/cop/style/redundant_return.rb +1 -1
  91. data/lib/rubocop/cop/style/single_line_block_params.rb +30 -7
  92. data/lib/rubocop/cop/style/single_line_methods.rb +34 -2
  93. data/lib/rubocop/cop/style/sole_nested_conditional.rb +15 -9
  94. data/lib/rubocop/cop/style/special_global_vars.rb +1 -13
  95. data/lib/rubocop/cop/style/string_concatenation.rb +20 -1
  96. data/lib/rubocop/cop/style/string_literals.rb +14 -8
  97. data/lib/rubocop/cop/style/string_literals_in_interpolation.rb +4 -3
  98. data/lib/rubocop/cop/style/symbol_proc.rb +5 -4
  99. data/lib/rubocop/cop/style/while_until_modifier.rb +2 -4
  100. data/lib/rubocop/cop/util.rb +3 -1
  101. data/lib/rubocop/formatter/emacs_style_formatter.rb +2 -0
  102. data/lib/rubocop/formatter/simple_text_formatter.rb +2 -0
  103. data/lib/rubocop/formatter/tap_formatter.rb +2 -0
  104. data/lib/rubocop/lockfile.rb +40 -0
  105. data/lib/rubocop/options.rb +9 -9
  106. data/lib/rubocop/rspec/cop_helper.rb +0 -4
  107. data/lib/rubocop/rspec/expect_offense.rb +34 -22
  108. data/lib/rubocop/runner.rb +16 -1
  109. data/lib/rubocop/target_finder.rb +4 -2
  110. data/lib/rubocop/target_ruby.rb +47 -11
  111. data/lib/rubocop/util.rb +16 -0
  112. data/lib/rubocop/version.rb +8 -2
  113. metadata +28 -7
@@ -106,23 +106,13 @@ module RuboCop
106
106
  error && error.ancestors[1] == SystemCallError
107
107
  end
108
108
 
109
- def silence_warnings
110
- # Replaces Kernel::silence_warnings since it hides any warnings,
111
- # including the RuboCop ones
112
- old_verbose = $VERBOSE
113
- $VERBOSE = nil
114
- yield
115
- ensure
116
- $VERBOSE = old_verbose
117
- end
118
-
119
109
  def evaluate_exceptions(group)
120
110
  rescued_exceptions = group.exceptions
121
111
 
122
112
  if rescued_exceptions.any?
123
113
  rescued_exceptions.each_with_object([]) do |exception, converted|
124
114
  begin
125
- silence_warnings do
115
+ RuboCop::Util.silence_warnings do
126
116
  # Avoid printing deprecation warnings about constants
127
117
  converted << Kernel.const_get(exception.source)
128
118
  end
@@ -9,6 +9,12 @@ module RuboCop
9
9
  # In rare cases where only one iteration (or at most one iteration) is intended behavior,
10
10
  # the code should be refactored to use `if` conditionals.
11
11
  #
12
+ # NOTE: Block methods that are used with `Enumerable`s are considered to be loops.
13
+ #
14
+ # `IgnoredPatterns` can be used to match against the block receiver in order to allow
15
+ # code that would otherwise be registered as an offense (eg. `times` used not in an
16
+ # `Enumerable` context).
17
+ #
12
18
  # @example
13
19
  # # bad
14
20
  # while node
@@ -70,7 +76,16 @@ module RuboCop
70
76
  # raise NotFoundError
71
77
  # end
72
78
  #
79
+ # # bad
80
+ # 2.times { raise ArgumentError }
81
+ #
82
+ # @example IgnoredPatterns: [/(exactly|at_least|at_most)\(\d+\)\.times/] (default)
83
+ #
84
+ # # good
85
+ # exactly(2).times { raise StandardError }
73
86
  class UnreachableLoop < Base
87
+ include IgnoredPattern
88
+
74
89
  MSG = 'This loop will have at most one iteration.'
75
90
 
76
91
  def on_while(node)
@@ -91,6 +106,8 @@ module RuboCop
91
106
  return false unless node.block_type?
92
107
 
93
108
  send_node = node.send_node
109
+ return false if matches_ignored_pattern?(send_node.source)
110
+
94
111
  send_node.enumerable_method? || send_node.enumerator_method? || send_node.method?(:loop)
95
112
  end
96
113
 
@@ -124,7 +124,7 @@ module RuboCop
124
124
  end
125
125
 
126
126
  def classlike_node?(node)
127
- CLASSLIKE_TYPES.include?(node.type)
127
+ CLASSLIKE_TYPES.include?(node&.type)
128
128
  end
129
129
 
130
130
  def foldable_node?(node)
@@ -71,7 +71,7 @@ module RuboCop
71
71
  end
72
72
 
73
73
  def qualified_legacy_cop_name(cop_name)
74
- legacy_cop_names = RuboCop::ConfigObsoletion::OBSOLETE_COPS.keys
74
+ legacy_cop_names = RuboCop::ConfigObsoletion.legacy_cop_names
75
75
 
76
76
  legacy_cop_names.detect do |legacy_cop_name|
77
77
  legacy_cop_name.split('/')[1] == cop_name
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ # This module encapsulates the ability to allow certain identifiers in a cop.
6
+ module AllowedIdentifiers
7
+ SIGILS = '@$' # if a variable starts with a sigil it will be removed
8
+
9
+ def allowed_identifier?(name)
10
+ allowed_identifiers.include?(name.to_s.delete(SIGILS))
11
+ end
12
+
13
+ def allowed_identifiers
14
+ cop_config.fetch('AllowedIdentifiers', [])
15
+ end
16
+ end
17
+ end
18
+ end
@@ -22,16 +22,7 @@ module RuboCop
22
22
  end
23
23
 
24
24
  def begin_pos_with_comment(node)
25
- annotation_line = node.first_line - 1
26
- first_comment = nil
27
-
28
- processed_source.comments_before_line(annotation_line)
29
- .reverse_each do |comment|
30
- if comment.location.line == annotation_line
31
- first_comment = comment
32
- annotation_line -= 1
33
- end
34
- end
25
+ first_comment = processed_source.ast_with_comments[node].first
35
26
 
36
27
  start_line_position(first_comment || node)
37
28
  end
@@ -21,7 +21,7 @@ module RuboCop
21
21
  end
22
22
 
23
23
  def check_children_line_break(node, children, start = node)
24
- return if children.size < 2
24
+ return if children.empty?
25
25
 
26
26
  line = start.first_line
27
27
 
@@ -14,7 +14,10 @@ module RuboCop
14
14
  return if part_of_ignored_node?(node)
15
15
 
16
16
  if offense?(node)
17
- add_offense(node) { opposite_style_detected }
17
+ add_offense(node) do |corrector|
18
+ opposite_style_detected
19
+ autocorrect(corrector, node) if respond_to?(:autocorrect, true)
20
+ end
18
21
  else
19
22
  correct_style_detected
20
23
  end
@@ -24,7 +24,11 @@ module RuboCop
24
24
  name = full_name.gsub(/\A(_+)/, '')
25
25
  next if allowed_names.include?(name)
26
26
 
27
- range = arg_range(arg, name.size)
27
+ length = full_name.size
28
+ length += 1 if arg.restarg_type?
29
+ length += 2 if arg.kwrestarg_type?
30
+
31
+ range = arg_range(arg, length)
28
32
  issue_offenses(node, range, name)
29
33
  end
30
34
  end
@@ -3,7 +3,13 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Naming
6
- # This cop makes sure that accessor methods are named properly.
6
+ # This cop makes sure that accessor methods are named properly. Applies
7
+ # to both instance and class methods.
8
+ #
9
+ # NOTE: Offenses are only registered for methods with the expected
10
+ # arity. Getters (`get_attribute`) must have no arguments to be
11
+ # registered, and setters (`set_attribute(value)`) must have exactly
12
+ # one.
7
13
  #
8
14
  # @example
9
15
  # # bad
@@ -21,6 +27,14 @@ module RuboCop
21
27
  # # good
22
28
  # def attribute
23
29
  # end
30
+ #
31
+ # # accepted, incorrect arity for getter
32
+ # def get_value(attr)
33
+ # end
34
+ #
35
+ # # accepted, incorrect arity for setter
36
+ # def set_value
37
+ # end
24
38
  class AccessorMethodName < Base
25
39
  MSG_READER = 'Do not prefix reader method names with `get_`.'
26
40
  MSG_WRITER = 'Do not prefix writer method names with `set_`.'
@@ -4,7 +4,9 @@ module RuboCop
4
4
  module Cop
5
5
  module Naming
6
6
  # This cop checks for memoized methods whose instance variable name
7
- # does not match the method name.
7
+ # does not match the method name. Applies to both regular methods
8
+ # (defined with `def`) and dynamic methods (defined with
9
+ # `define_method` or `define_singleton_method`).
8
10
  #
9
11
  # This cop can be configured with the EnforcedStyleForLeadingUnderscores
10
12
  # directive. It can be configured to allow for memoized instance variables
@@ -48,6 +50,17 @@ module RuboCop
48
50
  # @foo ||= calculate_expensive_thing(helper_variable)
49
51
  # end
50
52
  #
53
+ # # good
54
+ # define_method(:foo) do
55
+ # @foo ||= calculate_expensive_thing
56
+ # end
57
+ #
58
+ # # good
59
+ # define_method(:foo) do
60
+ # return @foo if defined?(@foo)
61
+ # @foo = calculate_expensive_thing
62
+ # end
63
+ #
51
64
  # @example EnforcedStyleForLeadingUnderscores: required
52
65
  # # bad
53
66
  # def foo
@@ -79,6 +92,17 @@ module RuboCop
79
92
  # @_foo = calculate_expensive_thing
80
93
  # end
81
94
  #
95
+ # # good
96
+ # define_method(:foo) do
97
+ # @_foo ||= calculate_expensive_thing
98
+ # end
99
+ #
100
+ # # good
101
+ # define_method(:foo) do
102
+ # return @_foo if defined?(@_foo)
103
+ # @_foo = calculate_expensive_thing
104
+ # end
105
+ #
82
106
  # @example EnforcedStyleForLeadingUnderscores :optional
83
107
  # # bad
84
108
  # def foo
@@ -105,6 +129,16 @@ module RuboCop
105
129
  # return @_foo if defined?(@_foo)
106
130
  # @_foo = calculate_expensive_thing
107
131
  # end
132
+ #
133
+ # # good
134
+ # define_method(:foo) do
135
+ # @foo ||= calculate_expensive_thing
136
+ # end
137
+ #
138
+ # # good
139
+ # define_method(:foo) do
140
+ # @_foo ||= calculate_expensive_thing
141
+ # end
108
142
  class MemoizedInstanceVariableName < Base
109
143
  include ConfigurableEnforcedStyle
110
144
 
@@ -112,17 +146,27 @@ module RuboCop
112
146
  'method name `%<method>s`. Use `@%<suggested_var>s` instead.'
113
147
  UNDERSCORE_REQUIRED = 'Memoized variable `%<var>s` does not start ' \
114
148
  'with `_`. Use `@%<suggested_var>s` instead.'
149
+ DYNAMIC_DEFINE_METHODS = %i[define_method define_singleton_method].to_set.freeze
150
+
151
+ def_node_matcher :method_definition?, <<~PATTERN
152
+ ${
153
+ (block (send _ %DYNAMIC_DEFINE_METHODS ({sym str} $_)) ...)
154
+ (def $_ ...)
155
+ (defs _ $_ ...)
156
+ }
157
+ PATTERN
115
158
 
116
159
  # rubocop:disable Metrics/AbcSize
117
160
  def on_or_asgn(node)
118
161
  lhs, _value = *node
119
162
  return unless lhs.ivasgn_type?
120
- return unless (method_node = node.each_ancestor(:def, :defs).first)
163
+
164
+ method_node, method_name = find_definition(node)
165
+ return unless method_node
121
166
 
122
167
  body = method_node.body
123
168
  return unless body == node || body.children.last == node
124
169
 
125
- method_name = method_node.method_name
126
170
  return if matches?(method_name, lhs)
127
171
 
128
172
  msg = format(
@@ -147,11 +191,10 @@ module RuboCop
147
191
  arg = node.arguments.first
148
192
  return unless arg.ivar_type?
149
193
 
150
- method_node = node.each_ancestor(:def, :defs).first
194
+ method_node, method_name = find_definition(node)
151
195
  return unless method_node
152
196
 
153
197
  var_name = arg.children.first
154
- method_name = method_node.method_name
155
198
  defined_memoized?(method_node.body, var_name) do |defined_ivar, return_ivar, ivar_assign|
156
199
  return if matches?(method_name, ivar_assign)
157
200
 
@@ -174,6 +217,17 @@ module RuboCop
174
217
  'EnforcedStyleForLeadingUnderscores'
175
218
  end
176
219
 
220
+ def find_definition(node)
221
+ # Methods can be defined in a `def` or `defs`,
222
+ # or dynamically via a `block` node.
223
+ node.each_ancestor(:def, :defs, :block).each do |ancestor|
224
+ method_node, method_name = method_definition?(ancestor)
225
+ return [method_node, method_name] if method_node
226
+ end
227
+
228
+ nil
229
+ end
230
+
177
231
  def matches?(method_name, ivar_assign)
178
232
  return true if ivar_assign.nil? || method_name == :initialize
179
233
 
@@ -20,6 +20,7 @@ module RuboCop
20
20
  # # good
21
21
  # fooBar = 1
22
22
  class VariableName < Base
23
+ include AllowedIdentifiers
23
24
  include ConfigurableNaming
24
25
 
25
26
  MSG = 'Use %<style>s for variable names.'
@@ -27,6 +28,7 @@ module RuboCop
27
28
  def on_lvasgn(node)
28
29
  name, = *node
29
30
  return unless name
31
+ return if allowed_identifier?(name)
30
32
 
31
33
  check_name(node, name, node.loc.name)
32
34
  end
@@ -97,6 +97,7 @@ module RuboCop
97
97
  # expect(Open3).to receive(:capture3)
98
98
  #
99
99
  class VariableNumber < Base
100
+ include AllowedIdentifiers
100
101
  include ConfigurableNumbering
101
102
 
102
103
  MSG = 'Use %<style>s for %<identifier_type>s numbers.'
@@ -139,14 +140,6 @@ module RuboCop
139
140
 
140
141
  format(MSG, style: style, identifier_type: identifier_type)
141
142
  end
142
-
143
- def allowed_identifier?(name)
144
- allowed_identifiers.include?(name.to_s.delete('@'))
145
- end
146
-
147
- def allowed_identifiers
148
- cop_config.fetch('AllowedIdentifiers', [])
149
- end
150
143
  end
151
144
  end
152
145
  end
@@ -204,6 +204,12 @@ module RuboCop
204
204
  to_h[cop_name].first
205
205
  end
206
206
 
207
+ def freeze
208
+ clear_enrollment_queue
209
+ unqualified_cop_names # build cache
210
+ super
211
+ end
212
+
207
213
  @global = new
208
214
 
209
215
  class << self
@@ -228,6 +234,10 @@ module RuboCop
228
234
  @global = previous
229
235
  end
230
236
 
237
+ def self.reset!
238
+ @global = new
239
+ end
240
+
231
241
  private
232
242
 
233
243
  def initialize_copy(reg)
@@ -87,7 +87,9 @@ module RuboCop
87
87
  return if allow_modifiers_on_symbols?(node)
88
88
 
89
89
  if offense?(node)
90
- add_offense(node.loc.selector) if opposite_style_detected
90
+ add_offense(node.loc.selector) do
91
+ opposite_style_detected
92
+ end
91
93
  else
92
94
  correct_style_detected
93
95
  end
@@ -14,8 +14,9 @@ module RuboCop
14
14
  #
15
15
  # # good
16
16
  # ?\C-\M-d
17
- class CharacterLiteral < Cop
17
+ class CharacterLiteral < Base
18
18
  include StringHelp
19
+ extend AutoCorrector
19
20
 
20
21
  MSG = 'Do not use the character literal - ' \
21
22
  'use string literal instead.'
@@ -26,17 +27,15 @@ module RuboCop
26
27
  node.source.size.between?(2, 3)
27
28
  end
28
29
 
29
- def autocorrect(node)
30
- lambda do |corrector|
31
- string = node.source[1..-1]
30
+ def autocorrect(corrector, node)
31
+ string = node.source[1..-1]
32
32
 
33
- # special character like \n
34
- # or ' which needs to use "" or be escaped.
35
- if string.length == 2 || string == "'"
36
- corrector.replace(node, %("#{string}"))
37
- elsif string.length == 1 # normal character
38
- corrector.replace(node, "'#{string}'")
39
- end
33
+ # special character like \n
34
+ # or ' which needs to use "" or be escaped.
35
+ if string.length == 2 || string == "'"
36
+ corrector.replace(node, %("#{string}"))
37
+ elsif string.length == 1 # normal character
38
+ corrector.replace(node, "'#{string}'")
40
39
  end
41
40
  end
42
41
 
@@ -48,7 +48,7 @@ module RuboCop
48
48
  end
49
49
 
50
50
  def on_send(node)
51
- return unless node.arguments.one? && node.first_argument.block_pass_type?
51
+ return unless implicit_block?(node)
52
52
 
53
53
  check_method_node(node)
54
54
  end
@@ -64,9 +64,22 @@ module RuboCop
64
64
  end
65
65
  end
66
66
 
67
+ def implicit_block?(node)
68
+ return false unless node.arguments.any?
69
+
70
+ node.last_argument.block_pass_type? ||
71
+ node.last_argument.sym_type? && methods_accepting_symbol.include?(node.method_name.to_s)
72
+ end
73
+
67
74
  def message(node)
68
75
  format(MSG, prefer: preferred_method(node.method_name), current: node.method_name)
69
76
  end
77
+
78
+ # Some enumerable methods accept a bare symbol (ie. _not_ Symbol#to_proc) instead
79
+ # of a block.
80
+ def methods_accepting_symbol
81
+ Array(cop_config['MethodsAcceptingSymbol'])
82
+ end
70
83
  end
71
84
  end
72
85
  end