rubocop 1.5.2 → 1.8.1

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 (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