Class: Obfuscator::NumberObfuscator

Inherits:
Object
  • Object
show all
Includes:
Internal::RNG
Defined in:
lib/obfuscator/number_obfuscator.rb

Overview

Note:

This method is optimized for single-use. For bulk operations, consider creating a single instance and reusing it.

Note:

This class is not thread-safe. For concurrent usage, create separate instances per thread.

Note:

Requires Ruby 3.0+ for pattern matching features

Class for obfuscating numbers while preserving their format and structure. Handles pure numbers (integers, floats), formatted strings, and mixed content including multilingual text (Latin and Cyrillic alphabets).

Features:

  • Preserves number format (decimal separators, thousand separators)

  • Maintains leading zeros (optional)

  • Handles mixed content with letters and numbers

  • Supports both Latin and Cyrillic alphabets

  • Provides reproducible results with seeds

  • UTF-8 encoding support

Examples:

Basic usage with numbers

obfuscator = NumberObfuscator.new
obfuscator.obfuscate(123.45)     # => 567.89
obfuscator.obfuscate(-42)        # => -73

With string numbers and leading zeros

obfuscator.obfuscate("0042")     # => "0073"
obfuscator.obfuscate("00123.40") # => "00567.80"

With formatted numbers

obfuscator.obfuscate("1 234,56") # => "5 678,91"
obfuscator.obfuscate("1_000_000") # => "5_678_912"

With mixed content (Latin and Cyrillic)

obfuscator.obfuscate("ABC-42XY")      # => "DEF-73ZW"
obfuscator.obfuscate("АБВ-42ЩЮ")      # => "ГДЕ-73ЖЗ"
obfuscator.obfuscate("21.11.234.23")  # => "65.87.891.45"

With options

# Don't preserve leading zeros
obfuscator = NumberObfuscator.new(preserve_leading_zeros: false)
obfuscator.obfuscate("0042") # => "7391"

# Remove signs from negative numbers
obfuscator = NumberObfuscator.new(unsigned: true)
obfuscator.obfuscate("-123") # => "456"

# Use seed for reproducible results
obfuscator = NumberObfuscator.new(seed: 12345)
obfuscator.obfuscate("123.45") # => Same result for same seed

Raises:

  • (Error)

    If number obfuscation fails

  • (InputError)

    If input is neither Numeric nor String

Constant Summary collapse

FormatError =
Class.new(Error)
RangeError =
Class.new(Error)
UPPERCASE_CYRILLIC =

Consider memoizing character sets

('А'..'Я').to_a - ['Ё']
LOWERCASE_CYRILLIC =
('а'..'я').to_a - ['ё']

Instance Method Summary collapse

Constructor Details

#initialize(preserve_leading_zeros: true, unsigned: false, seed: nil) ⇒ NumberObfuscator

Returns a new instance of NumberObfuscator.



71
72
73
74
75
76
# File 'lib/obfuscator/number_obfuscator.rb', line 71

def initialize(preserve_leading_zeros: true, unsigned: false, seed: nil)
  @preserve_leading_zeros = preserve_leading_zeros
  @unsigned = unsigned
  @seed = seed # Store seed for reuse
  setup_rng(seed)
end

Instance Method Details

#obfuscate(input) ⇒ Object



78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
# File 'lib/obfuscator/number_obfuscator.rb', line 78

def obfuscate(input)
  return input if input.nil? || (input.is_a?(String) && input.empty?)

  # Create a unique seed based on both the original seed and input
  if @seed
    combined_seed = [@seed, input.to_s].hash
    setup_rng(combined_seed)
  end

  # Handle unsigned option at the entry point
  input = if @unsigned && input.is_a?(String)
            input.gsub(/^-/, '')
          elsif @unsigned && input.is_a?(Numeric)
            input.abs
          else
            input
          end

  case input
  when Numeric
    obfuscate_numeric(input)
  when String
    obfuscate_string(input)
  else
    raise InputError, "Input must be Numeric or String, got: #{input.class}"
  end
rescue InputError
  raise
rescue StandardError => e
  raise Error, "Number obfuscation error: #{e.message}"
end