rubocop 1.5.2 → 1.8.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (113) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE.txt +1 -1
  3. data/README.md +3 -2
  4. data/config/default.yml +112 -16
  5. data/config/obsoletion.yml +196 -0
  6. data/lib/rubocop.rb +20 -1
  7. data/lib/rubocop/cli/command/suggest_extensions.rb +16 -44
  8. data/lib/rubocop/comment_config.rb +6 -6
  9. data/lib/rubocop/config.rb +8 -5
  10. data/lib/rubocop/config_loader.rb +11 -7
  11. data/lib/rubocop/config_loader_resolver.rb +21 -4
  12. data/lib/rubocop/config_obsoletion.rb +64 -262
  13. data/lib/rubocop/config_obsoletion/changed_enforced_styles.rb +33 -0
  14. data/lib/rubocop/config_obsoletion/changed_parameter.rb +21 -0
  15. data/lib/rubocop/config_obsoletion/cop_rule.rb +34 -0
  16. data/lib/rubocop/config_obsoletion/extracted_cop.rb +44 -0
  17. data/lib/rubocop/config_obsoletion/parameter_rule.rb +44 -0
  18. data/lib/rubocop/config_obsoletion/removed_cop.rb +41 -0
  19. data/lib/rubocop/config_obsoletion/renamed_cop.rb +34 -0
  20. data/lib/rubocop/config_obsoletion/rule.rb +41 -0
  21. data/lib/rubocop/config_obsoletion/split_cop.rb +27 -0
  22. data/lib/rubocop/config_validator.rb +11 -4
  23. data/lib/rubocop/cop/base.rb +17 -15
  24. data/lib/rubocop/cop/cop.rb +2 -2
  25. data/lib/rubocop/cop/correctors/string_literal_corrector.rb +6 -8
  26. data/lib/rubocop/cop/gemspec/required_ruby_version.rb +3 -2
  27. data/lib/rubocop/cop/internal_affairs.rb +1 -0
  28. data/lib/rubocop/cop/internal_affairs/style_detected_api_use.rb +145 -0
  29. data/lib/rubocop/cop/layout/empty_line_between_defs.rb +19 -3
  30. data/lib/rubocop/cop/layout/empty_lines_around_attribute_accessor.rb +1 -1
  31. data/lib/rubocop/cop/layout/heredoc_argument_closing_parenthesis.rb +14 -0
  32. data/lib/rubocop/cop/layout/line_length.rb +6 -16
  33. data/lib/rubocop/cop/layout/multiline_operation_indentation.rb +2 -2
  34. data/lib/rubocop/cop/layout/rescue_ensure_alignment.rb +3 -10
  35. data/lib/rubocop/cop/layout/space_around_equals_in_parameter_default.rb +1 -0
  36. data/lib/rubocop/cop/layout/space_before_block_braces.rb +2 -0
  37. data/lib/rubocop/cop/layout/space_before_brackets.rb +62 -0
  38. data/lib/rubocop/cop/layout/space_inside_block_braces.rb +13 -10
  39. data/lib/rubocop/cop/layout/space_inside_hash_literal_braces.rb +2 -2
  40. data/lib/rubocop/cop/lint/ambiguous_assignment.rb +59 -0
  41. data/lib/rubocop/cop/lint/binary_operator_with_identical_operands.rb +7 -2
  42. data/lib/rubocop/cop/lint/deprecated_constants.rb +75 -0
  43. data/lib/rubocop/cop/lint/duplicate_branch.rb +64 -2
  44. data/lib/rubocop/cop/lint/lambda_without_literal_block.rb +44 -0
  45. data/lib/rubocop/cop/lint/non_deterministic_require_order.rb +10 -6
  46. data/lib/rubocop/cop/lint/redundant_cop_disable_directive.rb +2 -1
  47. data/lib/rubocop/cop/lint/redundant_dir_glob_sort.rb +50 -0
  48. data/lib/rubocop/cop/lint/redundant_splat_expansion.rb +50 -17
  49. data/lib/rubocop/cop/lint/shadowed_exception.rb +1 -11
  50. data/lib/rubocop/cop/lint/unreachable_loop.rb +17 -0
  51. data/lib/rubocop/cop/metrics/utils/code_length_calculator.rb +1 -1
  52. data/lib/rubocop/cop/migration/department_name.rb +1 -1
  53. data/lib/rubocop/cop/mixin/allowed_identifiers.rb +18 -0
  54. data/lib/rubocop/cop/mixin/comments_help.rb +1 -10
  55. data/lib/rubocop/cop/mixin/first_element_line_break.rb +1 -1
  56. data/lib/rubocop/cop/mixin/string_help.rb +4 -1
  57. data/lib/rubocop/cop/mixin/uncommunicative_name.rb +5 -1
  58. data/lib/rubocop/cop/naming/accessor_method_name.rb +15 -1
  59. data/lib/rubocop/cop/naming/memoized_instance_variable_name.rb +59 -5
  60. data/lib/rubocop/cop/naming/variable_name.rb +2 -0
  61. data/lib/rubocop/cop/naming/variable_number.rb +1 -8
  62. data/lib/rubocop/cop/registry.rb +10 -0
  63. data/lib/rubocop/cop/style/access_modifier_declarations.rb +3 -1
  64. data/lib/rubocop/cop/style/character_literal.rb +10 -11
  65. data/lib/rubocop/cop/style/collection_methods.rb +14 -1
  66. data/lib/rubocop/cop/style/commented_keyword.rb +22 -5
  67. data/lib/rubocop/cop/style/empty_literal.rb +6 -2
  68. data/lib/rubocop/cop/style/endless_method.rb +102 -0
  69. data/lib/rubocop/cop/style/explicit_block_argument.rb +10 -0
  70. data/lib/rubocop/cop/style/float_division.rb +44 -1
  71. data/lib/rubocop/cop/style/for.rb +2 -0
  72. data/lib/rubocop/cop/style/hash_except.rb +95 -0
  73. data/lib/rubocop/cop/style/hash_like_case.rb +2 -1
  74. data/lib/rubocop/cop/style/if_inside_else.rb +8 -3
  75. data/lib/rubocop/cop/style/if_unless_modifier.rb +4 -0
  76. data/lib/rubocop/cop/style/ip_addresses.rb +1 -1
  77. data/lib/rubocop/cop/style/keyword_parameters_order.rb +12 -2
  78. data/lib/rubocop/cop/style/lambda_call.rb +2 -1
  79. data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +7 -0
  80. data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +16 -6
  81. data/lib/rubocop/cop/style/method_def_parentheses.rb +7 -0
  82. data/lib/rubocop/cop/style/multiline_method_signature.rb +26 -1
  83. data/lib/rubocop/cop/style/multiline_when_then.rb +3 -1
  84. data/lib/rubocop/cop/style/mutable_constant.rb +13 -3
  85. data/lib/rubocop/cop/style/nested_parenthesized_calls.rb +4 -0
  86. data/lib/rubocop/cop/style/perl_backrefs.rb +86 -9
  87. data/lib/rubocop/cop/style/raise_args.rb +5 -2
  88. data/lib/rubocop/cop/style/redundant_argument.rb +21 -2
  89. data/lib/rubocop/cop/style/redundant_freeze.rb +8 -4
  90. data/lib/rubocop/cop/style/redundant_return.rb +1 -1
  91. data/lib/rubocop/cop/style/single_line_block_params.rb +30 -7
  92. data/lib/rubocop/cop/style/single_line_methods.rb +34 -2
  93. data/lib/rubocop/cop/style/sole_nested_conditional.rb +15 -9
  94. data/lib/rubocop/cop/style/special_global_vars.rb +1 -13
  95. data/lib/rubocop/cop/style/string_concatenation.rb +20 -1
  96. data/lib/rubocop/cop/style/string_literals.rb +14 -8
  97. data/lib/rubocop/cop/style/string_literals_in_interpolation.rb +4 -3
  98. data/lib/rubocop/cop/style/symbol_proc.rb +5 -4
  99. data/lib/rubocop/cop/style/while_until_modifier.rb +2 -4
  100. data/lib/rubocop/cop/util.rb +3 -1
  101. data/lib/rubocop/formatter/emacs_style_formatter.rb +2 -0
  102. data/lib/rubocop/formatter/simple_text_formatter.rb +2 -0
  103. data/lib/rubocop/formatter/tap_formatter.rb +2 -0
  104. data/lib/rubocop/lockfile.rb +40 -0
  105. data/lib/rubocop/options.rb +9 -9
  106. data/lib/rubocop/rspec/cop_helper.rb +0 -4
  107. data/lib/rubocop/rspec/expect_offense.rb +34 -22
  108. data/lib/rubocop/runner.rb +16 -1
  109. data/lib/rubocop/target_finder.rb +4 -2
  110. data/lib/rubocop/target_ruby.rb +47 -11
  111. data/lib/rubocop/util.rb +16 -0
  112. data/lib/rubocop/version.rb +8 -2
  113. metadata +28 -7
@@ -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,75 @@
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
+ constant = node.absolute? ? consntant_name(node, node.short_name.to_s) : node.source
41
+ return unless (deprecated_constant = deprecated_constants[constant])
42
+
43
+ alternative = deprecated_constant['Alternative']
44
+ version = deprecated_constant['DeprecatedVersion']
45
+
46
+ add_offense(node, message: message(alternative, node.source, version)) do |corrector|
47
+ corrector.replace(node, alternative)
48
+ end
49
+ end
50
+
51
+ private
52
+
53
+ def consntant_name(node, nested_constant_name)
54
+ return nested_constant_name unless node.namespace.const_type?
55
+
56
+ consntant_name(node.namespace, "#{node.namespace.short_name}::#{nested_constant_name}")
57
+ end
58
+
59
+ def message(good, bad, deprecated_version)
60
+ deprecated_message = ", deprecated since Ruby #{deprecated_version}" if deprecated_version
61
+
62
+ if good
63
+ format(SUGGEST_GOOD_MSG, good: good, bad: bad, deprecated_message: deprecated_message)
64
+ else
65
+ format(DO_NOT_USE_MSG, bad: bad, deprecated_message: deprecated_message)
66
+ end
67
+ end
68
+
69
+ def deprecated_constants
70
+ cop_config.fetch('DeprecatedConstants', {})
71
+ end
72
+ end
73
+ end
74
+ end
75
+ 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
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Lint
6
+ # This cop checks uses of lambda without a literal block.
7
+ # It emulates the following warning in Ruby 3.0:
8
+ #
9
+ # % ruby -vwe 'lambda(&proc {})'
10
+ # ruby 3.0.0p0 (2020-12-25 revision 95aff21468) [x86_64-darwin19]
11
+ # -e:1: warning: lambda without a literal block is deprecated; use the proc without
12
+ # lambda instead
13
+ #
14
+ # This way, proc object is never converted to lambda.
15
+ # Auto-correction replaces with compatible proc argument.
16
+ #
17
+ # @example
18
+ #
19
+ # # bad
20
+ # lambda(&proc { do_something })
21
+ # lambda(&Proc.new { do_something })
22
+ #
23
+ # # good
24
+ # proc { do_something }
25
+ # Proc.new { do_something }
26
+ # lambda { do_something } # If you use lambda.
27
+ #
28
+ class LambdaWithoutLiteralBlock < Base
29
+ extend AutoCorrector
30
+
31
+ MSG = 'lambda without a literal block is deprecated; use the proc without lambda instead.'
32
+ RESTRICT_ON_SEND = %i[lambda].freeze
33
+
34
+ def on_send(node)
35
+ return if node.parent&.block_type? || !node.first_argument
36
+
37
+ add_offense(node) do |corrector|
38
+ corrector.replace(node, node.first_argument.source.delete('&'))
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
@@ -11,6 +11,11 @@ module RuboCop
11
11
  # that are hard to debug. To ensure this doesn't happen,
12
12
  # always sort the list.
13
13
  #
14
+ # `Dir.glob` and `Dir[]` sort globbed results by default in Ruby 3.0.
15
+ # So all bad cases are acceptable when Ruby 3.0 or higher are used.
16
+ #
17
+ # This cop will be deprecated and removed when supporting only Ruby 3.0 and higher.
18
+ #
14
19
  # @example
15
20
  #
16
21
  # # bad
@@ -23,8 +28,6 @@ module RuboCop
23
28
  # require file
24
29
  # end
25
30
  #
26
- # @example
27
- #
28
31
  # # bad
29
32
  # Dir.glob(Rails.root.join(__dir__, 'test', '*.rb')) do |file|
30
33
  # require file
@@ -35,28 +38,28 @@ module RuboCop
35
38
  # require file
36
39
  # end
37
40
  #
38
- # @example
39
- #
40
41
  # # bad
41
42
  # Dir['./lib/**/*.rb'].each(&method(:require))
42
43
  #
43
44
  # # good
44
45
  # Dir['./lib/**/*.rb'].sort.each(&method(:require))
45
46
  #
46
- # @example
47
- #
48
47
  # # bad
49
48
  # Dir.glob(Rails.root.join('test', '*.rb'), &method(:require))
50
49
  #
51
50
  # # good
52
51
  # Dir.glob(Rails.root.join('test', '*.rb')).sort.each(&method(:require))
53
52
  #
53
+ # # good - Respect intent if `sort` keyword option is specified in Ruby 3.0 or higher.
54
+ # Dir.glob(Rails.root.join(__dir__, 'test', '*.rb'), sort: false).each(&method(:require))
55
+ #
54
56
  class NonDeterministicRequireOrder < Base
55
57
  extend AutoCorrector
56
58
 
57
59
  MSG = 'Sort files before requiring them.'
58
60
 
59
61
  def on_block(node)
62
+ return if target_ruby_version >= 3.0
60
63
  return unless node.body
61
64
  return unless unsorted_dir_loop?(node.send_node)
62
65
 
@@ -70,6 +73,7 @@ module RuboCop
70
73
  end
71
74
 
72
75
  def on_block_pass(node)
76
+ return if target_ruby_version >= 3.0
73
77
  return unless method_require?(node)
74
78
  return unless unsorted_dir_pass?(node.parent)
75
79
 
@@ -61,7 +61,8 @@ module RuboCop
61
61
  end
62
62
 
63
63
  def comment_range_with_surrounding_space(range)
64
- if previous_line_blank?(range)
64
+ if previous_line_blank?(range) &&
65
+ processed_source.comment_config.comment_only_line?(range.line)
65
66
  # When the previous line is blank, it should be retained
66
67
  range_with_surrounding_space(range: range, side: :right)
67
68
  else
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Lint
6
+ # Sort globbed results by default in Ruby 3.0.
7
+ # This cop checks for redundant `sort` method to `Dir.glob` and `Dir[]`.
8
+ #
9
+ # @example
10
+ #
11
+ # # bad
12
+ # Dir.glob('./lib/**/*.rb').sort.each do |file|
13
+ # end
14
+ #
15
+ # Dir['./lib/**/*.rb'].sort.each do |file|
16
+ # end
17
+ #
18
+ # # good
19
+ # Dir.glob('./lib/**/*.rb').each do |file|
20
+ # end
21
+ #
22
+ # Dir['./lib/**/*.rb'].each do |file|
23
+ # end
24
+ #
25
+ class RedundantDirGlobSort < Base
26
+ extend AutoCorrector
27
+ extend TargetRubyVersion
28
+
29
+ minimum_target_ruby_version 3.0
30
+
31
+ MSG = 'Remove redundant `sort`.'
32
+ RESTRICT_ON_SEND = %i[sort].freeze
33
+ GLOB_METHODS = %i[glob []].freeze
34
+
35
+ def on_send(node)
36
+ return unless (receiver = node.receiver)
37
+ return unless receiver.receiver&.const_type? && receiver.receiver.short_name == :Dir
38
+ return unless GLOB_METHODS.include?(receiver.method_name)
39
+
40
+ selector = node.loc.selector
41
+
42
+ add_offense(selector) do |corrector|
43
+ corrector.remove(selector)
44
+ corrector.remove(node.loc.dot)
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
@@ -8,47 +8,66 @@ module RuboCop
8
8
  # @example
9
9
  #
10
10
  # # bad
11
- #
12
11
  # a = *[1, 2, 3]
13
12
  # a = *'a'
14
13
  # a = *1
15
- #
16
- # begin
17
- # foo
18
- # rescue *[StandardError, ApplicationError]
19
- # bar
20
- # end
21
- #
22
- # case foo
23
- # when *[1, 2, 3]
24
- # bar
25
- # else
26
- # baz
27
- # end
28
- #
29
- # @example
14
+ # ['a', 'b', *%w(c d e), 'f', 'g']
30
15
  #
31
16
  # # good
32
- #
33
17
  # c = [1, 2, 3]
34
18
  # a = *c
35
19
  # a, b = *c
36
20
  # a, *b = *c
37
21
  # a = *1..10
38
22
  # a = ['a']
23
+ # ['a', 'b', 'c', 'd', 'e', 'f', 'g']
39
24
  #
25
+ # # bad
26
+ # do_something(*['foo', 'bar', 'baz'])
27
+ #
28
+ # # good
29
+ # do_something('foo', 'bar', 'baz')
30
+ #
31
+ # # bad
32
+ # begin
33
+ # foo
34
+ # rescue *[StandardError, ApplicationError]
35
+ # bar
36
+ # end
37
+ #
38
+ # # good
40
39
  # begin
41
40
  # foo
42
41
  # rescue StandardError, ApplicationError
43
42
  # bar
44
43
  # end
45
44
  #
45
+ # # bad
46
+ # case foo
47
+ # when *[1, 2, 3]
48
+ # bar
49
+ # else
50
+ # baz
51
+ # end
52
+ #
53
+ # # good
46
54
  # case foo
47
55
  # when 1, 2, 3
48
56
  # bar
49
57
  # else
50
58
  # baz
51
59
  # end
60
+ #
61
+ # @example AllowPercentLiteralArrayArgument: true (default)
62
+ #
63
+ # # good
64
+ # do_something(*%w[foo bar baz])
65
+ #
66
+ # @example AllowPercentLiteralArrayArgument: false
67
+ #
68
+ # # bad
69
+ # do_something(*%w[foo bar baz])
70
+ #
52
71
  class RedundantSplatExpansion < Base
53
72
  extend AutoCorrector
54
73
 
@@ -75,6 +94,9 @@ module RuboCop
75
94
  redundant_splat_expansion(node) do
76
95
  if array_splat?(node) &&
77
96
  (method_argument?(node) || part_of_an_array?(node))
97
+ return if allow_percent_literal_array_argument? &&
98
+ use_percent_literal_array_argument?(node)
99
+
78
100
  add_offense(node, message: ARRAY_PARAM_MSG) do |corrector|
79
101
  autocorrect(corrector, node)
80
102
  end
@@ -170,6 +192,17 @@ module RuboCop
170
192
  elements.join(', ')
171
193
  end
172
194
  end
195
+
196
+ def use_percent_literal_array_argument?(node)
197
+ argument = node.children.first
198
+
199
+ node.parent.send_type? &&
200
+ (argument.percent_literal?(:string) || argument.percent_literal?(:symbol))
201
+ end
202
+
203
+ def allow_percent_literal_array_argument?
204
+ cop_config.fetch('AllowPercentLiteralArrayArgument', true)
205
+ end
173
206
  end
174
207
  end
175
208
  end