Module: Amka

Defined in:
lib/amka.rb,
lib/amka/luhn.rb,
lib/amka/utils.rb,
lib/amka/version.rb

Overview

The Amka module provides functionality for validating and generating Greek A.M.K.A (social security) IDs as well as generic Luhn algorithm IDs. A.M.K.A IDs follow the Luhn algorithm and have their first 6 digits representing the date of birth in format DDMMYY.

An AMKA (Αριθμός Μητρώου Κοινωνικής Ασφάλισης) is a unique 11-digit number assigned to each Greek citizen or resident who works, pays social security contributions, or is entitled to healthcare. It follows these rules:

  1. The first 6 digits represent the date of birth in format DDMMYY

  2. The remaining 5 digits include a check digit based on the Luhn algorithm

  3. The total length is always 11 digits

Examples:

Validating an AMKA

Amka.valid?('01018012345')  #=> true or false

Generating a random AMKA

Amka.generate  #=> "21129012345"

Generating an AMKA with specific birth date

Amka.generate('21/12/1990')  #=> "21129012345"

Author:

  • Ioannis Angelakopoulos

Since:

  • 1.0.0

Defined Under Namespace

Classes: Error, Luhn, Utils, ValidationError

Constant Summary collapse

VERSION =

Since:

  • 1.0.0

'2.1.0'

Class Method Summary collapse

Class Method Details

.generate(date_of_birth = nil) ⇒ String

Generates a random valid AMKA

This method can create an AMKA with either:

  • A random valid birth date (when called without parameters)

  • A specific birth date (when called with a date parameter)

The generated AMKA will always satisfy all validation rules:

  • 11 digits in length

  • First 6 digits form a valid date

  • Passes the Luhn algorithm check

Examples:

Generate a random AMKA

Amka.generate  #=> "01011912345"

Generate an AMKA with specific birth date

Amka.generate('1/1/1990')  #=> "01019012345"

Parameters:

  • date_of_birth (String, nil) (defaults to: nil)

    optional date in format ‘dd/mm/yyyy’

Returns:

  • (String)

    a valid AMKA with the first 6 digits representing the birth date, and the remainder satisfying the Luhn algorithm

Since:

  • 1.0.0



190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
# File 'lib/amka.rb', line 190

def self.generate(date_of_birth = nil)
  return generate_with_date_of_birth(date_of_birth) unless date_of_birth.nil?

  date_6_digits = String.new
  loop do
    day = "#{rand(0..3)}#{rand(0..9)}"
    next if day == '00' || day.to_i > 31

    month = "#{rand(0..1)}#{rand(0..2)}"
    next if month == '00' || month.to_i > 12

    year = "#{rand(19..20)}#{rand(0..9)}#{rand(0..9)}"
    next if year.to_i > Date.today.year

    date = day + month + year[2..3]
    if Utils.valid_date?(date, year)
      date_6_digits = date
      break
    end
  end

  Luhn.generate(11, date_6_digits)
end

.valid?(amka, year = nil) ⇒ Boolean

Validates whether a given string is a valid AMKA

The validation checks three conditions:

  1. The AMKA must be exactly 11 digits long

  2. The first 6 digits must form a valid date (DDMMYY format)

  3. The entire number must satisfy the Luhn algorithm check

This method will always return a boolean and never raise exceptions, returning false for any input that doesn’t meet the AMKA criteria.

Examples:

Validating with default century assumption

Amka.valid?('17019012345')  #=> true

Validating with explicit year

Amka.valid?('17019012345', '1990')  #=> true

Validating invalid input

Amka.valid?(nil)  #=> false
Amka.valid?(12345)  #=> false
Amka.valid?('abc123')  #=> false

Parameters:

  • amka (Object)

    the AMKA to validate, should be a string containing only digits

  • year (String, nil) (defaults to: nil)

    optional four-digit year to match against When provided, improves the validation by ensuring the birth year matches exactly (resolves century ambiguity in 2-digit years)

Returns:

  • (Boolean)

    true if all validation criteria are met, false otherwise

Since:

  • 1.0.0



60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
# File 'lib/amka.rb', line 60

def self.valid?(amka, year = nil)
  # Return false for non-string input
  return false unless amka.is_a?(String)
  # Return false for strings with non-digits
  return false unless amka.match(/\A\d+\Z/)
  # Check length requirement
  return false unless length_is_11?(amka)

  # Check if date and Luhn algorithm are valid
  begin
    return false unless Utils.valid_date?(amka, year)

    Luhn.safe_valid?(amka)
  rescue ArgumentError
    # If any validation raises an exception, the AMKA is invalid
    false
  end
end

.validate(amka, year = nil) ⇒ Array<String>

Validates an AMKA and returns an array of validation errors

This method provides detailed feedback about why validation failed, returning an empty array for valid AMKAs or an array of error messages for invalid ones.

Examples:

Get validation errors

errors = Amka.validate(input)
if errors.empty?
  puts "Valid AMKA!"
else
  puts "Invalid AMKA: #{errors.join(', ')}"
end

Parameters:

  • amka (Object)

    the AMKA to validate

  • year (String, nil) (defaults to: nil)

    optional four-digit year to match against

Returns:

  • (Array<String>)

    empty array if valid, otherwise contains error messages

Since:

  • 1.0.0



95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
# File 'lib/amka.rb', line 95

def self.validate(amka, year = nil)
  errors = []

  # Check for basic format issues and return early if found
  basic_format_errors = check_basic_format(amka)
  return basic_format_errors unless basic_format_errors.empty?

  # Check length
  errors << 'AMKA must be exactly 11 digits long' unless length_is_11?(amka)

  # Check date format
  check_date(errors, amka, year)

  # Check Luhn algorithm
  check_luhn(errors, amka)

  errors
end

.validate!(amka, year = nil) ⇒ true

Strictly validates an AMKA and raises exceptions for invalid input

Similar to valid? but raises specific exceptions when validation fails, which is useful for cases where you need detailed error information or when you prefer exceptions for control flow.

Examples:

Strict validation with exception handling

begin
  Amka.validate!('17019012345')  #=> true (if valid)
rescue Amka::ValidationError => e
  puts e.message  # Contains detailed error info
end

Parameters:

  • amka (Object)

    the AMKA to validate

  • year (String, nil) (defaults to: nil)

    optional four-digit year to match against

Returns:

  • (true)

    if the AMKA is valid

Raises:

Since:

  • 1.0.0



164
165
166
167
168
169
170
# File 'lib/amka.rb', line 164

def self.validate!(amka, year = nil)
  errors = validate(amka, year)

  raise ValidationError, errors.first unless errors.empty?

  true
end