class Amka::Luhn

Implements the Luhn algorithm as described in the wikipedia article en.wikipedia.org/wiki/Luhn_algorithm

Public Class Methods

generate(total, id_start = '') click to toggle source
# File lib/amka/luhn.rb, line 14
def self.generate(total, id_start = '')
  validate_generate_args_or_fail(total, id_start)
  id_start == '' && total == 1 and return '0'

  last_digits_length = total - id_start.length
  last_digits_except_check = ''
  # subtract by one to account for the check digit
  (last_digits_length - 1).times { last_digits_except_check << rand(0..9).to_s }
  luhn_id_except_check_digit = id_start << last_digits_except_check

  digits_sum = calculate_digits_sum(luhn_id_except_check_digit, true)

  check_digit = (digits_sum * 9) % 10

  luhn_id_except_check_digit << check_digit.to_s
end
valid?(luhn_id) click to toggle source
# File lib/amka/luhn.rb, line 6
def self.valid?(luhn_id)
  Utils.string_with_digits_or_fail luhn_id

  digits_sum = calculate_digits_sum(luhn_id)

  (digits_sum % 10) == 0
end

Private Class Methods

calculate_digits_sum(luhn_id, generate = false) click to toggle source
# File lib/amka/luhn.rb, line 31
def self.calculate_digits_sum(luhn_id, generate = false)
  luhn_id_double = luhn_id.chars.reverse.map(&:to_i).map.with_index do |digit, i|
    if (!generate && i.odd?) || (generate && i.even?)
      if (digit *= 2) > 9
        # digit = digit.to_s.chars.map(&:to_i).reduce(:+)
        digit -= 9
      end
    end
    digit
  end
  luhn_id_double.reduce(:+)
end
validate_generate_args_or_fail(total, id_start) click to toggle source
# File lib/amka/luhn.rb, line 45
def self.validate_generate_args_or_fail(total, id_start)
  Utils.string_with_digits_or_empty_or_fail id_start
  Utils.positive_integer_or_fail total
  total > id_start.length or
    fail ArgumentError, "'#{total}': must be greater at least by one from string length: "\
                        "#{id_start.length}, to account for the check digit!"
end