rubocop 1.6.1 → 1.9.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (120) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE.txt +1 -1
  3. data/README.md +4 -3
  4. data/config/default.yml +145 -19
  5. data/lib/rubocop.rb +16 -1
  6. data/lib/rubocop/cli/command/auto_genenerate_config.rb +5 -4
  7. data/lib/rubocop/comment_config.rb +6 -6
  8. data/lib/rubocop/config.rb +13 -7
  9. data/lib/rubocop/config_loader.rb +11 -14
  10. data/lib/rubocop/config_loader_resolver.rb +21 -4
  11. data/lib/rubocop/config_obsoletion.rb +5 -3
  12. data/lib/rubocop/config_store.rb +12 -1
  13. data/lib/rubocop/cop/base.rb +2 -1
  14. data/lib/rubocop/cop/exclude_limit.rb +26 -0
  15. data/lib/rubocop/cop/gemspec/required_ruby_version.rb +3 -2
  16. data/lib/rubocop/cop/generator.rb +1 -3
  17. data/lib/rubocop/cop/internal_affairs.rb +6 -1
  18. data/lib/rubocop/cop/internal_affairs/empty_line_between_expect_offense_and_correction.rb +68 -0
  19. data/lib/rubocop/cop/internal_affairs/example_description.rb +89 -0
  20. data/lib/rubocop/cop/internal_affairs/redundant_described_class_as_subject.rb +61 -0
  21. data/lib/rubocop/cop/internal_affairs/redundant_let_rubocop_config_new.rb +64 -0
  22. data/lib/rubocop/cop/internal_affairs/style_detected_api_use.rb +145 -0
  23. data/lib/rubocop/cop/layout/class_structure.rb +7 -2
  24. data/lib/rubocop/cop/layout/empty_line_between_defs.rb +56 -20
  25. data/lib/rubocop/cop/layout/first_argument_indentation.rb +16 -2
  26. data/lib/rubocop/cop/layout/heredoc_argument_closing_parenthesis.rb +14 -0
  27. data/lib/rubocop/cop/layout/line_length.rb +2 -1
  28. data/lib/rubocop/cop/layout/multiline_operation_indentation.rb +2 -2
  29. data/lib/rubocop/cop/layout/rescue_ensure_alignment.rb +3 -10
  30. data/lib/rubocop/cop/layout/space_around_equals_in_parameter_default.rb +1 -0
  31. data/lib/rubocop/cop/layout/space_before_block_braces.rb +2 -0
  32. data/lib/rubocop/cop/layout/space_before_brackets.rb +67 -0
  33. data/lib/rubocop/cop/layout/space_inside_block_braces.rb +13 -10
  34. data/lib/rubocop/cop/layout/space_inside_hash_literal_braces.rb +2 -2
  35. data/lib/rubocop/cop/lint/ambiguous_assignment.rb +59 -0
  36. data/lib/rubocop/cop/lint/binary_operator_with_identical_operands.rb +7 -2
  37. data/lib/rubocop/cop/lint/deprecated_constants.rb +80 -0
  38. data/lib/rubocop/cop/lint/duplicate_branch.rb +64 -2
  39. data/lib/rubocop/cop/lint/lambda_without_literal_block.rb +44 -0
  40. data/lib/rubocop/cop/lint/non_deterministic_require_order.rb +10 -6
  41. data/lib/rubocop/cop/lint/number_conversion.rb +41 -6
  42. data/lib/rubocop/cop/lint/numbered_parameter_assignment.rb +47 -0
  43. data/lib/rubocop/cop/lint/or_assignment_to_constant.rb +39 -0
  44. data/lib/rubocop/cop/lint/redundant_cop_disable_directive.rb +2 -1
  45. data/lib/rubocop/cop/lint/redundant_dir_glob_sort.rb +50 -0
  46. data/lib/rubocop/cop/lint/redundant_splat_expansion.rb +50 -17
  47. data/lib/rubocop/cop/lint/shadowed_exception.rb +1 -11
  48. data/lib/rubocop/cop/lint/symbol_conversion.rb +103 -0
  49. data/lib/rubocop/cop/lint/triple_quotes.rb +71 -0
  50. data/lib/rubocop/cop/lint/unreachable_loop.rb +17 -0
  51. data/lib/rubocop/cop/message_annotator.rb +4 -1
  52. data/lib/rubocop/cop/metrics/block_nesting.rb +2 -2
  53. data/lib/rubocop/cop/metrics/parameter_lists.rb +5 -2
  54. data/lib/rubocop/cop/metrics/utils/code_length_calculator.rb +1 -1
  55. data/lib/rubocop/cop/mixin/allowed_identifiers.rb +18 -0
  56. data/lib/rubocop/cop/mixin/check_line_breakable.rb +5 -0
  57. data/lib/rubocop/cop/mixin/code_length.rb +3 -1
  58. data/lib/rubocop/cop/mixin/comments_help.rb +1 -11
  59. data/lib/rubocop/cop/mixin/configurable_max.rb +1 -0
  60. data/lib/rubocop/cop/mixin/first_element_line_break.rb +1 -1
  61. data/lib/rubocop/cop/mixin/method_complexity.rb +3 -1
  62. data/lib/rubocop/cop/mixin/uncommunicative_name.rb +5 -1
  63. data/lib/rubocop/cop/naming/memoized_instance_variable_name.rb +59 -5
  64. data/lib/rubocop/cop/naming/rescued_exceptions_variable_name.rb +38 -5
  65. data/lib/rubocop/cop/naming/variable_name.rb +2 -0
  66. data/lib/rubocop/cop/naming/variable_number.rb +2 -9
  67. data/lib/rubocop/cop/registry.rb +10 -0
  68. data/lib/rubocop/cop/severity.rb +3 -3
  69. data/lib/rubocop/cop/style/access_modifier_declarations.rb +3 -1
  70. data/lib/rubocop/cop/style/ascii_comments.rb +1 -1
  71. data/lib/rubocop/cop/style/collection_methods.rb +14 -1
  72. data/lib/rubocop/cop/style/commented_keyword.rb +22 -5
  73. data/lib/rubocop/cop/style/disable_cops_within_source_code_directive.rb +49 -9
  74. data/lib/rubocop/cop/style/empty_literal.rb +6 -2
  75. data/lib/rubocop/cop/style/endless_method.rb +102 -0
  76. data/lib/rubocop/cop/style/eval_with_location.rb +63 -34
  77. data/lib/rubocop/cop/style/explicit_block_argument.rb +10 -0
  78. data/lib/rubocop/cop/style/float_division.rb +3 -0
  79. data/lib/rubocop/cop/style/for.rb +2 -0
  80. data/lib/rubocop/cop/style/format_string_token.rb +18 -2
  81. data/lib/rubocop/cop/style/hash_except.rb +95 -0
  82. data/lib/rubocop/cop/style/hash_like_case.rb +2 -1
  83. data/lib/rubocop/cop/style/if_inside_else.rb +22 -10
  84. data/lib/rubocop/cop/style/if_with_boolean_literal_branches.rb +120 -0
  85. data/lib/rubocop/cop/style/keyword_parameters_order.rb +12 -2
  86. data/lib/rubocop/cop/style/lambda_call.rb +2 -1
  87. data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +7 -0
  88. data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +16 -6
  89. data/lib/rubocop/cop/style/method_def_parentheses.rb +7 -0
  90. data/lib/rubocop/cop/style/multiline_method_signature.rb +26 -1
  91. data/lib/rubocop/cop/style/multiline_when_then.rb +3 -1
  92. data/lib/rubocop/cop/style/mutable_constant.rb +13 -3
  93. data/lib/rubocop/cop/style/nested_parenthesized_calls.rb +4 -0
  94. data/lib/rubocop/cop/style/nil_comparison.rb +3 -0
  95. data/lib/rubocop/cop/style/non_nil_check.rb +23 -13
  96. data/lib/rubocop/cop/style/numeric_literals.rb +6 -9
  97. data/lib/rubocop/cop/style/numeric_predicate.rb +1 -1
  98. data/lib/rubocop/cop/style/raise_args.rb +5 -2
  99. data/lib/rubocop/cop/style/redundant_argument.rb +7 -1
  100. data/lib/rubocop/cop/style/redundant_freeze.rb +8 -4
  101. data/lib/rubocop/cop/style/redundant_return.rb +1 -1
  102. data/lib/rubocop/cop/style/single_line_methods.rb +36 -2
  103. data/lib/rubocop/cop/style/sole_nested_conditional.rb +29 -5
  104. data/lib/rubocop/cop/style/string_concatenation.rb +1 -1
  105. data/lib/rubocop/cop/style/symbol_proc.rb +5 -4
  106. data/lib/rubocop/cop/style/ternary_parentheses.rb +1 -1
  107. data/lib/rubocop/cop/style/while_until_modifier.rb +2 -4
  108. data/lib/rubocop/cop/util.rb +3 -1
  109. data/lib/rubocop/formatter/git_hub_actions_formatter.rb +1 -0
  110. data/lib/rubocop/formatter/simple_text_formatter.rb +2 -1
  111. data/lib/rubocop/magic_comment.rb +30 -1
  112. data/lib/rubocop/options.rb +10 -10
  113. data/lib/rubocop/rspec/cop_helper.rb +0 -4
  114. data/lib/rubocop/rspec/expect_offense.rb +37 -22
  115. data/lib/rubocop/runner.rb +17 -1
  116. data/lib/rubocop/target_finder.rb +4 -2
  117. data/lib/rubocop/target_ruby.rb +47 -11
  118. data/lib/rubocop/util.rb +16 -0
  119. data/lib/rubocop/version.rb +8 -2
  120. metadata +27 -7
@@ -70,6 +70,7 @@ module RuboCop
70
70
  return unless outermost_send.loc.end
71
71
  return unless heredoc_arg.first_line != outermost_send.loc.end.line
72
72
  return if subsequent_closing_parentheses_in_same_line?(outermost_send)
73
+ return if exist_argument_between_heredoc_end_and_closing_parentheses?(node)
73
74
 
74
75
  add_offense(outermost_send.loc.end) do |corrector|
75
76
  autocorrect(corrector, outermost_send)
@@ -215,6 +216,19 @@ module RuboCop
215
216
  end
216
217
  end
217
218
 
219
+ def exist_argument_between_heredoc_end_and_closing_parentheses?(node)
220
+ return false unless (heredoc_end = find_most_bottom_of_heredoc_end(node.arguments))
221
+
222
+ heredoc_end < node.loc.end.begin_pos &&
223
+ range_between(heredoc_end, node.loc.end.begin_pos).source.strip != ''
224
+ end
225
+
226
+ def find_most_bottom_of_heredoc_end(arguments)
227
+ arguments.map do |argument|
228
+ argument.loc.heredoc_end.end_pos if argument.loc.respond_to?(:heredoc_end)
229
+ end.compact.max
230
+ end
231
+
218
232
  # Internal trailing comma helpers.
219
233
 
220
234
  def remove_internal_trailing_comma(node, corrector)
@@ -60,12 +60,13 @@ module RuboCop
60
60
  # }
61
61
  class LineLength < Base
62
62
  include CheckLineBreakable
63
- include ConfigurableMax
64
63
  include IgnoredPattern
65
64
  include RangeHelp
66
65
  include LineLengthHelp
67
66
  extend AutoCorrector
68
67
 
68
+ exclude_limit 'Max'
69
+
69
70
  MSG = 'Line is too long. [%<length>d/%<max>d]'
70
71
 
71
72
  def on_block(node)
@@ -16,14 +16,14 @@ module RuboCop
16
16
  # if a +
17
17
  # b
18
18
  # something &&
19
- # something_else
19
+ # something_else
20
20
  # end
21
21
  #
22
22
  # # good
23
23
  # if a +
24
24
  # b
25
25
  # something &&
26
- # something_else
26
+ # something_else
27
27
  # end
28
28
  #
29
29
  # @example EnforcedStyle: indented
@@ -191,16 +191,9 @@ module RuboCop
191
191
  end
192
192
 
193
193
  def begin_end_alignment_style
194
- # FIXME: Workaround for pending status for `Layout/BeginEndAlignment` cop
195
- # When RuboCop 1.0 is released, please replace it with the following condition.
196
- #
197
- # config.for_cop('Layout/BeginEndAlignment')['Enabled'] &&
198
- # config.for_cop('Layout/BeginEndAlignment')['EnforcedStyleAlignWith']
199
- if config.for_all_cops['NewCops'] == 'enable' ||
200
- config.for_cop('Layout/BeginEndAlignment')['Enabled'] &&
201
- config.for_cop('Layout/BeginEndAlignment')['Enabled'] != 'pending'
202
- config.for_cop('Layout/BeginEndAlignment')['EnforcedStyleAlignWith']
203
- end
194
+ begin_end_alignment_conf = config.for_cop('Layout/BeginEndAlignment')
195
+
196
+ begin_end_alignment_conf['Enabled'] && begin_end_alignment_conf['EnforcedStyleAlignWith']
204
197
  end
205
198
  end
206
199
  end
@@ -60,6 +60,7 @@ module RuboCop
60
60
 
61
61
  add_offense(range) do |corrector|
62
62
  autocorrect(corrector, range)
63
+ opposite_style_detected
63
64
  end
64
65
  end
65
66
 
@@ -106,6 +106,7 @@ module RuboCop
106
106
  def space_missing(left_brace)
107
107
  add_offense(left_brace, message: MISSING_MSG) do |corrector|
108
108
  autocorrect(corrector, left_brace)
109
+ opposite_style_detected
109
110
  end
110
111
  end
111
112
 
@@ -114,6 +115,7 @@ module RuboCop
114
115
 
115
116
  add_offense(space, message: DETECTED_MSG) do |corrector|
116
117
  autocorrect(corrector, space)
118
+ opposite_style_detected
117
119
  end
118
120
  end
119
121
 
@@ -0,0 +1,67 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Layout
6
+ # Checks for space between the name of a receiver and a left
7
+ # brackets.
8
+ #
9
+ # @example
10
+ #
11
+ # # bad
12
+ # collection [index_or_key]
13
+ #
14
+ # # good
15
+ # collection[index_or_key]
16
+ #
17
+ class SpaceBeforeBrackets < Base
18
+ include RangeHelp
19
+ extend AutoCorrector
20
+
21
+ MSG = 'Remove the space before the opening brackets.'
22
+
23
+ def on_send(node)
24
+ return unless (first_argument = node.first_argument)
25
+
26
+ begin_pos = first_argument.source_range.begin_pos
27
+ return unless (range = offense_range(node, begin_pos))
28
+
29
+ register_offense(range)
30
+ end
31
+
32
+ private
33
+
34
+ def offense_range(node, begin_pos)
35
+ if reference_variable_with_brackets?(node)
36
+ receiver_end_pos = node.receiver.source_range.end_pos
37
+ selector_begin_pos = node.loc.selector.begin_pos
38
+ return if receiver_end_pos >= selector_begin_pos
39
+
40
+ range_between(receiver_end_pos, selector_begin_pos)
41
+ elsif node.method?(:[]=)
42
+ offense_range_for_assignment(node, begin_pos)
43
+ end
44
+ end
45
+
46
+ def offense_range_for_assignment(node, begin_pos)
47
+ end_pos = node.receiver.source_range.end_pos
48
+
49
+ return if begin_pos - end_pos == 1 ||
50
+ (range = range_between(end_pos, begin_pos - 1)).source == '['
51
+
52
+ range
53
+ end
54
+
55
+ def register_offense(range)
56
+ add_offense(range) do |corrector|
57
+ corrector.remove(range)
58
+ end
59
+ end
60
+
61
+ def reference_variable_with_brackets?(node)
62
+ node.receiver&.variable? && node.method?(:[]) && node.arguments.size == 1
63
+ end
64
+ end
65
+ end
66
+ end
67
+ end
@@ -111,7 +111,8 @@ module RuboCop
111
111
  braces_with_contents_inside(node, inner)
112
112
  elsif style_for_empty_braces == :no_space
113
113
  offense(range.begin_pos, range.end_pos,
114
- 'Space inside empty braces detected.')
114
+ 'Space inside empty braces detected.',
115
+ 'EnforcedStyleForEmptyBraces')
115
116
  end
116
117
  end
117
118
  end
@@ -120,7 +121,8 @@ module RuboCop
120
121
  return if style_for_empty_braces != :space
121
122
 
122
123
  offense(left_brace.begin_pos, right_brace.end_pos,
123
- 'Space missing inside empty braces.')
124
+ 'Space missing inside empty braces.',
125
+ 'EnforcedStyleForEmptyBraces')
124
126
  end
125
127
 
126
128
  def braces_with_contents_inside(node, inner)
@@ -164,9 +166,9 @@ module RuboCop
164
166
  if left_brace.end_pos == args_delimiter.begin_pos &&
165
167
  cop_config['SpaceBeforeBlockParameters']
166
168
  offense(left_brace.begin_pos, args_delimiter.end_pos,
167
- 'Space between { and | missing.') do
168
- opposite_style_detected
169
- end
169
+ 'Space between { and | missing.')
170
+ else
171
+ correct_style_detected
170
172
  end
171
173
  else
172
174
  # We indicate the position after the left brace. Otherwise it's
@@ -179,11 +181,11 @@ module RuboCop
179
181
 
180
182
  def space_inside_left_brace(left_brace, args_delimiter)
181
183
  if pipe?(args_delimiter)
182
- unless cop_config['SpaceBeforeBlockParameters']
184
+ if cop_config['SpaceBeforeBlockParameters']
185
+ correct_style_detected
186
+ else
183
187
  offense(left_brace.end_pos, args_delimiter.begin_pos,
184
- 'Space between { and | detected.') do
185
- opposite_style_detected
186
- end
188
+ 'Space between { and | detected.')
187
189
  end
188
190
  else
189
191
  brace_with_space = range_with_surrounding_space(range: left_brace,
@@ -220,7 +222,7 @@ module RuboCop
220
222
  end
221
223
  end
222
224
 
223
- def offense(begin_pos, end_pos, msg)
225
+ def offense(begin_pos, end_pos, msg, style_param = 'EnforcedStyle')
224
226
  range = range_between(begin_pos, end_pos)
225
227
  add_offense(range, message: msg) do |corrector|
226
228
  case range.source
@@ -229,6 +231,7 @@ module RuboCop
229
231
  when '{|' then corrector.replace(range, '{ |')
230
232
  else corrector.insert_before(range, ' ')
231
233
  end
234
+ opposite_style_detected if style_param == 'EnforcedStyle'
232
235
  end
233
236
  end
234
237
 
@@ -112,13 +112,13 @@ module RuboCop
112
112
 
113
113
  def incorrect_style_detected(token1, token2,
114
114
  expect_space, is_empty_braces)
115
- return unless ambiguous_or_unexpected_style_detected(style, token1.text == token2.text)
116
-
117
115
  brace = (token1.text == '{' ? token1 : token2).pos
118
116
  range = expect_space ? brace : space_range(brace)
117
+ detected_style = expect_space ? 'no_space' : 'space'
119
118
 
120
119
  add_offense(range, message: message(brace, is_empty_braces, expect_space)) do |corrector|
121
120
  autocorrect(corrector, range)
121
+ ambiguous_or_unexpected_style_detected(detected_style, token1.text == token2.text)
122
122
  end
123
123
  end
124
124
 
@@ -0,0 +1,59 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Lint
6
+ # This cop checks for mistyped shorthand assignments.
7
+ #
8
+ # @example
9
+ # # bad
10
+ # x =- y
11
+ # x =+ y
12
+ # x =* y
13
+ # x =! y
14
+ #
15
+ # # good
16
+ # x -= y # or x = -y
17
+ # x += y # or x = +y
18
+ # x *= y # or x = *y
19
+ # x != y # or x = !y
20
+ #
21
+ class AmbiguousAssignment < Base
22
+ include RangeHelp
23
+
24
+ MSG = 'Suspicious assignment detected. Did you mean `%<op>s`?'
25
+
26
+ SIMPLE_ASSIGNMENT_TYPES = %i[lvasgn ivasgn cvasgn gvasgn casgn].freeze
27
+
28
+ MISTAKES = {
29
+ '=-' => '-=',
30
+ '=+' => '+=',
31
+ '=*' => '*=',
32
+ '=!' => '!='
33
+ }.freeze
34
+
35
+ def on_asgn(node)
36
+ return unless (rhs = rhs(node))
37
+
38
+ range = range_between(node.loc.operator.end_pos - 1, rhs.source_range.begin_pos + 1)
39
+ source = range.source
40
+ return unless MISTAKES.key?(source)
41
+
42
+ add_offense(range, message: format(MSG, op: MISTAKES[source]))
43
+ end
44
+
45
+ SIMPLE_ASSIGNMENT_TYPES.each { |asgn_type| alias_method :"on_#{asgn_type}", :on_asgn }
46
+
47
+ private
48
+
49
+ def rhs(node)
50
+ if node.casgn_type?
51
+ node.children[2]
52
+ else
53
+ node.children[1]
54
+ end
55
+ end
56
+ end
57
+ end
58
+ end
59
+ end
@@ -17,6 +17,7 @@ module RuboCop
17
17
  #
18
18
  # @example
19
19
  # # bad
20
+ # x / x
20
21
  # x.top >= x.top
21
22
  #
22
23
  # if a.x != 0 && a.x != 0
@@ -27,15 +28,19 @@ module RuboCop
27
28
  # left_child || left_child
28
29
  # end
29
30
  #
31
+ # # good
32
+ # x + x
33
+ # 1 << 1
34
+ #
30
35
  class BinaryOperatorWithIdenticalOperands < Base
31
36
  MSG = 'Binary operator `%<op>s` has identical operands.'
32
- MATH_OPERATORS = %i[+ - * / % ** << >> | ^].to_set.freeze
37
+ ALLOWED_MATH_OPERATORS = %i[+ * ** << >>].to_set.freeze
33
38
 
34
39
  def on_send(node)
35
40
  return unless node.binary_operation?
36
41
 
37
42
  lhs, operation, rhs = *node
38
- return if MATH_OPERATORS.include?(node.method_name) && lhs.basic_literal?
43
+ return if ALLOWED_MATH_OPERATORS.include?(node.method_name)
39
44
 
40
45
  add_offense(node, message: format(MSG, op: operation)) if lhs == rhs
41
46
  end
@@ -0,0 +1,80 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Lint
6
+ # This cop checks for deprecated constants.
7
+ #
8
+ # It has `DeprecatedConstants` config. If there is an alternative method, you can set
9
+ # alternative value as `Alternative`. And you can set the deprecated version as
10
+ # `DeprecatedVersion`. These options can be omitted if they are not needed.
11
+ #
12
+ # DeprecatedConstants:
13
+ # 'DEPRECATED_CONSTANT':
14
+ # Alternative: 'alternative_value'
15
+ # DeprecatedVersion: 'deprecated_version'
16
+ #
17
+ # By default, `NIL`, `TRUE`, `FALSE` and `Random::DEFAULT` are configured.
18
+ #
19
+ # @example
20
+ #
21
+ # # bad
22
+ # NIL
23
+ # TRUE
24
+ # FALSE
25
+ # Random::DEFAULT # Return value of Ruby 2 is `Random` instance, Ruby 3.0 is `Random` class.
26
+ #
27
+ # # good
28
+ # nil
29
+ # true
30
+ # false
31
+ # Random.new # `::DEFAULT` has been deprecated in Ruby 3, `.new` is compatible with Ruby 2.
32
+ #
33
+ class DeprecatedConstants < Base
34
+ extend AutoCorrector
35
+
36
+ SUGGEST_GOOD_MSG = 'Use `%<good>s` instead of `%<bad>s`%<deprecated_message>s.'
37
+ DO_NOT_USE_MSG = 'Do not use `%<bad>s`%<deprecated_message>s.'
38
+
39
+ def on_const(node)
40
+ # FIXME: Workaround for "`undefined method `expression' for nil:NilClass`" when processing
41
+ # `__ENCODING__`. It is better to be able to work without this condition.
42
+ # Maybe further investigation of RuboCop AST will lead to an essential solution.
43
+ return unless node.loc
44
+
45
+ constant = node.absolute? ? consntant_name(node, node.short_name.to_s) : node.source
46
+ return unless (deprecated_constant = deprecated_constants[constant])
47
+
48
+ alternative = deprecated_constant['Alternative']
49
+ version = deprecated_constant['DeprecatedVersion']
50
+
51
+ add_offense(node, message: message(alternative, node.source, version)) do |corrector|
52
+ corrector.replace(node, alternative)
53
+ end
54
+ end
55
+
56
+ private
57
+
58
+ def consntant_name(node, nested_constant_name)
59
+ return nested_constant_name unless node.namespace.const_type?
60
+
61
+ consntant_name(node.namespace, "#{node.namespace.short_name}::#{nested_constant_name}")
62
+ end
63
+
64
+ def message(good, bad, deprecated_version)
65
+ deprecated_message = ", deprecated since Ruby #{deprecated_version}" if deprecated_version
66
+
67
+ if good
68
+ format(SUGGEST_GOOD_MSG, good: good, bad: bad, deprecated_message: deprecated_message)
69
+ else
70
+ format(DO_NOT_USE_MSG, bad: bad, deprecated_message: deprecated_message)
71
+ end
72
+ end
73
+
74
+ def deprecated_constants
75
+ cop_config.fetch('DeprecatedConstants', {})
76
+ end
77
+ end
78
+ end
79
+ end
80
+ end
@@ -6,6 +6,15 @@ module RuboCop
6
6
  # This cop checks that there are no repeated bodies
7
7
  # within `if/unless`, `case-when` and `rescue` constructs.
8
8
  #
9
+ # With `IgnoreLiteralBranches: true`, branches are not registered
10
+ # as offenses if they return a basic literal value (string, symbol,
11
+ # integer, float, rational, complex, `true`, `false`, or `nil`), or
12
+ # return an array, hash, regexp or range that only contains one of
13
+ # the above basic literal values.
14
+ #
15
+ # With `IgnoreConstantBranches: true`, branches are not registered
16
+ # as offenses if they return a constant value.
17
+ #
9
18
  # @example
10
19
  # # bad
11
20
  # if foo
@@ -56,14 +65,33 @@ module RuboCop
56
65
  # handle_error
57
66
  # end
58
67
  #
68
+ # @example IgnoreLiteralBranches: true
69
+ # # good
70
+ # case size
71
+ # when "small" then 100
72
+ # when "medium" then 250
73
+ # when "large" then 1000
74
+ # else 250
75
+ # end
76
+ #
77
+ # @example IgnoreLiteralBranches: true
78
+ # # good
79
+ # case size
80
+ # when "small" then SMALL_SIZE
81
+ # when "medium" then MEDIUM_SIZE
82
+ # when "large" then LARGE_SIZE
83
+ # else MEDIUM_SIZE
84
+ # end
85
+ #
59
86
  class DuplicateBranch < Base
60
87
  include RescueNode
61
88
 
62
89
  MSG = 'Duplicate branch body detected.'
63
90
 
64
91
  def on_branching_statement(node)
65
- branches = node.branches.compact
66
- branches.each_with_object(Set.new) do |branch, previous|
92
+ branches(node).each_with_object(Set.new) do |branch, previous|
93
+ next unless consider_branch?(branch)
94
+
67
95
  add_offense(offense_range(branch)) unless previous.add?(branch)
68
96
  end
69
97
  end
@@ -87,6 +115,40 @@ module RuboCop
87
115
  parent.source_range
88
116
  end
89
117
  end
118
+
119
+ def branches(node)
120
+ node.branches.compact
121
+ end
122
+
123
+ def consider_branch?(branch)
124
+ return false if ignore_literal_branches? && literal_branch?(branch)
125
+ return false if ignore_constant_branches? && const_branch?(branch)
126
+
127
+ true
128
+ end
129
+
130
+ def ignore_literal_branches?
131
+ cop_config.fetch('IgnoreLiteralBranches', false)
132
+ end
133
+
134
+ def ignore_constant_branches?
135
+ cop_config.fetch('IgnoreConstantBranches', false)
136
+ end
137
+
138
+ def literal_branch?(branch) # rubocop:disable Metrics/CyclomaticComplexity
139
+ return false if !branch.literal? || branch.xstr_type?
140
+ return true if branch.basic_literal?
141
+
142
+ branch.each_descendant.all? do |node|
143
+ node.basic_literal? ||
144
+ node.pair_type? || # hash keys and values are contained within a `pair` node
145
+ (node.const_type? && ignore_constant_branches?)
146
+ end
147
+ end
148
+
149
+ def const_branch?(branch)
150
+ branch.const_type?
151
+ end
90
152
  end
91
153
  end
92
154
  end