diff --git a/changelog/change_add_allowedpatterns_to.md b/changelog/change_add_allowedpatterns_to.md new file mode 100644 index 00000000000..4438110e4e0 --- /dev/null +++ b/changelog/change_add_allowedpatterns_to.md @@ -0,0 +1 @@ +* [#10857](https://github.com/rubocop/rubocop/issues/10857): Add `AllowedPatterns` to `Style/NumericLiterals`. ([@dvandersluis][]) diff --git a/config/default.yml b/config/default.yml index 092a32e0da1..4157b30dbc8 100644 --- a/config/default.yml +++ b/config/default.yml @@ -4405,6 +4405,7 @@ Style/NumericLiterals: Strict: false # You can specify allowed numbers. (e.g. port number 3000, 8080, and etc) AllowedNumbers: [] + AllowedPatterns: [] Style/NumericPredicate: Description: >- diff --git a/lib/rubocop/cop/style/numeric_literals.rb b/lib/rubocop/cop/style/numeric_literals.rb index 0db9dc0b256..acd9529f9a3 100644 --- a/lib/rubocop/cop/style/numeric_literals.rb +++ b/lib/rubocop/cop/style/numeric_literals.rb @@ -3,9 +3,17 @@ module RuboCop module Cop module Style - # Checks for big numeric literals without _ between groups + # Checks for big numeric literals without `_` between groups # of digits in them. # + # Additional allowed patterns can be added by adding regexps to + # the `AllowedPatterns` configuration. All regexps are treated + # as anchored even if the patterns do not contain anchors (so + # `\d{4}_\d{4}` will allow `1234_5678` but not `1234_5678_9012`). + # + # NOTE: Even if `AllowedPatterns` are given, autocorrection will + # only correct to the standard pattern of an `_` every 3 digits. + # # @example # # # bad @@ -34,6 +42,7 @@ module Style # class NumericLiterals < Base include IntegerNode + include AllowedPattern extend AutoCorrector MSG = 'Use underscores(_) as thousands separator and separate every 3 digits with them.' @@ -59,6 +68,7 @@ def check(node) # TODO: handle non-decimal literals as well return if int.start_with?('0') return if allowed_numbers.include?(int) + return if matches_allowed_pattern?(int) return unless int.size >= min_digits case int @@ -108,6 +118,11 @@ def min_digits def allowed_numbers cop_config.fetch('AllowedNumbers', []).map(&:to_s) end + + def allowed_patterns + # Convert the patterns to be anchored + super.map { |regexp| Regexp.new(/\A#{regexp}\z/) } + end end end end diff --git a/spec/rubocop/cli/auto_gen_config_spec.rb b/spec/rubocop/cli/auto_gen_config_spec.rb index dd86553bffc..4ba3380588f 100644 --- a/spec/rubocop/cli/auto_gen_config_spec.rb +++ b/spec/rubocop/cli/auto_gen_config_spec.rb @@ -379,7 +379,7 @@ def f '', '# Offense count: 1', '# This cop supports safe autocorrection (--autocorrect).', - '# Configuration parameters: Strict, AllowedNumbers.', + '# Configuration parameters: Strict, AllowedNumbers, AllowedPatterns.', 'Style/NumericLiterals:', ' MinDigits: 7', '', diff --git a/spec/rubocop/cop/style/numeric_literals_spec.rb b/spec/rubocop/cop/style/numeric_literals_spec.rb index 4c204bfbb14..c2a3e1c5e96 100644 --- a/spec/rubocop/cop/style/numeric_literals_spec.rb +++ b/spec/rubocop/cop/style/numeric_literals_spec.rb @@ -253,4 +253,42 @@ RUBY end end + + context 'AllowedPatterns' do + let(:cop_config) { { 'AllowedPatterns' => [/\d{2}_\d{2}_\d{4}/] } } + + it 'does not register an offense for numbers that exactly match the pattern' do + expect_no_offenses(<<~RUBY) + 12_34_5678 + RUBY + end + + it 'registers an offense for numbers that do not exactly match the pattern' do + expect_offense(<<~RUBY) + 1234_56_78_9012 + ^^^^^^^^^^^^^^^ Use underscores(_) as thousands separator and separate every 3 digits with them. + RUBY + end + + it 'corrects by inserting underscores every 3 digits' do + expect_offense(<<~RUBY) + 12345678 + ^^^^^^^^ Use underscores(_) as thousands separator and separate every 3 digits with them. + RUBY + + expect_correction(<<~RUBY) + 12_345_678 + RUBY + end + + context 'AllowedPatterns with repetition' do + let(:cop_config) { { 'AllowedPatterns' => [/\d{4}(_\d{4})+/] } } + + it 'does not register an offense for numbers that match the pattern' do + expect_no_offenses(<<~RUBY) + 1234_5678_9012_3456 + RUBY + end + end + end end