rubocop 0.85.1 → 0.86.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (100) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +16 -4
  3. data/config/default.yml +29 -1
  4. data/lib/rubocop.rb +3 -0
  5. data/lib/rubocop/cli/command/init_dotfile.rb +1 -1
  6. data/lib/rubocop/config.rb +1 -1
  7. data/lib/rubocop/config_loader_resolver.rb +1 -1
  8. data/lib/rubocop/cop/gemspec/required_ruby_version.rb +1 -1
  9. data/lib/rubocop/cop/generator/configuration_injector.rb +1 -1
  10. data/lib/rubocop/cop/layout/comment_indentation.rb +3 -3
  11. data/lib/rubocop/cop/layout/empty_comment.rb +1 -1
  12. data/lib/rubocop/cop/layout/empty_lines_around_attribute_accessor.rb +2 -0
  13. data/lib/rubocop/cop/layout/end_of_line.rb +1 -1
  14. data/lib/rubocop/cop/layout/first_argument_indentation.rb +1 -1
  15. data/lib/rubocop/cop/layout/first_array_element_line_break.rb +1 -1
  16. data/lib/rubocop/cop/layout/hash_alignment.rb +1 -1
  17. data/lib/rubocop/cop/layout/multiline_block_layout.rb +1 -1
  18. data/lib/rubocop/cop/layout/space_after_colon.rb +1 -1
  19. data/lib/rubocop/cop/layout/space_around_keyword.rb +2 -2
  20. data/lib/rubocop/cop/layout/space_around_operators.rb +1 -1
  21. data/lib/rubocop/cop/layout/space_before_block_braces.rb +14 -0
  22. data/lib/rubocop/cop/layout/space_inside_array_literal_brackets.rb +1 -1
  23. data/lib/rubocop/cop/layout/space_inside_block_braces.rb +1 -1
  24. data/lib/rubocop/cop/layout/space_inside_hash_literal_braces.rb +2 -2
  25. data/lib/rubocop/cop/lint/constant_resolution.rb +89 -0
  26. data/lib/rubocop/cop/lint/float_out_of_range.rb +1 -1
  27. data/lib/rubocop/cop/lint/format_parameter_mismatch.rb +6 -1
  28. data/lib/rubocop/cop/lint/percent_string_array.rb +1 -1
  29. data/lib/rubocop/cop/lint/percent_symbol_array.rb +1 -1
  30. data/lib/rubocop/cop/lint/raise_exception.rb +12 -4
  31. data/lib/rubocop/cop/lint/redundant_cop_disable_directive.rb +4 -2
  32. data/lib/rubocop/cop/lint/regexp_as_condition.rb +6 -0
  33. data/lib/rubocop/cop/lint/safe_navigation_with_empty.rb +1 -1
  34. data/lib/rubocop/cop/metrics/cyclomatic_complexity.rb +35 -3
  35. data/lib/rubocop/cop/metrics/utils/abc_size_calculator.rb +1 -1
  36. data/lib/rubocop/cop/metrics/utils/iterating_block.rb +61 -0
  37. data/lib/rubocop/cop/mixin/configurable_naming.rb +1 -1
  38. data/lib/rubocop/cop/mixin/documentation_comment.rb +2 -2
  39. data/lib/rubocop/cop/mixin/end_keyword_alignment.rb +1 -1
  40. data/lib/rubocop/cop/mixin/first_element_line_break.rb +1 -1
  41. data/lib/rubocop/cop/mixin/multiline_expression_indentation.rb +1 -1
  42. data/lib/rubocop/cop/mixin/parentheses.rb +1 -2
  43. data/lib/rubocop/cop/mixin/preceding_following_alignment.rb +1 -1
  44. data/lib/rubocop/cop/mixin/range_help.rb +1 -1
  45. data/lib/rubocop/cop/mixin/regexp_literal_help.rb +27 -0
  46. data/lib/rubocop/cop/mixin/string_literals_help.rb +1 -1
  47. data/lib/rubocop/cop/mixin/surrounding_space.rb +3 -3
  48. data/lib/rubocop/cop/mixin/trailing_comma.rb +1 -1
  49. data/lib/rubocop/cop/mixin/uncommunicative_name.rb +2 -2
  50. data/lib/rubocop/cop/naming/binary_operator_parameter_name.rb +1 -1
  51. data/lib/rubocop/cop/naming/file_name.rb +1 -3
  52. data/lib/rubocop/cop/naming/heredoc_delimiter_naming.rb +1 -1
  53. data/lib/rubocop/cop/style/bare_percent_literals.rb +1 -1
  54. data/lib/rubocop/cop/style/block_delimiters.rb +2 -4
  55. data/lib/rubocop/cop/style/class_and_module_children.rb +1 -1
  56. data/lib/rubocop/cop/style/command_literal.rb +1 -1
  57. data/lib/rubocop/cop/style/commented_keyword.rb +2 -2
  58. data/lib/rubocop/cop/style/conditional_assignment.rb +1 -1
  59. data/lib/rubocop/cop/style/copyright.rb +3 -3
  60. data/lib/rubocop/cop/style/disable_cops_within_source_code_directive.rb +1 -1
  61. data/lib/rubocop/cop/style/documentation.rb +2 -2
  62. data/lib/rubocop/cop/style/empty_case_condition.rb +8 -6
  63. data/lib/rubocop/cop/style/encoding.rb +1 -1
  64. data/lib/rubocop/cop/style/exponential_notation.rb +2 -2
  65. data/lib/rubocop/cop/style/frozen_string_literal_comment.rb +1 -1
  66. data/lib/rubocop/cop/style/identical_conditional_branches.rb +1 -1
  67. data/lib/rubocop/cop/style/if_inside_else.rb +1 -1
  68. data/lib/rubocop/cop/style/inverse_methods.rb +1 -1
  69. data/lib/rubocop/cop/style/ip_addresses.rb +1 -1
  70. data/lib/rubocop/cop/style/multiline_if_then.rb +1 -1
  71. data/lib/rubocop/cop/style/multiline_ternary_operator.rb +17 -6
  72. data/lib/rubocop/cop/style/nested_ternary_operator.rb +27 -0
  73. data/lib/rubocop/cop/style/next.rb +2 -2
  74. data/lib/rubocop/cop/style/numeric_literal_prefix.rb +2 -2
  75. data/lib/rubocop/cop/style/percent_literal_delimiters.rb +1 -1
  76. data/lib/rubocop/cop/style/redundant_fetch_block.rb +103 -0
  77. data/lib/rubocop/cop/style/redundant_parentheses.rb +1 -1
  78. data/lib/rubocop/cop/style/redundant_percent_q.rb +2 -2
  79. data/lib/rubocop/cop/style/redundant_regexp_character_class.rb +2 -2
  80. data/lib/rubocop/cop/style/redundant_regexp_escape.rb +14 -23
  81. data/lib/rubocop/cop/style/redundant_self.rb +6 -9
  82. data/lib/rubocop/cop/style/sample.rb +1 -1
  83. data/lib/rubocop/cop/style/semicolon.rb +1 -1
  84. data/lib/rubocop/cop/style/struct_inheritance.rb +21 -0
  85. data/lib/rubocop/cop/style/symbol_array.rb +5 -5
  86. data/lib/rubocop/cop/style/ternary_parentheses.rb +1 -1
  87. data/lib/rubocop/cop/style/word_array.rb +1 -1
  88. data/lib/rubocop/cop/style/yoda_condition.rb +18 -1
  89. data/lib/rubocop/cop/util.rb +2 -2
  90. data/lib/rubocop/cop/utils/format_string.rb +1 -1
  91. data/lib/rubocop/formatter/disabled_config_formatter.rb +1 -1
  92. data/lib/rubocop/formatter/formatter_set.rb +1 -1
  93. data/lib/rubocop/name_similarity.rb +6 -0
  94. data/lib/rubocop/path_util.rb +2 -2
  95. data/lib/rubocop/platform.rb +1 -1
  96. data/lib/rubocop/rspec/expect_offense.rb +12 -2
  97. data/lib/rubocop/target_finder.rb +1 -1
  98. data/lib/rubocop/target_ruby.rb +1 -1
  99. data/lib/rubocop/version.rb +1 -1
  100. metadata +11 -2
@@ -123,10 +123,9 @@ module RuboCop
123
123
  # special handling for Action Pack Variants file names like
124
124
  # some_file.xlsx+mobile.axlsx
125
125
  basename = basename.sub('+', '_')
126
- basename =~ (regex || SNAKE_CASE)
126
+ basename.match?(regex || SNAKE_CASE)
127
127
  end
128
128
 
129
- # rubocop:disable Metrics/CyclomaticComplexity
130
129
  def find_class_or_module(node, namespace)
131
130
  return nil unless node
132
131
 
@@ -145,7 +144,6 @@ module RuboCop
145
144
 
146
145
  nil
147
146
  end
148
- # rubocop:enable Metrics/CyclomaticComplexity
149
147
 
150
148
  def match_namespace(node, namespace, expected)
151
149
  match_partial = partial_matcher!(expected)
@@ -42,7 +42,7 @@ module RuboCop
42
42
  return false unless /\w/.match?(delimiters)
43
43
 
44
44
  forbidden_delimiters.none? do |forbidden_delimiter|
45
- delimiters =~ Regexp.new(forbidden_delimiter)
45
+ Regexp.new(forbidden_delimiter).match?(delimiters)
46
46
  end
47
47
  end
48
48
 
@@ -60,7 +60,7 @@ module RuboCop
60
60
  end
61
61
 
62
62
  def requires_percent_q?(source)
63
- style == :percent_q && source =~ /^%[^\w]/
63
+ style == :percent_q && /^%[^\w]/.match?(source)
64
64
  end
65
65
 
66
66
  def requires_bare_percent?(source)
@@ -245,14 +245,13 @@ module RuboCop
245
245
  end
246
246
 
247
247
  def whitespace_before?(range)
248
- range.source_buffer.source[range.begin_pos - 1, 1] =~ /\s/
248
+ /\s/.match?(range.source_buffer.source[range.begin_pos - 1, 1])
249
249
  end
250
250
 
251
251
  def whitespace_after?(range, length = 1)
252
- range.source_buffer.source[range.begin_pos + length, 1] =~ /\s/
252
+ /\s/.match?(range.source_buffer.source[range.begin_pos + length, 1])
253
253
  end
254
254
 
255
- # rubocop:disable Metrics/CyclomaticComplexity
256
255
  def get_blocks(node, &block)
257
256
  case node.type
258
257
  when :block
@@ -270,7 +269,6 @@ module RuboCop
270
269
  node.each_child_node { |child| get_blocks(child, &block) }
271
270
  end
272
271
  end
273
- # rubocop:enable Metrics/CyclomaticComplexity
274
272
 
275
273
  def proper_block_style?(node)
276
274
  return special_method_proper_block_style?(node) if special_method?(node.method_name)
@@ -143,7 +143,7 @@ module RuboCop
143
143
  end
144
144
 
145
145
  def compact_node_name?(node)
146
- node.loc.name.source =~ /::/
146
+ /::/.match?(node.loc.name.source)
147
147
  end
148
148
  end
149
149
  end
@@ -153,7 +153,7 @@ module RuboCop
153
153
  end
154
154
 
155
155
  def contains_backtick?(node)
156
- node_body(node) =~ /`/
156
+ /`/.match?(node_body(node))
157
157
  end
158
158
 
159
159
  def node_body(node)
@@ -55,8 +55,8 @@ module RuboCop
55
55
 
56
56
  def offensive?(comment)
57
57
  line = line(comment)
58
- KEYWORDS.any? { |word| line =~ /^\s*#{word}\s/ } &&
59
- ALLOWED_COMMENTS.none? { |c| line =~ /#\s*#{c}/ }
58
+ KEYWORDS.any? { |word| /^\s*#{word}\s/.match?(line) } &&
59
+ ALLOWED_COMMENTS.none? { |c| /#\s*#{c}/.match?(line) }
60
60
  end
61
61
 
62
62
  def message(comment)
@@ -67,7 +67,7 @@ module RuboCop
67
67
 
68
68
  private
69
69
 
70
- def expand_elsif(node, elsif_branches = [])
70
+ def expand_elsif(node, elsif_branches = []) # rubocop:todo Metrics/CyclomaticComplexity
71
71
  return [] if node.nil? || !node.if_type? || !node.elsif?
72
72
 
73
73
  elsif_branches << node.if_branch
@@ -72,14 +72,14 @@ module RuboCop
72
72
  return false if token_index >= processed_source.tokens.size
73
73
 
74
74
  token = processed_source.tokens[token_index]
75
- token.comment? && token.text =~ /^#!.*$/
75
+ token.comment? && /^#!.*$/.match?(token.text)
76
76
  end
77
77
 
78
78
  def encoding_token?(processed_source, token_index)
79
79
  return false if token_index >= processed_source.tokens.size
80
80
 
81
81
  token = processed_source.tokens[token_index]
82
- token.comment? && token.text =~ /^#.*coding\s?[:=]\s?(?:UTF|utf)-8/
82
+ token.comment? && /^#.*coding\s?[:=]\s?(?:UTF|utf)-8/.match?(token.text)
83
83
  end
84
84
 
85
85
  def notice_found?(processed_source)
@@ -88,7 +88,7 @@ module RuboCop
88
88
  processed_source.each_token do |token|
89
89
  break unless token.comment?
90
90
 
91
- notice_found = !(token.text =~ notice_regexp).nil?
91
+ notice_found = notice_regexp.match?(token.text)
92
92
  break if notice_found
93
93
  end
94
94
  notice_found
@@ -41,7 +41,7 @@ module RuboCop
41
41
  private
42
42
 
43
43
  def rubocop_directive_comment?(comment)
44
- comment.text =~ CommentConfig::COMMENT_DIRECTIVE_REGEXP
44
+ CommentConfig::COMMENT_DIRECTIVE_REGEXP.match?(comment.text)
45
45
  end
46
46
  end
47
47
  end
@@ -104,7 +104,7 @@ module RuboCop
104
104
  end
105
105
 
106
106
  def compact_namespace?(node)
107
- node.loc.name.source =~ /::/
107
+ /::/.match?(node.loc.name.source)
108
108
  end
109
109
 
110
110
  # First checks if the :nodoc: comment is associated with the
@@ -123,7 +123,7 @@ module RuboCop
123
123
  end
124
124
 
125
125
  def nodoc?(comment, require_all = false)
126
- comment.text =~ /^#\s*:nodoc:#{"\s+all\s*$" if require_all}/
126
+ /^#\s*:nodoc:#{"\s+all\s*$" if require_all}/.match?(comment.text)
127
127
  end
128
128
 
129
129
  def nodoc(node)
@@ -43,13 +43,15 @@ module RuboCop
43
43
 
44
44
  def on_case(case_node)
45
45
  return if case_node.condition
46
- return if case_node.when_branches.any? do |when_branch|
47
- when_branch.each_descendant.any?(&:return_type?)
48
- end
49
46
 
50
- if (else_branch = case_node.else_branch)
51
- return if else_branch.return_type? ||
52
- else_branch.each_descendant.any?(&:return_type?)
47
+ branch_bodies = [
48
+ *case_node.when_branches.map(&:body),
49
+ case_node.else_branch
50
+ ].compact
51
+
52
+ return if branch_bodies.any? do |body|
53
+ body.return_type? ||
54
+ body.each_descendant.any?(&:return_type?)
53
55
  end
54
56
 
55
57
  add_offense(case_node, location: :keyword)
@@ -42,7 +42,7 @@ module RuboCop
42
42
  end
43
43
 
44
44
  def encoding_omitable?(line)
45
- line =~ ENCODING_PATTERN
45
+ ENCODING_PATTERN.match?(line)
46
46
  end
47
47
 
48
48
  def encoding_line_number(processed_source)
@@ -69,7 +69,7 @@ module RuboCop
69
69
 
70
70
  def scientific?(node)
71
71
  mantissa, = node.source.split('e')
72
- mantissa =~ /^-?[1-9](\.\d*[0-9])?$/
72
+ /^-?[1-9](\.\d*[0-9])?$/.match?(mantissa)
73
73
  end
74
74
 
75
75
  def engineering?(node)
@@ -85,7 +85,7 @@ module RuboCop
85
85
 
86
86
  def integral(node)
87
87
  mantissa, = node.source.split('e')
88
- mantissa =~ /^-?[1-9](\d*[1-9])?$/
88
+ /^-?[1-9](\d*[1-9])?$/.match?(mantissa)
89
89
  end
90
90
 
91
91
  def offense?(node)
@@ -148,7 +148,7 @@ module RuboCop
148
148
  end
149
149
 
150
150
  next_token = processed_source.tokens[token_number]
151
- token = next_token if next_token && next_token.text =~ Encoding::ENCODING_PATTERN
151
+ token = next_token if Encoding::ENCODING_PATTERN.match?(next_token&.text)
152
152
 
153
153
  token
154
154
  end
@@ -81,7 +81,7 @@ module RuboCop
81
81
 
82
82
  private
83
83
 
84
- def check_branches(branches)
84
+ def check_branches(branches) # rubocop:todo Metrics/CyclomaticComplexity
85
85
  # return if any branch is empty. An empty branch can be an `if`
86
86
  # without an `else` or a branch that contains only comments.
87
87
  return if branches.any?(&:nil?)
@@ -61,7 +61,7 @@ module RuboCop
61
61
  class IfInsideElse < Cop
62
62
  MSG = 'Convert `if` nested inside `else` to `elsif`.'
63
63
 
64
- def on_if(node)
64
+ def on_if(node) # rubocop:todo Metrics/CyclomaticComplexity
65
65
  return if node.ternary? || node.unless?
66
66
 
67
67
  else_branch = node.else_branch
@@ -178,7 +178,7 @@ module RuboCop
178
178
  end
179
179
 
180
180
  def camel_case_constant?(node)
181
- node.const_type? && node.source =~ CAMEL_CASE
181
+ node.const_type? && CAMEL_CASE.match?(node.source)
182
182
  end
183
183
 
184
184
  def dot_range(loc)
@@ -34,7 +34,7 @@ module RuboCop
34
34
  # shortcut out if the string does not look like an IP address
35
35
  return false unless could_be_ip?(contents)
36
36
 
37
- contents =~ ::Resolv::IPv4::Regex || contents =~ ::Resolv::IPv6::Regex
37
+ ::Resolv::IPv4::Regex.match?(contents) || ::Resolv::IPv6::Regex.match?(contents)
38
38
  end
39
39
 
40
40
  # Dummy implementation of method in ConfigurableEnforcedStyle that is
@@ -42,7 +42,7 @@ module RuboCop
42
42
  private
43
43
 
44
44
  def non_modifier_then?(node)
45
- node.loc.begin && node.loc.begin.source_line =~ NON_MODIFIER_THEN
45
+ NON_MODIFIER_THEN.match?(node.loc.begin&.source_line)
46
46
  end
47
47
  end
48
48
  end
@@ -17,12 +17,11 @@ module RuboCop
17
17
  #
18
18
  # # good
19
19
  # a = cond ? b : c
20
- # a =
21
- # if cond
22
- # b
23
- # else
24
- # c
25
- # end
20
+ # a = if cond
21
+ # b
22
+ # else
23
+ # c
24
+ # end
26
25
  class MultilineTernaryOperator < Cop
27
26
  MSG = 'Avoid multi-line ternary operators, ' \
28
27
  'use `if` or `unless` instead.'
@@ -32,6 +31,18 @@ module RuboCop
32
31
 
33
32
  add_offense(node)
34
33
  end
34
+
35
+ def autocorrect(node)
36
+ lambda do |corrector|
37
+ corrector.replace(node, <<~RUBY.chop)
38
+ if #{node.condition.source}
39
+ #{node.if_branch.source}
40
+ else
41
+ #{node.else_branch.source}
42
+ end
43
+ RUBY
44
+ end
45
+ end
35
46
  end
36
47
  end
37
48
  end
@@ -26,6 +26,33 @@ module RuboCop
26
26
  add_offense(nested_ternary)
27
27
  end
28
28
  end
29
+
30
+ def autocorrect(node)
31
+ if_node = if_node(node)
32
+
33
+ lambda do |corrector|
34
+ corrector.replace(if_node, <<~RUBY.chop)
35
+ if #{if_node.condition.source}
36
+ #{remove_parentheses(if_node.if_branch.source)}
37
+ else
38
+ #{if_node.else_branch.source}
39
+ end
40
+ RUBY
41
+ end
42
+ end
43
+
44
+ private
45
+
46
+ def if_node(node)
47
+ node = node.parent
48
+ return node if node.if_type?
49
+
50
+ if_node(node)
51
+ end
52
+
53
+ def remove_parentheses(source)
54
+ source.gsub(/\A\(/, '').gsub(/\)\z/, '')
55
+ end
29
56
  end
30
57
  end
31
58
  end
@@ -191,7 +191,7 @@ module RuboCop
191
191
  end
192
192
 
193
193
  def end_followed_by_whitespace_only?(source_buffer, end_pos)
194
- source_buffer.source[end_pos..-1] =~ /\A\s*$/
194
+ /\A\s*$/.match?(source_buffer.source[end_pos..-1])
195
195
  end
196
196
 
197
197
  def reindentable_lines(node)
@@ -201,7 +201,7 @@ module RuboCop
201
201
  lines = (node.source_range.line + 1)...node.loc.end.line
202
202
  lines = lines.to_a - heredoc_lines(node)
203
203
  # Skip blank lines
204
- lines.reject { |lineno| buffer.source_line(lineno) =~ /\A\s*\z/ }
204
+ lines.reject { |lineno| /\A\s*\z/.match?(buffer.source_line(lineno)) }
205
205
  end
206
206
 
207
207
  # Adjust indentation of `lines` to match `node`
@@ -77,9 +77,9 @@ module RuboCop
77
77
  end
78
78
 
79
79
  def octal_literal_type(literal)
80
- if literal =~ OCTAL_ZERO_ONLY_REGEX && octal_zero_only?
80
+ if OCTAL_ZERO_ONLY_REGEX.match?(literal) && octal_zero_only?
81
81
  :octal_zero_only
82
- elsif literal =~ OCTAL_REGEX && !octal_zero_only?
82
+ elsif OCTAL_REGEX.match?(literal) && !octal_zero_only?
83
83
  :octal
84
84
  end
85
85
  end
@@ -102,7 +102,7 @@ module RuboCop
102
102
  delimiters_regexp = Regexp.union(delimiters)
103
103
  node
104
104
  .children.map { |n| string_source(n) }.compact
105
- .any? { |s| delimiters_regexp =~ s }
105
+ .any? { |s| delimiters_regexp.match?(s) }
106
106
  end
107
107
 
108
108
  def string_source(node)
@@ -0,0 +1,103 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Style
6
+ # This cop identifies places where `fetch(key) { value }`
7
+ # can be replaced by `fetch(key, value)`.
8
+ #
9
+ # In such cases `fetch(key, value)` method is faster
10
+ # than `fetch(key) { value }`.
11
+ #
12
+ # @example SafeForConstants: false (default)
13
+ # # bad
14
+ # hash.fetch(:key) { 5 }
15
+ # hash.fetch(:key) { true }
16
+ # hash.fetch(:key) { nil }
17
+ # array.fetch(5) { :value }
18
+ # ENV.fetch(:key) { 'value' }
19
+ #
20
+ # # good
21
+ # hash.fetch(:key, 5)
22
+ # hash.fetch(:key, true)
23
+ # hash.fetch(:key, nil)
24
+ # array.fetch(5, :value)
25
+ # ENV.fetch(:key, 'value')
26
+ #
27
+ # @example SafeForConstants: true
28
+ # # bad
29
+ # ENV.fetch(:key) { VALUE }
30
+ #
31
+ # # good
32
+ # ENV.fetch(:key, VALUE)
33
+ #
34
+ class RedundantFetchBlock < Cop
35
+ include FrozenStringLiteral
36
+ include RangeHelp
37
+
38
+ MSG = 'Use `%<good>s` instead of `%<bad>s`.'
39
+
40
+ def_node_matcher :redundant_fetch_block_candidate?, <<~PATTERN
41
+ (block
42
+ $(send _ :fetch _)
43
+ (args)
44
+ ${#basic_literal? const_type?})
45
+ PATTERN
46
+
47
+ def on_block(node)
48
+ redundant_fetch_block_candidate?(node) do |send, body|
49
+ return if body.const_type? && !check_for_constant?
50
+ return if body.str_type? && !check_for_string?
51
+
52
+ range = fetch_range(send, node)
53
+ good = build_good_method(send, body)
54
+ bad = build_bad_method(send, body)
55
+
56
+ add_offense(
57
+ node,
58
+ location: range,
59
+ message: format(MSG, good: good, bad: bad)
60
+ )
61
+ end
62
+ end
63
+
64
+ def autocorrect(node)
65
+ redundant_fetch_block_candidate?(node) do |send, body|
66
+ lambda do |corrector|
67
+ receiver, _, key = send.children
68
+ corrector.replace(node, "#{receiver.source}.fetch(#{key.source}, #{body.source})")
69
+ end
70
+ end
71
+ end
72
+
73
+ private
74
+
75
+ def basic_literal?(node)
76
+ node.basic_literal?
77
+ end
78
+
79
+ def fetch_range(send, node)
80
+ range_between(send.loc.selector.begin_pos, node.loc.end.end_pos)
81
+ end
82
+
83
+ def build_good_method(send, body)
84
+ key = send.children[2].source
85
+ "fetch(#{key}, #{body.source})"
86
+ end
87
+
88
+ def build_bad_method(send, body)
89
+ key = send.children[2].source
90
+ "fetch(#{key}) { #{body.source} }"
91
+ end
92
+
93
+ def check_for_constant?
94
+ cop_config['SafeForConstants']
95
+ end
96
+
97
+ def check_for_string?
98
+ frozen_string_literals_enabled?
99
+ end
100
+ end
101
+ end
102
+ end
103
+ end