rubocop 1.7.0 → 1.10.0

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 (100) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE.txt +1 -1
  3. data/README.md +4 -3
  4. data/config/default.yml +137 -31
  5. data/config/obsoletion.yml +4 -0
  6. data/lib/rubocop.rb +14 -1
  7. data/lib/rubocop/cli/command/auto_genenerate_config.rb +5 -4
  8. data/lib/rubocop/comment_config.rb +6 -6
  9. data/lib/rubocop/config.rb +5 -2
  10. data/lib/rubocop/config_loader.rb +7 -14
  11. data/lib/rubocop/config_store.rb +12 -1
  12. data/lib/rubocop/cop/base.rb +2 -1
  13. data/lib/rubocop/cop/exclude_limit.rb +26 -0
  14. data/lib/rubocop/cop/gemspec/date_assignment.rb +56 -0
  15. data/lib/rubocop/cop/generator.rb +1 -3
  16. data/lib/rubocop/cop/internal_affairs.rb +5 -1
  17. data/lib/rubocop/cop/internal_affairs/empty_line_between_expect_offense_and_correction.rb +68 -0
  18. data/lib/rubocop/cop/internal_affairs/example_description.rb +89 -0
  19. data/lib/rubocop/cop/internal_affairs/redundant_described_class_as_subject.rb +61 -0
  20. data/lib/rubocop/cop/internal_affairs/redundant_let_rubocop_config_new.rb +64 -0
  21. data/lib/rubocop/cop/layout/class_structure.rb +7 -2
  22. data/lib/rubocop/cop/layout/empty_line_between_defs.rb +38 -18
  23. data/lib/rubocop/cop/layout/first_argument_indentation.rb +16 -2
  24. data/lib/rubocop/cop/layout/line_length.rb +2 -1
  25. data/lib/rubocop/cop/layout/multiline_assignment_layout.rb +26 -0
  26. data/lib/rubocop/cop/layout/multiline_operation_indentation.rb +2 -2
  27. data/lib/rubocop/cop/layout/space_before_brackets.rb +19 -16
  28. data/lib/rubocop/cop/lint/debugger.rb +58 -14
  29. data/lib/rubocop/cop/lint/deprecated_constants.rb +80 -0
  30. data/lib/rubocop/cop/lint/deprecated_open_ssl_constant.rb +13 -4
  31. data/lib/rubocop/cop/lint/duplicate_require.rb +2 -2
  32. data/lib/rubocop/cop/lint/else_layout.rb +1 -1
  33. data/lib/rubocop/cop/lint/lambda_without_literal_block.rb +44 -0
  34. data/lib/rubocop/cop/lint/multiple_comparison.rb +4 -4
  35. data/lib/rubocop/cop/lint/non_deterministic_require_order.rb +10 -6
  36. data/lib/rubocop/cop/lint/number_conversion.rb +41 -6
  37. data/lib/rubocop/cop/lint/numbered_parameter_assignment.rb +47 -0
  38. data/lib/rubocop/cop/lint/or_assignment_to_constant.rb +39 -0
  39. data/lib/rubocop/cop/lint/redundant_cop_disable_directive.rb +2 -1
  40. data/lib/rubocop/cop/lint/redundant_dir_glob_sort.rb +50 -0
  41. data/lib/rubocop/cop/lint/redundant_splat_expansion.rb +5 -3
  42. data/lib/rubocop/cop/lint/symbol_conversion.rb +103 -0
  43. data/lib/rubocop/cop/lint/triple_quotes.rb +71 -0
  44. data/lib/rubocop/cop/message_annotator.rb +4 -1
  45. data/lib/rubocop/cop/metrics/block_nesting.rb +2 -2
  46. data/lib/rubocop/cop/metrics/parameter_lists.rb +5 -2
  47. data/lib/rubocop/cop/mixin/allowed_identifiers.rb +18 -0
  48. data/lib/rubocop/cop/mixin/check_line_breakable.rb +5 -0
  49. data/lib/rubocop/cop/mixin/code_length.rb +3 -1
  50. data/lib/rubocop/cop/mixin/comments_help.rb +1 -11
  51. data/lib/rubocop/cop/mixin/configurable_max.rb +1 -0
  52. data/lib/rubocop/cop/mixin/first_element_line_break.rb +1 -1
  53. data/lib/rubocop/cop/mixin/method_complexity.rb +3 -1
  54. data/lib/rubocop/cop/mixin/preferred_delimiters.rb +2 -2
  55. data/lib/rubocop/cop/mixin/uncommunicative_name.rb +5 -1
  56. data/lib/rubocop/cop/naming/rescued_exceptions_variable_name.rb +38 -5
  57. data/lib/rubocop/cop/naming/variable_name.rb +2 -0
  58. data/lib/rubocop/cop/naming/variable_number.rb +2 -9
  59. data/lib/rubocop/cop/registry.rb +1 -1
  60. data/lib/rubocop/cop/severity.rb +3 -3
  61. data/lib/rubocop/cop/style/ascii_comments.rb +1 -1
  62. data/lib/rubocop/cop/style/constant_visibility.rb +27 -0
  63. data/lib/rubocop/cop/style/disable_cops_within_source_code_directive.rb +49 -9
  64. data/lib/rubocop/cop/style/double_negation.rb +2 -2
  65. data/lib/rubocop/cop/style/empty_literal.rb +6 -2
  66. data/lib/rubocop/cop/style/endless_method.rb +102 -0
  67. data/lib/rubocop/cop/style/eval_with_location.rb +138 -49
  68. data/lib/rubocop/cop/style/explicit_block_argument.rb +11 -1
  69. data/lib/rubocop/cop/style/exponential_notation.rb +6 -7
  70. data/lib/rubocop/cop/style/float_division.rb +3 -0
  71. data/lib/rubocop/cop/style/format_string_token.rb +18 -2
  72. data/lib/rubocop/cop/style/hash_conversion.rb +81 -0
  73. data/lib/rubocop/cop/style/hash_like_case.rb +2 -1
  74. data/lib/rubocop/cop/style/if_inside_else.rb +22 -10
  75. data/lib/rubocop/cop/style/if_with_boolean_literal_branches.rb +120 -0
  76. data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +4 -0
  77. data/lib/rubocop/cop/style/nested_parenthesized_calls.rb +4 -0
  78. data/lib/rubocop/cop/style/nil_comparison.rb +3 -0
  79. data/lib/rubocop/cop/style/non_nil_check.rb +23 -13
  80. data/lib/rubocop/cop/style/numeric_literals.rb +6 -9
  81. data/lib/rubocop/cop/style/numeric_predicate.rb +1 -1
  82. data/lib/rubocop/cop/style/raise_args.rb +3 -2
  83. data/lib/rubocop/cop/style/redundant_return.rb +1 -1
  84. data/lib/rubocop/cop/style/single_line_methods.rb +32 -2
  85. data/lib/rubocop/cop/style/sole_nested_conditional.rb +29 -5
  86. data/lib/rubocop/cop/style/special_global_vars.rb +3 -3
  87. data/lib/rubocop/cop/style/string_concatenation.rb +1 -1
  88. data/lib/rubocop/cop/style/ternary_parentheses.rb +1 -1
  89. data/lib/rubocop/cop/style/while_until_modifier.rb +2 -4
  90. data/lib/rubocop/formatter/git_hub_actions_formatter.rb +1 -0
  91. data/lib/rubocop/formatter/offense_count_formatter.rb +1 -1
  92. data/lib/rubocop/formatter/simple_text_formatter.rb +2 -1
  93. data/lib/rubocop/formatter/worst_offenders_formatter.rb +1 -1
  94. data/lib/rubocop/magic_comment.rb +30 -1
  95. data/lib/rubocop/options.rb +1 -1
  96. data/lib/rubocop/rspec/expect_offense.rb +5 -2
  97. data/lib/rubocop/runner.rb +1 -0
  98. data/lib/rubocop/target_ruby.rb +47 -11
  99. data/lib/rubocop/version.rb +2 -2
  100. metadata +24 -7
@@ -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
@@ -44,6 +44,8 @@ module RuboCop
44
44
  MSG = 'Use `%<constant>s.%<method>s(%<replacement_args>s)`' \
45
45
  ' instead of `%<original>s`.'
46
46
 
47
+ NO_ARG_ALGORITHM = %w[BF DES IDEA RC4].freeze
48
+
47
49
  def_node_matcher :algorithm_const, <<~PATTERN
48
50
  (send
49
51
  $(const
@@ -104,7 +106,7 @@ module RuboCop
104
106
  def algorithm_name(node)
105
107
  name = node.loc.name.source
106
108
 
107
- if openssl_class(node) == 'OpenSSL::Cipher'
109
+ if openssl_class(node) == 'OpenSSL::Cipher' && !NO_ARG_ALGORITHM.include?(name)
108
110
  name.scan(/.{3}/).join('-')
109
111
  else
110
112
  name
@@ -124,16 +126,23 @@ module RuboCop
124
126
  algorithm_name = algorithm_name(algorithm_constant)
125
127
 
126
128
  if openssl_class(algorithm_constant) == 'OpenSSL::Cipher'
127
- build_cipher_arguments(node, algorithm_name)
129
+ build_cipher_arguments(node, algorithm_name, node.arguments.empty?)
128
130
  else
129
131
  (["'#{algorithm_name}'"] + node.arguments.map(&:source)).join(', ')
130
132
  end
131
133
  end
132
134
 
133
- def build_cipher_arguments(node, algorithm_name)
135
+ def build_cipher_arguments(node, algorithm_name, no_arguments)
134
136
  algorithm_parts = algorithm_name.downcase.split('-')
135
137
  size_and_mode = sanitize_arguments(node.arguments).map(&:downcase)
136
- "'#{(algorithm_parts + size_and_mode + ['cbc']).take(3).join('-')}'"
138
+
139
+ if NO_ARG_ALGORITHM.include?(algorithm_parts.first.upcase) && no_arguments
140
+ "'#{algorithm_parts.first}'"
141
+ else
142
+ mode = 'cbc' unless size_and_mode == ['cbc']
143
+
144
+ "'#{(algorithm_parts + size_and_mode + [mode]).compact.take(3).join('-')}'"
145
+ end
137
146
  end
138
147
  end
139
148
  end
@@ -21,11 +21,11 @@ module RuboCop
21
21
  #
22
22
  class DuplicateRequire < Base
23
23
  MSG = 'Duplicate `%<method>s` detected.'
24
- REQUIRE_METHODS = %i[require require_relative].freeze
24
+ REQUIRE_METHODS = Set.new(%i[require require_relative]).freeze
25
25
  RESTRICT_ON_SEND = REQUIRE_METHODS
26
26
 
27
27
  def_node_matcher :require_call?, <<~PATTERN
28
- (send {nil? (const _ :Kernel)} {:#{REQUIRE_METHODS.join(' :')}} _)
28
+ (send {nil? (const _ :Kernel)} %REQUIRE_METHODS _)
29
29
  PATTERN
30
30
 
31
31
  def on_new_investigation
@@ -47,7 +47,7 @@ module RuboCop
47
47
  MSG = 'Odd `else` layout detected. Did you mean to use `elsif`?'
48
48
 
49
49
  def on_if(node)
50
- return if node.ternary? || node.elsif?
50
+ return if node.ternary?
51
51
 
52
52
  check(node)
53
53
  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,14 +11,10 @@ module RuboCop
11
11
  # @example
12
12
  #
13
13
  # # bad
14
- #
15
14
  # x < y < z
16
15
  # 10 <= x <= 20
17
16
  #
18
- # @example
19
- #
20
17
  # # good
21
- #
22
18
  # x < y && y < z
23
19
  # 10 <= x && x <= 20
24
20
  class MultipleComparison < Base
@@ -26,6 +22,7 @@ module RuboCop
26
22
 
27
23
  MSG = 'Use the `&&` operator to compare multiple values.'
28
24
  COMPARISON_METHODS = %i[< > <= >=].freeze
25
+ SET_OPERATION_OPERATORS = %i[& | ^].freeze
29
26
  RESTRICT_ON_SEND = COMPARISON_METHODS
30
27
 
31
28
  def_node_matcher :multiple_compare?, <<~PATTERN
@@ -34,6 +31,9 @@ module RuboCop
34
31
 
35
32
  def on_send(node)
36
33
  return unless (center = multiple_compare?(node))
34
+ # It allows multiple comparison using `&`, `|`, and `^` set operation operators.
35
+ # e.g. `x >= y & y < z`
36
+ return if center.send_type? && SET_OPERATION_OPERATORS.include?(center.method_name)
37
37
 
38
38
  add_offense(node) do |corrector|
39
39
  new_center = "#{center.source} && #{center.source}"
@@ -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
 
@@ -25,12 +25,18 @@ module RuboCop
25
25
  # '10'.to_i
26
26
  # '10.2'.to_f
27
27
  # '10'.to_c
28
+ # ['1', '2', '3'].map(&:to_i)
29
+ # foo.try(:to_f)
30
+ # bar.send(:to_c)
28
31
  #
29
32
  # # good
30
33
  #
31
34
  # Integer('10', 10)
32
35
  # Float('10.2')
33
36
  # Complex('10')
37
+ # ['1', '2', '3'].map { |i| Integer(i, 10) }
38
+ # foo.try { |i| Float(i) }
39
+ # bar.send { |i| Complex(i) }
34
40
  #
35
41
  # @example IgnoredMethods: [minutes]
36
42
  #
@@ -52,22 +58,33 @@ module RuboCop
52
58
  }.freeze
53
59
  MSG = 'Replace unsafe number conversion with number '\
54
60
  'class parsing, instead of using '\
55
- '%<number_object>s.%<to_method>s, use stricter '\
61
+ '%<current>s, use stricter '\
56
62
  '%<corrected_method>s.'
57
- RESTRICT_ON_SEND = CONVERSION_METHOD_CLASS_MAPPING.keys.freeze
63
+ METHODS = CONVERSION_METHOD_CLASS_MAPPING.keys.map(&:inspect).join(' ')
58
64
 
59
65
  def_node_matcher :to_method, <<~PATTERN
60
- (send $_ ${:to_i :to_f :to_c})
66
+ (send $_ ${#{METHODS}})
67
+ PATTERN
68
+
69
+ def_node_matcher :to_method_symbol, <<~PATTERN
70
+ {(send _ $_ ${(sym ${#{METHODS}})} ...)
71
+ (send _ $_ ${(block_pass (sym ${#{METHODS}}))} ...)}
61
72
  PATTERN
62
73
 
63
74
  def on_send(node)
75
+ handle_conversion_method(node)
76
+ handle_as_symbol(node)
77
+ end
78
+
79
+ private
80
+
81
+ def handle_conversion_method(node)
64
82
  to_method(node) do |receiver, to_method|
65
83
  next if receiver.nil? || ignore_receiver?(receiver)
66
84
 
67
85
  message = format(
68
86
  MSG,
69
- number_object: receiver.source,
70
- to_method: to_method,
87
+ current: "#{receiver.source}.#{to_method}",
71
88
  corrected_method: correct_method(node, receiver)
72
89
  )
73
90
  add_offense(node, message: message) do |corrector|
@@ -76,13 +93,31 @@ module RuboCop
76
93
  end
77
94
  end
78
95
 
79
- private
96
+ def handle_as_symbol(node)
97
+ to_method_symbol(node) do |receiver, sym_node, to_method|
98
+ next if receiver.nil?
99
+
100
+ message = format(
101
+ MSG,
102
+ current: sym_node.source,
103
+ corrected_method: correct_sym_method(to_method)
104
+ )
105
+ add_offense(node, message: message) do |corrector|
106
+ corrector.replace(sym_node, correct_sym_method(to_method))
107
+ end
108
+ end
109
+ end
80
110
 
81
111
  def correct_method(node, receiver)
82
112
  format(CONVERSION_METHOD_CLASS_MAPPING[node.method_name],
83
113
  number_object: receiver.source)
84
114
  end
85
115
 
116
+ def correct_sym_method(to_method)
117
+ body = format(CONVERSION_METHOD_CLASS_MAPPING[to_method], number_object: 'i')
118
+ "{ |i| #{body} }"
119
+ end
120
+
86
121
  def ignore_receiver?(receiver)
87
122
  if receiver.send_type? && ignored_method?(receiver.method_name)
88
123
  true
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Lint
6
+ # This cop checks for uses of numbered parameter assignment.
7
+ # It emulates the following warning in Ruby 2.7:
8
+ #
9
+ # % ruby -ve '_1 = :value'
10
+ # ruby 2.7.2p137 (2020-10-01 revision 5445e04352) [x86_64-darwin19]
11
+ # -e:1: warning: `_1' is reserved for numbered parameter; consider another name
12
+ #
13
+ # Assiging to numbered parameter (from `_1` to `_9`) cause an error in Ruby 3.0.
14
+ #
15
+ # % ruby -ve '_1 = :value'
16
+ # ruby 3.0.0p0 (2020-12-25 revision 95aff21468) [x86_64-darwin19]
17
+ # -e:1: _1 is reserved for numbered parameter
18
+ #
19
+ # NOTE: The parametered parameters are from `_1` to `_9`. This cop checks `_0`, and over `_10`
20
+ # as well to prevent confusion.
21
+ #
22
+ # @example
23
+ #
24
+ # # bad
25
+ # _1 = :value
26
+ #
27
+ # # good
28
+ # non_numbered_parameter_name = :value
29
+ #
30
+ class NumberedParameterAssignment < Base
31
+ NUM_PARAM_MSG = '`_%<number>s` is reserved for numbered parameter; consider another name.'
32
+ LVAR_MSG = '`_%<number>s` is similar to numbered parameter; consider another name.'
33
+ NUMBERED_PARAMETER_RANGE = (1..9).freeze
34
+
35
+ def on_lvasgn(node)
36
+ lhs, _rhs = *node
37
+ return unless /\A_(\d+)\z/ =~ lhs
38
+
39
+ number = Regexp.last_match(1).to_i
40
+ template = NUMBERED_PARAMETER_RANGE.include?(number) ? NUM_PARAM_MSG : LVAR_MSG
41
+
42
+ add_offense(node, message: format(template, number: number))
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Lint
6
+ # This cop checks for unintended or-assignment to a constant.
7
+ #
8
+ # Constants should always be assigned in the same location. And its value
9
+ # should always be the same. If constants are assigned in multiple
10
+ # locations, the result may vary depending on the order of `require`.
11
+ #
12
+ # Also, if you already have such an implementation, auto-correction may
13
+ # change the result.
14
+ #
15
+ # @example
16
+ #
17
+ # # bad
18
+ # CONST ||= 1
19
+ #
20
+ # # good
21
+ # CONST = 1
22
+ #
23
+ class OrAssignmentToConstant < Base
24
+ extend AutoCorrector
25
+
26
+ MSG = 'Avoid using or-assignment with constants.'
27
+
28
+ def on_or_asgn(node)
29
+ lhs, _rhs = *node
30
+ return unless lhs&.casgn_type?
31
+
32
+ add_offense(node.loc.operator) do |corrector|
33
+ corrector.replace(node.loc.operator, '=')
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end