Class: Amka::Luhn
- Inherits:
-
Object
- Object
- Amka::Luhn
- Defined in:
- lib/amka/luhn.rb
Overview
Implements the Luhn algorithm as described in the wikipedia article en.wikipedia.org/wiki/Luhn_algorithm
The Luhn algorithm (also known as the “modulus 10” or “mod 10” algorithm) is a simple checksum formula used to validate various identification numbers, such as credit card numbers, IMEI numbers, and national identification numbers (like AMKA in Greece).
## Algorithm Steps
-
Starting from the rightmost digit, double the value of every second digit
-
If doubling a number results in a two-digit number (>9), subtract 9 from the result
-
Sum all digits (both doubled and non-doubled)
-
If the total modulo 10 is 0, then the number is valid
## Uses This class provides both validation of existing IDs and generation of new valid IDs that follow the Luhn algorithm.
Class Method Summary collapse
-
.generate(total, id_start = '') ⇒ String
Generates a valid Luhn ID.
-
.safe_valid?(luhn_id) ⇒ Boolean
Validates if a given ID follows the Luhn algorithm, without raising exceptions.
-
.valid?(luhn_id) ⇒ Boolean
Validates if a given ID follows the Luhn algorithm.
Class Method Details
.generate(total, id_start = '') ⇒ String
Generates a valid Luhn ID
Creates a number that passes the Luhn check by:
-
Taking the provided prefix (or creating a random one)
-
Calculating what the check digit should be for the number to be valid
-
Appending the check digit to create a valid Luhn number
97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 |
# File 'lib/amka/luhn.rb', line 97 def self.generate(total, id_start = '') validate_generate_args_or_fail(total, id_start) return '0' if id_start.empty? && total == 1 last_digits_length = total - id_start.length # Use String.new to create an unfrozen string last_digits_except_check = String.new # subtract by one to account for the check digit (last_digits_length - 1).times { last_digits_except_check << rand(0..9).to_s } # Using + instead of << for string concatenation to prevent frozen string issues luhn_id_except_check_digit = id_start + last_digits_except_check digits_sum = calculate_digits_sum(luhn_id_except_check_digit, generate: true) check_digit = (digits_sum * 9) % 10 luhn_id_except_check_digit + check_digit.to_s end |
.safe_valid?(luhn_id) ⇒ Boolean
Validates if a given ID follows the Luhn algorithm, without raising exceptions
This is a safe version of valid? that returns false for any invalid input instead of raising exceptions. It’s designed for use in validation pipelines where exceptions would need to be caught.
67 68 69 70 71 72 73 74 75 76 77 78 |
# File 'lib/amka/luhn.rb', line 67 def self.safe_valid?(luhn_id) # Return false for non-string input return false unless luhn_id.is_a?(String) # Return false for strings with non-digits return false unless luhn_id.match(/\A\d+\Z/) digits_sum = calculate_digits_sum(luhn_id) (digits_sum % 10).zero? rescue StandardError # Catch any unexpected errors and return false false end |
.valid?(luhn_id) ⇒ Boolean
Validates if a given ID follows the Luhn algorithm
Applies the standard Luhn algorithm to check if a number is valid:
-
From the rightmost digit, double every second digit
-
Sum the digits (if any doubled digit > 9, subtract 9)
-
If the sum is divisible by 10, the number is valid
45 46 47 48 49 50 51 |
# File 'lib/amka/luhn.rb', line 45 def self.valid?(luhn_id) Utils.string_with_digits_or_fail(luhn_id) digits_sum = calculate_digits_sum(luhn_id) (digits_sum % 10).zero? end |