rubocop 1.32.0 → 1.33.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 (46) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +2 -2
  3. data/config/default.yml +45 -16
  4. data/config/obsoletion.yml +23 -1
  5. data/lib/rubocop/cache_config.rb +29 -0
  6. data/lib/rubocop/cli/command/auto_genenerate_config.rb +2 -2
  7. data/lib/rubocop/cli/command/init_dotfile.rb +1 -1
  8. data/lib/rubocop/config_finder.rb +68 -0
  9. data/lib/rubocop/config_loader.rb +5 -45
  10. data/lib/rubocop/config_obsoletion/changed_parameter.rb +5 -0
  11. data/lib/rubocop/config_obsoletion/parameter_rule.rb +4 -0
  12. data/lib/rubocop/config_obsoletion.rb +7 -2
  13. data/lib/rubocop/cop/layout/block_end_newline.rb +32 -5
  14. data/lib/rubocop/cop/layout/first_argument_indentation.rb +6 -1
  15. data/lib/rubocop/cop/lint/ambiguous_block_association.rb +21 -8
  16. data/lib/rubocop/cop/lint/debugger.rb +11 -1
  17. data/lib/rubocop/cop/lint/empty_conditional_body.rb +60 -1
  18. data/lib/rubocop/cop/lint/number_conversion.rb +24 -8
  19. data/lib/rubocop/cop/metrics/abc_size.rb +3 -1
  20. data/lib/rubocop/cop/metrics/block_length.rb +6 -7
  21. data/lib/rubocop/cop/metrics/method_length.rb +8 -8
  22. data/lib/rubocop/cop/mixin/allowed_methods.rb +15 -1
  23. data/lib/rubocop/cop/mixin/allowed_pattern.rb +9 -1
  24. data/lib/rubocop/cop/mixin/comments_help.rb +5 -1
  25. data/lib/rubocop/cop/mixin/method_complexity.rb +4 -9
  26. data/lib/rubocop/cop/naming/predicate_name.rb +24 -3
  27. data/lib/rubocop/cop/style/block_delimiters.rb +26 -7
  28. data/lib/rubocop/cop/style/class_and_module_children.rb +4 -4
  29. data/lib/rubocop/cop/style/class_equality_comparison.rb +32 -7
  30. data/lib/rubocop/cop/style/empty_heredoc.rb +15 -1
  31. data/lib/rubocop/cop/style/format_string_token.rb +21 -8
  32. data/lib/rubocop/cop/style/hash_except.rb +0 -4
  33. data/lib/rubocop/cop/style/method_call_with_args_parentheses/require_parentheses.rb +5 -1
  34. data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +7 -7
  35. data/lib/rubocop/cop/style/method_call_without_args_parentheses.rb +11 -6
  36. data/lib/rubocop/cop/style/numeric_predicate.rb +28 -8
  37. data/lib/rubocop/cop/style/redundant_condition.rb +19 -4
  38. data/lib/rubocop/cop/style/redundant_sort.rb +21 -6
  39. data/lib/rubocop/cop/style/symbol_proc.rb +29 -9
  40. data/lib/rubocop/result_cache.rb +22 -20
  41. data/lib/rubocop/server/cache.rb +33 -1
  42. data/lib/rubocop/server/cli.rb +19 -2
  43. data/lib/rubocop/version.rb +1 -1
  44. data/lib/rubocop.rb +0 -1
  45. metadata +5 -4
  46. data/lib/rubocop/cop/mixin/ignored_methods.rb +0 -52
@@ -15,9 +15,19 @@ module RuboCop
15
15
  # [source,yaml]
16
16
  # ----
17
17
  # Lint/Debugger:
18
- # WebConsole: ~
18
+ # DebuggerMethods:
19
+ # WebConsole: ~
19
20
  # ----
20
21
  #
22
+ # You can also add your own methods by adding a new category:
23
+ #
24
+ # [source,yaml]
25
+ # ----
26
+ # Lint/Debugger:
27
+ # DebuggerMethods:
28
+ # MyDebugger:
29
+ # MyDebugger.debug_this
30
+ # ----
21
31
  #
22
32
  # @example
23
33
  #
@@ -4,6 +4,9 @@ module RuboCop
4
4
  module Cop
5
5
  module Lint
6
6
  # Checks for the presence of `if`, `elsif` and `unless` branches without a body.
7
+ #
8
+ # NOTE: empty `else` branches are handled by `Style/EmptyElse`.
9
+ #
7
10
  # @example
8
11
  # # bad
9
12
  # if condition
@@ -53,7 +56,9 @@ module RuboCop
53
56
  # end
54
57
  #
55
58
  class EmptyConditionalBody < Base
59
+ extend AutoCorrector
56
60
  include CommentsHelp
61
+ include RangeHelp
57
62
 
58
63
  MSG = 'Avoid `%<keyword>s` branches without a body.'
59
64
 
@@ -61,7 +66,61 @@ module RuboCop
61
66
  return if node.body
62
67
  return if cop_config['AllowComments'] && contains_comments?(node)
63
68
 
64
- add_offense(node, message: format(MSG, keyword: node.keyword))
69
+ add_offense(node, message: format(MSG, keyword: node.keyword)) do |corrector|
70
+ autocorrect(corrector, node)
71
+ end
72
+ end
73
+
74
+ private
75
+
76
+ def autocorrect(corrector, node)
77
+ remove_comments(corrector, node)
78
+ remove_empty_branch(corrector, node)
79
+ correct_other_branches(corrector, node)
80
+ end
81
+
82
+ def remove_comments(corrector, node)
83
+ comments_in_range(node).each do |comment|
84
+ range = range_by_whole_lines(comment.loc.expression, include_final_newline: true)
85
+ corrector.remove(range)
86
+ end
87
+ end
88
+
89
+ def remove_empty_branch(corrector, node)
90
+ corrector.remove(deletion_range(branch_range(node)))
91
+ end
92
+
93
+ def correct_other_branches(corrector, node)
94
+ return unless (node.if? || node.unless?) && node.else_branch
95
+
96
+ if node.else_branch.if_type?
97
+ # Replace an orphaned `elsif` with `if`
98
+ corrector.replace(node.else_branch.loc.keyword, 'if')
99
+ else
100
+ # Flip orphaned `else`
101
+ corrector.replace(node.loc.else, "#{node.inverse_keyword} #{node.condition.source}")
102
+ end
103
+ end
104
+
105
+ def branch_range(node)
106
+ if node.loc.else
107
+ node.source_range.with(end_pos: node.loc.else.begin_pos - 1)
108
+ else
109
+ node.source_range
110
+ end
111
+ end
112
+
113
+ def deletion_range(range)
114
+ # Collect a range between the start of the `if` node and the next relevant node,
115
+ # including final new line.
116
+ # Based on `RangeHelp#range_by_whole_lines` but allows the `if` to not start
117
+ # on the first column.
118
+ buffer = @processed_source.buffer
119
+
120
+ last_line = buffer.source_line(range.last_line)
121
+ end_offset = last_line.length - range.last_column + 1
122
+
123
+ range.adjust(end_pos: end_offset).intersect(buffer.source_range)
65
124
  end
66
125
  end
67
126
  end
@@ -16,8 +16,8 @@ module RuboCop
16
16
  # NOTE: Some values cannot be converted properly using one of the `Kernel`
17
17
  # method (for instance, `Time` and `DateTime` values are allowed by this
18
18
  # cop by default). Similarly, Rails' duration methods do not work well
19
- # with `Integer()` and can be ignored with `IgnoredMethods`. By default,
20
- # there are no methods to ignored.
19
+ # with `Integer()` and can be allowed with `AllowedMethods`. By default,
20
+ # there are no methods to allowed.
21
21
  #
22
22
  # @safety
23
23
  # Autocorrection is unsafe because it is not guaranteed that the
@@ -46,12 +46,22 @@ module RuboCop
46
46
  # foo.try { |i| Float(i) }
47
47
  # bar.send { |i| Complex(i) }
48
48
  #
49
- # @example IgnoredMethods: [] (default)
49
+ # @example AllowedMethods: [] (default)
50
50
  #
51
51
  # # bad
52
52
  # 10.minutes.to_i
53
53
  #
54
- # @example IgnoredMethods: [minutes]
54
+ # @example AllowedMethods: [minutes]
55
+ #
56
+ # # good
57
+ # 10.minutes.to_i
58
+ #
59
+ # @example AllowedPatterns: [] (default)
60
+ #
61
+ # # bad
62
+ # 10.minutes.to_i
63
+ #
64
+ # @example AllowedPatterns: [/min*/]
55
65
  #
56
66
  # # good
57
67
  # 10.minutes.to_i
@@ -62,7 +72,8 @@ module RuboCop
62
72
  # Time.now.to_datetime.to_i
63
73
  class NumberConversion < Base
64
74
  extend AutoCorrector
65
- include IgnoredMethods
75
+ include AllowedMethods
76
+ include AllowedPattern
66
77
 
67
78
  CONVERSION_METHOD_CLASS_MAPPING = {
68
79
  to_i: "#{Integer.name}(%<number_object>s, 10)",
@@ -97,7 +108,7 @@ module RuboCop
97
108
 
98
109
  def handle_conversion_method(node)
99
110
  to_method(node) do |receiver, to_method|
100
- next if receiver.nil? || ignore_receiver?(receiver)
111
+ next if receiver.nil? || allow_receiver?(receiver)
101
112
 
102
113
  message = format(
103
114
  MSG,
@@ -141,9 +152,10 @@ module RuboCop
141
152
  corrector.remove(node.loc.end)
142
153
  end
143
154
 
144
- def ignore_receiver?(receiver)
155
+ def allow_receiver?(receiver)
145
156
  if receiver.numeric_type? || (receiver.send_type? &&
146
- (conversion_method?(receiver.method_name) || ignored_method?(receiver.method_name)))
157
+ (conversion_method?(receiver.method_name) ||
158
+ allowed_method_name?(receiver.method_name)))
147
159
  true
148
160
  elsif (receiver = top_receiver(receiver))
149
161
  receiver.const_type? && ignored_class?(receiver.const_name)
@@ -152,6 +164,10 @@ module RuboCop
152
164
  end
153
165
  end
154
166
 
167
+ def allowed_method_name?(name)
168
+ allowed_method?(name) || matches_allowed_pattern?(name)
169
+ end
170
+
155
171
  def top_receiver(node)
156
172
  receiver = node
157
173
  receiver = receiver.receiver until receiver.receiver.nil?
@@ -33,7 +33,9 @@ module RuboCop
33
33
  # render 'pages/search/page'
34
34
  # end
35
35
  #
36
- # This cop also takes into account `IgnoredMethods` (defaults to `[]`)
36
+ # This cop also takes into account `AllowedMethods` (defaults to `[]`)
37
+ # And `AllowedPatterns` (defaults to `[]`)
38
+ #
37
39
  class AbcSize < Base
38
40
  include MethodComplexity
39
41
 
@@ -14,8 +14,8 @@ module RuboCop
14
14
  #
15
15
  #
16
16
  # NOTE: The `ExcludedMethods` configuration is deprecated and only kept
17
- # for backwards compatibility. Please use `IgnoredMethods` instead.
18
- # By default, there are no methods to ignored.
17
+ # for backwards compatibility. Please use `AllowedMethods` and `AllowedPatterns`
18
+ # instead. By default, there are no methods to allowed.
19
19
  #
20
20
  # @example CountAsOne: ['array', 'heredoc']
21
21
  #
@@ -38,14 +38,13 @@ module RuboCop
38
38
  # NOTE: This cop does not apply for `Struct` definitions.
39
39
  class BlockLength < Base
40
40
  include CodeLength
41
- include IgnoredMethods
42
-
43
- ignored_methods deprecated_key: 'ExcludedMethods'
41
+ include AllowedMethods
42
+ include AllowedPattern
44
43
 
45
44
  LABEL = 'Block'
46
45
 
47
46
  def on_block(node)
48
- return if ignored_method?(node.method_name)
47
+ return if allowed_method?(node.method_name) || matches_allowed_pattern?(node.method_name)
49
48
  return if method_receiver_excluded?(node)
50
49
  return if node.class_constructor? || node.struct_constructor?
51
50
 
@@ -59,7 +58,7 @@ module RuboCop
59
58
  node_receiver = node.receiver&.source&.gsub(/\s+/, '')
60
59
  node_method = String(node.method_name)
61
60
 
62
- ignored_methods.any? do |config|
61
+ allowed_methods.any? do |config|
63
62
  next unless config.is_a?(String)
64
63
 
65
64
  receiver, method = config.split('.')
@@ -4,16 +4,17 @@ module RuboCop
4
4
  module Cop
5
5
  module Metrics
6
6
  # Checks if the length of a method exceeds some maximum value.
7
- # Comment lines can optionally be ignored.
7
+ # Comment lines can optionally be allowed.
8
8
  # The maximum allowed length is configurable.
9
9
  #
10
10
  # You can set literals you want to fold with `CountAsOne`.
11
11
  # Available are: 'array', 'hash', and 'heredoc'. Each literal
12
12
  # will be counted as one line regardless of its actual size.
13
13
  #
14
- # NOTE: The `ExcludedMethods` configuration is deprecated and only kept
15
- # for backwards compatibility. Please use `IgnoredMethods` instead.
16
- # By default, there are no methods to ignored.
14
+ # NOTE: The `ExcludedMethods` and `IgnoredMethods` configuration is
15
+ # deprecated and only kept for backwards compatibility.
16
+ # Please use `AllowedMethods` and `AllowedPatterns` instead.
17
+ # By default, there are no methods to allowed.
17
18
  #
18
19
  # @example CountAsOne: ['array', 'heredoc']
19
20
  #
@@ -35,14 +36,13 @@ module RuboCop
35
36
  #
36
37
  class MethodLength < Base
37
38
  include CodeLength
38
- include IgnoredMethods
39
-
40
- ignored_methods deprecated_key: 'ExcludedMethods'
39
+ include AllowedMethods
40
+ include AllowedPattern
41
41
 
42
42
  LABEL = 'Method'
43
43
 
44
44
  def on_def(node)
45
- return if ignored_method?(node.method_name)
45
+ return if allowed_method?(node.method_name) || matches_allowed_pattern?(node.method_name)
46
46
 
47
47
  check_code_length(node)
48
48
  end
@@ -12,10 +12,24 @@ module RuboCop
12
12
  allowed_methods.include?(name.to_s)
13
13
  end
14
14
 
15
+ # @deprecated Use allowed_method? instead
16
+ alias ignored_method? allowed_method?
17
+
15
18
  # @api public
16
19
  def allowed_methods
17
- cop_config.fetch('AllowedMethods', [])
20
+ deprecated_values = cop_config_deprecated_values
21
+ if deprecated_values.any?(Regexp)
22
+ cop_config.fetch('AllowedMethods', [])
23
+ else
24
+ Array(cop_config['AllowedMethods']).concat(deprecated_values)
25
+ end
26
+ end
27
+
28
+ def cop_config_deprecated_values
29
+ Array(cop_config['IgnoredMethods']).concat(Array(cop_config['ExcludedMethods']))
18
30
  end
19
31
  end
32
+ # @deprecated IgnoredMethods class has been replaced with AllowedMethods.
33
+ IgnoredMethods = AllowedMethods
20
34
  end
21
35
  end
@@ -30,7 +30,15 @@ module RuboCop
30
30
  def allowed_patterns
31
31
  # Since there could be a pattern specified in the default config, merge the two
32
32
  # arrays together.
33
- Array(cop_config['AllowedPatterns']).concat(Array(cop_config['IgnoredPatterns']))
33
+ patterns = Array(cop_config['AllowedPatterns']).concat(Array(cop_config['IgnoredPatterns']))
34
+ deprecated_values = cop_config_deprecated_methods_values
35
+ return patterns unless deprecated_values.any?(Regexp)
36
+
37
+ Array(patterns.concat(deprecated_values))
38
+ end
39
+
40
+ def cop_config_deprecated_methods_values
41
+ Array(cop_config['IgnoredMethods']).concat(Array(cop_config['ExcludedMethods']))
34
42
  end
35
43
  end
36
44
 
@@ -12,10 +12,14 @@ module RuboCop
12
12
  end
13
13
 
14
14
  def contains_comments?(node)
15
+ comments_in_range(node).any?
16
+ end
17
+
18
+ def comments_in_range(node)
15
19
  start_line = node.source_range.line
16
20
  end_line = find_end_line(node)
17
21
 
18
- processed_source.each_comment_in_lines(start_line...end_line).any?
22
+ processed_source.each_comment_in_lines(start_line...end_line)
19
23
  end
20
24
 
21
25
  private
@@ -6,21 +6,16 @@ module RuboCop
6
6
  #
7
7
  # This module handles measurement and reporting of complexity in methods.
8
8
  module MethodComplexity
9
- include IgnoredMethods
9
+ include AllowedMethods
10
+ include AllowedPattern
10
11
  include Metrics::Utils::RepeatedCsendDiscount
11
12
  extend NodePattern::Macros
12
13
  extend ExcludeLimit
13
14
 
14
15
  exclude_limit 'Max'
15
16
 
16
- # Ensure cops that include `MethodComplexity` have the config
17
- # `attr_accessor`s that `ignored_method?` needs.
18
- def self.included(base)
19
- base.extend(IgnoredMethods::Config)
20
- end
21
-
22
17
  def on_def(node)
23
- return if ignored_method?(node.method_name)
18
+ return if allowed_method?(node.method_name) || matches_allowed_pattern?(node.method_name)
24
19
 
25
20
  check_complexity(node, node.method_name)
26
21
  end
@@ -28,7 +23,7 @@ module RuboCop
28
23
 
29
24
  def on_block(node)
30
25
  define_method?(node) do |name|
31
- return if ignored_method?(name)
26
+ return if allowed_method?(name) || matches_allowed_pattern?(name)
32
27
 
33
28
  check_complexity(node, name)
34
29
  end
@@ -3,9 +3,30 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Naming
6
- # Makes sure that predicates are named properly.
7
- # `is_a?` method is allowed by default.
8
- # These are customizable with `AllowedMethods` option.
6
+ # Checks that predicate methods names end with a question mark and
7
+ # do not start with a forbidden prefix.
8
+ #
9
+ # A method is determined to be a predicate method if its name starts
10
+ # with one of the prefixes defined in the `NamePrefix` configuration.
11
+ # You can change what prefixes are considered by changing this option.
12
+ # Any method name that starts with one of these prefixes is required by
13
+ # the cop to end with a `?`. Other methods can be allowed by adding to
14
+ # the `AllowedMethods` configuration.
15
+ #
16
+ # NOTE: The `is_a?` method is allowed by default.
17
+ #
18
+ # If `ForbiddenPrefixes` is set, methods that start with the configured
19
+ # prefixes will not be allowed and will be removed by autocorrection.
20
+ #
21
+ # In other words, if `ForbiddenPrefixes` is empty, a method named `is_foo`
22
+ # will register an offense only due to the lack of question mark (and will be
23
+ # autocorrected to `is_foo?`). If `ForbiddenPrefixes` contains `is_`,
24
+ # `is_foo` will register an offense both because the ? is missing and because of
25
+ # the `is_` prefix, and will be corrected to `foo?`.
26
+ #
27
+ # NOTE: `ForbiddenPrefixes` is only applied to prefixes in `NamePrefix`;
28
+ # a prefix in the former but not the latter will not be considered by
29
+ # this cop.
9
30
  #
10
31
  # @example
11
32
  # # bad
@@ -10,7 +10,7 @@ module RuboCop
10
10
  # Methods that can be either procedural or functional and cannot be
11
11
  # categorised from their usage alone is ignored.
12
12
  # `lambda`, `proc`, and `it` are their defaults.
13
- # Additional methods can be added to the `IgnoredMethods`.
13
+ # Additional methods can be added to the `AllowedMethods`.
14
14
  #
15
15
  # @example EnforcedStyle: line_count_based (default)
16
16
  # # bad - single line block
@@ -66,7 +66,7 @@ module RuboCop
66
66
  # x
67
67
  # }.inspect
68
68
  #
69
- # # The AllowBracesOnProceduralOneLiners option is ignored unless the
69
+ # # The AllowBracesOnProceduralOneLiners option is allowed unless the
70
70
  # # EnforcedStyle is set to `semantic`. If so:
71
71
  #
72
72
  # # If the AllowBracesOnProceduralOneLiners option is unspecified, or
@@ -116,7 +116,7 @@ module RuboCop
116
116
  #
117
117
  # # Methods listed in the BracesRequiredMethods list, such as 'sig'
118
118
  # # in this example, will require `{...}` braces. This option takes
119
- # # precedence over all other configurations except IgnoredMethods.
119
+ # # precedence over all other configurations except AllowedMethods.
120
120
  #
121
121
  # # bad
122
122
  # sig do
@@ -138,7 +138,7 @@ module RuboCop
138
138
  # puts foo
139
139
  # end
140
140
  #
141
- # @example IgnoredMethods: ['lambda', 'proc', 'it' ] (default)
141
+ # @example AllowedMethods: ['lambda', 'proc', 'it' ] (default)
142
142
  #
143
143
  # # good
144
144
  # foo = lambda do |x|
@@ -149,9 +149,26 @@ module RuboCop
149
149
  # x * 100
150
150
  # end
151
151
  #
152
+ # @example AllowedPatterns: [] (default)
153
+ #
154
+ # # bad
155
+ # things.map { |thing|
156
+ # something = thing.some_method
157
+ # process(something)
158
+ # }
159
+ #
160
+ # @example AllowedPatterns: [/map/]
161
+ #
162
+ # # good
163
+ # things.map { |thing|
164
+ # something = thing.some_method
165
+ # process(something)
166
+ # }
167
+ #
152
168
  class BlockDelimiters < Base
153
169
  include ConfigurableEnforcedStyle
154
- include IgnoredMethods
170
+ include AllowedMethods
171
+ include AllowedPattern
155
172
  include RangeHelp
156
173
  extend AutoCorrector
157
174
 
@@ -330,12 +347,14 @@ module RuboCop
330
347
  end
331
348
 
332
349
  def special_method?(method_name)
333
- ignored_method?(method_name) || braces_required_method?(method_name)
350
+ allowed_method?(method_name) ||
351
+ matches_allowed_pattern?(method_name) ||
352
+ braces_required_method?(method_name)
334
353
  end
335
354
 
336
355
  def special_method_proper_block_style?(node)
337
356
  method_name = node.method_name
338
- return true if ignored_method?(method_name)
357
+ return true if allowed_method?(method_name) || matches_allowed_pattern?(method_name)
339
358
  return node.braces? if braces_required_method?(method_name)
340
359
  end
341
360
 
@@ -117,10 +117,10 @@ module RuboCop
117
117
  end
118
118
 
119
119
  def remove_end(corrector, body)
120
- range = range_between(
121
- body.loc.end.begin_pos - leading_spaces(body).size,
122
- body.loc.end.end_pos + 1
123
- )
120
+ remove_begin_pos = body.loc.end.begin_pos - leading_spaces(body).size
121
+ adjustment = processed_source.raw_source[remove_begin_pos] == ';' ? 0 : 1
122
+ range = range_between(remove_begin_pos, body.loc.end.end_pos + adjustment)
123
+
124
124
  corrector.remove(range)
125
125
  end
126
126
 
@@ -5,8 +5,8 @@ module RuboCop
5
5
  module Style
6
6
  # Enforces the use of `Object#instance_of?` instead of class comparison
7
7
  # for equality.
8
- # `==`, `equal?`, and `eql?` methods are ignored by default.
9
- # These are customizable with `IgnoredMethods` option.
8
+ # `==`, `equal?`, and `eql?` methods are allowed by default.
9
+ # These are customizable with `AllowedMethods` option.
10
10
  #
11
11
  # @example
12
12
  # # bad
@@ -18,7 +18,7 @@ module RuboCop
18
18
  # # good
19
19
  # var.instance_of?(Date)
20
20
  #
21
- # @example IgnoreMethods: [] (default)
21
+ # @example AllowedMethods: [] (default)
22
22
  # # good
23
23
  # var.instance_of?(Date)
24
24
  #
@@ -28,7 +28,7 @@ module RuboCop
28
28
  # var.class.eql?(Date)
29
29
  # var.class.name == 'Date'
30
30
  #
31
- # @example IgnoreMethods: [`==`]
31
+ # @example AllowedMethods: [`==`]
32
32
  # # good
33
33
  # var.instance_of?(Date)
34
34
  # var.class == Date
@@ -38,9 +38,30 @@ module RuboCop
38
38
  # var.class.equal?(Date)
39
39
  # var.class.eql?(Date)
40
40
  #
41
+ # @example AllowedPatterns: [] (default)
42
+ # # good
43
+ # var.instance_of?(Date)
44
+ #
45
+ # # bad
46
+ # var.class == Date
47
+ # var.class.equal?(Date)
48
+ # var.class.eql?(Date)
49
+ # var.class.name == 'Date'
50
+ #
51
+ # @example AllowedPatterns: [`/eq/`]
52
+ # # good
53
+ # var.instance_of?(Date)
54
+ # var.class.equal?(Date)
55
+ # var.class.eql?(Date)
56
+ #
57
+ # # bad
58
+ # var.class == Date
59
+ # var.class.name == 'Date'
60
+ #
41
61
  class ClassEqualityComparison < Base
42
62
  include RangeHelp
43
- include IgnoredMethods
63
+ include AllowedMethods
64
+ include AllowedPattern
44
65
  extend AutoCorrector
45
66
 
46
67
  MSG = 'Use `instance_of?(%<class_name>s)` instead of comparing classes.'
@@ -56,7 +77,9 @@ module RuboCop
56
77
 
57
78
  def on_send(node)
58
79
  def_node = node.each_ancestor(:def, :defs).first
59
- return if def_node && ignored_method?(def_node.method_name)
80
+ return if def_node &&
81
+ (allowed_method?(def_node.method_name) ||
82
+ matches_allowed_pattern?(def_node.method_name))
60
83
 
61
84
  class_comparison_candidate?(node) do |receiver_node, class_node|
62
85
  range = offense_range(receiver_node, node)
@@ -74,7 +97,9 @@ module RuboCop
74
97
  if node.children.first.method?(:name)
75
98
  return class_node.receiver.source if class_node.receiver
76
99
 
77
- class_node.source.delete('"').delete("'")
100
+ value = class_node.source.delete('"').delete("'")
101
+ value.prepend('::') if class_node.each_ancestor(:class, :module).any?
102
+ value
78
103
  else
79
104
  class_node.source
80
105
  end
@@ -48,11 +48,25 @@ module RuboCop
48
48
  add_offense(node) do |corrector|
49
49
  heredoc_end = node.loc.heredoc_end
50
50
 
51
- corrector.replace(node, "''")
51
+ corrector.replace(node, preferred_string_literal)
52
52
  corrector.remove(range_by_whole_lines(heredoc_body, include_final_newline: true))
53
53
  corrector.remove(range_by_whole_lines(heredoc_end, include_final_newline: true))
54
54
  end
55
55
  end
56
+
57
+ private
58
+
59
+ def preferred_string_literal
60
+ enforce_double_quotes? ? '""' : "''"
61
+ end
62
+
63
+ def enforce_double_quotes?
64
+ string_literals_config['EnforcedStyle'] == 'double_quotes'
65
+ end
66
+
67
+ def string_literals_config
68
+ config.for_cop('Style/StringLiterals')
69
+ end
56
70
  end
57
71
  end
58
72
  end
@@ -11,8 +11,8 @@ module RuboCop
11
11
  # The reason is that _unannotated_ format is very similar
12
12
  # to encoded URLs or Date/Time formatting strings.
13
13
  #
14
- # This cop can be customized ignored methods with `IgnoredMethods`.
15
- # By default, there are no methods to ignored.
14
+ # This cop can be customized allowed methods with `AllowedMethods`.
15
+ # By default, there are no methods to allowed.
16
16
  #
17
17
  # @example EnforcedStyle: annotated (default)
18
18
  #
@@ -62,23 +62,34 @@ module RuboCop
62
62
  # # good
63
63
  # format('%06d', 10)
64
64
  #
65
- # @example IgnoredMethods: [] (default)
65
+ # @example AllowedMethods: [] (default)
66
66
  #
67
67
  # # bad
68
68
  # redirect('foo/%{bar_id}')
69
69
  #
70
- # @example IgnoredMethods: [redirect]
70
+ # @example AllowedMethods: [redirect]
71
+ #
72
+ # # good
73
+ # redirect('foo/%{bar_id}')
74
+ #
75
+ # @example AllowedPatterns: [] (default)
76
+ #
77
+ # # bad
78
+ # redirect('foo/%{bar_id}')
79
+ #
80
+ # @example AllowedPatterns: [/redirect/]
71
81
  #
72
82
  # # good
73
83
  # redirect('foo/%{bar_id}')
74
84
  #
75
85
  class FormatStringToken < Base
76
86
  include ConfigurableEnforcedStyle
77
- include IgnoredMethods
87
+ include AllowedMethods
88
+ include AllowedPattern
78
89
  extend AutoCorrector
79
90
 
80
91
  def on_str(node)
81
- return if format_string_token?(node) || use_ignored_method?(node)
92
+ return if format_string_token?(node) || use_allowed_method?(node)
82
93
 
83
94
  detections = collect_detections(node)
84
95
  return if detections.empty?
@@ -103,9 +114,11 @@ module RuboCop
103
114
  !node.value.include?('%') || node.each_ancestor(:xstr, :regexp).any?
104
115
  end
105
116
 
106
- def use_ignored_method?(node)
117
+ def use_allowed_method?(node)
107
118
  send_parent = node.each_ancestor(:send).first
108
- send_parent && ignored_method?(send_parent.method_name)
119
+ send_parent &&
120
+ (allowed_method?(send_parent.method_name) ||
121
+ matches_allowed_pattern?(send_parent.method_name))
109
122
  end
110
123
 
111
124
  def check_sequence(detected_sequence, token_range)