rubocop 1.32.0 → 1.33.0

Sign up to get free protection for your applications and to get access to all the features.
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)