amka 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 76922012dc2b85729db33348da7753fc164eed0b
4
+ data.tar.gz: d3260e6a18b05709bc15267203cbbe736af86f99
5
+ SHA512:
6
+ metadata.gz: cac4f4858fb5a86a16b4d6f3691ab1fb9e0dc05710d204b99df4ca07dc471ed134e248982e78eaa8dff9b5e6929f9d264a7d5fc4bc0bbcf34d449e20b1961f15
7
+ data.tar.gz: 54479b23df39970651323b2a2760d93ba810f67caf93d2e85f2dacd05376681d1b905a0d67a864986def51cbcb87cba66fcf33fc51b8ccbf6c2ae179bbeeae6b
data/.gitignore ADDED
@@ -0,0 +1,9 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ 2.2.3@amka
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in amka.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2015 Ioannis Angelakopoulos
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,80 @@
1
+ # AMKA and Luhn IDs Validator / Generator
2
+ ##### Α.Μ.Κ.Α (Αριθμός Μητρώου Κοινωνικής Ασφάλισης)
3
+ This gem validates **A.M.K.A** Greek social security IDs by
4
+ using the Luhn algorithm, as described in this [Wikipedia article](https://en.wikipedia.org/wiki/Luhn_algorithm).
5
+ The only additional validation needed that applies to Greek A.M.K.A is that the
6
+ first 6 digits must be a valid date (date of birth).
7
+
8
+ The gem also *validates* and *generates* **Luhn** ids, as well as *generating*
9
+ **AMKA** (like) ids. The *like* here means that the AMKA generated are not
10
+ **real** as those provided by the Official Authorities in Greece.
11
+
12
+ There is an online calculator in [planetcalc](http://planetcalc.com/2464/), you
13
+ can validate the results of the gem, until you are confident that is working
14
+ as it should. Try you own and your family AMKA.
15
+
16
+ **DISCLAIMER**: The gem *does not* validate the real existence of the A.M.K.A or that it
17
+ belongs to a given person. The same applies to the generator.
18
+
19
+ ## Installation
20
+
21
+ Add this line to your application's Gemfile:
22
+
23
+ ```ruby
24
+ gem 'amka'
25
+ ```
26
+
27
+ And then execute:
28
+
29
+ $ bundle
30
+
31
+ Or install it yourself as:
32
+
33
+ $ gem install amka
34
+
35
+ ## Usage
36
+
37
+ ```ruby
38
+ require 'amka'
39
+
40
+ # To validate (takes the AMKA as a string and returns true or false)
41
+ Amka.valid?('01011441432')
42
+ # returns false (i did not use a valid one in this example just in case
43
+ # it belonged to a real person!!!!)
44
+
45
+ # To generate (returns the AMKA as a string)
46
+ Amka.generate
47
+
48
+ # To generate with a specific date (date format: [d]d/[m]m/yyyy)
49
+ # returns: 101190xxxxx
50
+ Amka.generate('10/11/1990')
51
+
52
+ ###### Bonus ######
53
+
54
+ # To validate any number against the Luhn algorithm
55
+ Amka::Luhn.valid?('1142376755673') # returns true
56
+
57
+ # To generate a Luhn id
58
+ # takes up to 2 arguments: total, id_start(optional)
59
+ # total: how many digits you want in the Luhn generated
60
+ # id_start: string of numbers to include from the start of the Luhn
61
+ # - total must be greater than id_start by at least one, to account for the
62
+ # rightmost check digit.
63
+ Amka::Luhn.generate(13) # returns '5361281695669'
64
+ Amka::Luhn.generate(10, '123456789') # returns '1234567897', 7 is the check digit.
65
+ Amka::Luhn.generate(15, '12345') # returns something like: '123450789968798'
66
+ ```
67
+
68
+ ## TODO
69
+
70
+ Add tests for the Luhn class.
71
+
72
+ ## Contributing
73
+
74
+ Bug reports and pull requests are welcome on GitHub at https://github.com/ioagel/amka.
75
+
76
+
77
+ ## License
78
+
79
+ The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
80
+
data/Rakefile ADDED
@@ -0,0 +1,8 @@
1
+ require 'bundler/gem_tasks'
2
+
3
+ require 'rake/testtask'
4
+
5
+ Rake::TestTask.new do |t|
6
+ t.libs << 'test'
7
+ t.pattern = 'test/*_test.rb'
8
+ end
data/amka.gemspec ADDED
@@ -0,0 +1,27 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'amka/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "amka"
8
+ spec.version = Amka::VERSION
9
+ spec.authors = ["Ioannis Angelakopoulos"]
10
+ spec.email = ["ioagel@gmail.com"]
11
+
12
+ spec.summary = %q{AMKA/Luhn IDs Generator and Validator}
13
+ spec.description = %q{Generates and Validates Greek A.M.K.A (social security number) and Luhn IDs, using the Luhn algorithm. DISCLAIMER: It does not validate the real existence of the A.M.K.A or that it belongs to a given person. The same applies to the generator.}
14
+ spec.homepage = "https://github.com/ioagel/amka"
15
+ spec.license = "MIT"
16
+
17
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
18
+ spec.bindir = "exe"
19
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
20
+ spec.require_paths = ["lib"]
21
+
22
+ spec.add_development_dependency "minitest"
23
+ spec.add_development_dependency "minitest-reporters"
24
+ spec.add_development_dependency "mocha"
25
+ spec.add_development_dependency "bundler", "~> 1.10"
26
+ spec.add_development_dependency "rake", "~> 10.0"
27
+ end
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "amka"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start
data/bin/setup ADDED
@@ -0,0 +1,7 @@
1
+ #!/bin/bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+
5
+ bundle install
6
+
7
+ # Do any other automated setup that you need to do here
data/lib/amka.rb ADDED
@@ -0,0 +1,56 @@
1
+ require 'amka/version'
2
+ require 'date'
3
+
4
+ module Amka
5
+
6
+ def self.valid?(amka, year = nil)
7
+ Utils.string_with_digits_or_fail amka
8
+
9
+ return false unless length_is_11?(amka)
10
+
11
+ return Luhn.valid?(amka) if Utils.valid_date?(amka, year)
12
+
13
+ false
14
+ end
15
+
16
+ def self.generate(date_of_birth = nil)
17
+ return generate_with_date_of_birth(date_of_birth) unless date_of_birth.nil?
18
+
19
+ date_6_digits = ''
20
+ loop do
21
+ day = rand(0..3).to_s << rand(0..9).to_s
22
+ next if day == '00' || day.to_i > 31
23
+ month = rand(0..1).to_s << rand(0..2).to_s
24
+ next if month == '00' || month.to_i > 12
25
+ year = rand(19..20).to_s << rand(0..9).to_s << rand(0..9).to_s
26
+ next if year.to_i > Date.today.year
27
+
28
+ if Utils.valid_date?(date = day << month << year[2..3], year)
29
+ date_6_digits = date
30
+ break
31
+ end
32
+ end
33
+
34
+ Luhn.generate(11, date_6_digits)
35
+ end
36
+
37
+ def self.generate_with_date_of_birth(date_of_birth)
38
+ Utils.string_with_date_or_fail date_of_birth
39
+
40
+ day, month, year = date_of_birth.split('/').map { |i| i.length == 1 && ('0' << i) or i }
41
+ date_6_digit = day << month << year[2..3]
42
+ fail ArgumentError, 'The date of birth is invalid!' unless Utils.valid_date?(date_6_digit, year)
43
+
44
+ Luhn.generate(11, date_6_digit)
45
+ end
46
+ private_class_method :generate_with_date_of_birth
47
+
48
+ def self.length_is_11?(id)
49
+ id.length == 11
50
+ end
51
+ private_class_method :length_is_11?
52
+
53
+ end
54
+
55
+ require 'amka/luhn'
56
+ require 'amka/utils'
data/lib/amka/luhn.rb ADDED
@@ -0,0 +1,55 @@
1
+ module Amka
2
+ # Implements the Luhn algorithm as described in the wikipedia article
3
+ # https://en.wikipedia.org/wiki/Luhn_algorithm
4
+ class Luhn
5
+
6
+ def self.valid?(luhn_id)
7
+ Utils.string_with_digits_or_fail luhn_id
8
+
9
+ digits_sum = calculate_digits_sum(luhn_id)
10
+
11
+ (digits_sum % 10) == 0
12
+ end
13
+
14
+ def self.generate(total, id_start = '')
15
+ validate_generate_args_or_fail(total, id_start)
16
+ id_start == '' && total == 1 and return '0'
17
+
18
+ last_digits_length = total - id_start.length
19
+ last_digits_except_check = ''
20
+ # subtract by one to account for the check digit
21
+ (last_digits_length - 1).times { last_digits_except_check << rand(0..9).to_s }
22
+ luhn_id_except_check_digit = id_start << last_digits_except_check
23
+
24
+ digits_sum = calculate_digits_sum(luhn_id_except_check_digit, true)
25
+
26
+ check_digit = (digits_sum * 9) % 10
27
+
28
+ luhn_id_except_check_digit << check_digit.to_s
29
+ end
30
+
31
+ def self.calculate_digits_sum(luhn_id, generate = false)
32
+ luhn_id_double = luhn_id.chars.reverse.map(&:to_i).map.with_index do |digit, i|
33
+ if (!generate && i.odd?) || (generate && i.even?)
34
+ if (digit *= 2) > 9
35
+ # digit = digit.to_s.chars.map(&:to_i).reduce(:+)
36
+ digit -= 9
37
+ end
38
+ end
39
+ digit
40
+ end
41
+ luhn_id_double.reduce(:+)
42
+ end
43
+ private_class_method :calculate_digits_sum
44
+
45
+ def self.validate_generate_args_or_fail(total, id_start)
46
+ Utils.string_with_digits_or_empty_or_fail id_start
47
+ Utils.positive_integer_or_fail total
48
+ total > id_start.length or
49
+ fail ArgumentError, "'#{total}': must be greater at least by one from string length: "\
50
+ "#{id_start.length}, to account for the check digit!"
51
+ end
52
+ private_class_method :validate_generate_args_or_fail
53
+
54
+ end
55
+ end
data/lib/amka/utils.rb ADDED
@@ -0,0 +1,57 @@
1
+ module Amka
2
+
3
+ class Utils
4
+ class << self
5
+ def string_with_digits_or_fail(id)
6
+ id.is_a?(String) && id.match(/\A\d+\Z/) or
7
+ fail ArgumentError, "'#{id}': must be a string of digits only!"
8
+ end
9
+
10
+ def string_with_digits_or_empty_or_fail(id)
11
+ id.is_a?(String) && id.match(/\A\d*\Z/) or
12
+ fail ArgumentError, "'#{id}': must be a string of digits or even an empty one!"
13
+ end
14
+
15
+ def string_with_date_or_fail(date)
16
+ date.is_a?(String) && date.match(%r{\A\d?\d{1}/\d?\d{1}/\d{4}\Z}) or
17
+ fail ArgumentError, 'date of birth must be in this format: [d]d/[m]m/yyyy'
18
+ end
19
+
20
+ def positive_integer_or_fail(num)
21
+ num.is_a?(Integer) && num > 0 or
22
+ fail ArgumentError, "'#{num}': must be a non-zero positive integer!"
23
+ end
24
+
25
+ def valid_date?(date, year = nil)
26
+ return false unless date.match(/\A\d{6,}\Z/)
27
+
28
+ unless year.nil?
29
+ year.is_a?(String) && year.match(/\A\d{4}\Z/) or
30
+ fail ArgumentError, 'Year must be a 4 digit string'
31
+ year.to_i >= 1800 && year.to_i <= Date.today.year or
32
+ fail ArgumentError, 'Year must be between 1800 and current!'
33
+ year[2..3] == date[4..5] or
34
+ fail ArgumentError, 'The last 2 digits of year parameter and the 2 digits'\
35
+ ' that correspond to the year in date must be equal!'
36
+ begin
37
+ dob = Date.strptime(date[0..3] << year, '%d%m%Y')
38
+ return dob < Date.today
39
+ rescue ArgumentError
40
+ return false
41
+ end
42
+ end
43
+
44
+ begin
45
+ date_2_digit_year = Date.strptime(date[0..5], '%d%m%y')
46
+ if date_2_digit_year > Date.today
47
+ Date.strptime(date[0..3] << '19' << date[4..5], '%d%m%Y')
48
+ end
49
+ return true
50
+ rescue ArgumentError
51
+ return false
52
+ end
53
+ end
54
+ end
55
+ end
56
+
57
+ end
@@ -0,0 +1,3 @@
1
+ module Amka
2
+ VERSION = '1.0.0'
3
+ end
metadata ADDED
@@ -0,0 +1,129 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: amka
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Ioannis Angelakopoulos
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2015-12-16 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: minitest
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: minitest-reporters
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: mocha
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: bundler
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '1.10'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '1.10'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rake
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '10.0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '10.0'
83
+ description: 'Generates and Validates Greek A.M.K.A (social security number) and Luhn
84
+ IDs, using the Luhn algorithm. DISCLAIMER: It does not validate the real existence
85
+ of the A.M.K.A or that it belongs to a given person. The same applies to the generator.'
86
+ email:
87
+ - ioagel@gmail.com
88
+ executables: []
89
+ extensions: []
90
+ extra_rdoc_files: []
91
+ files:
92
+ - ".gitignore"
93
+ - ".ruby-version"
94
+ - Gemfile
95
+ - LICENSE.txt
96
+ - README.md
97
+ - Rakefile
98
+ - amka.gemspec
99
+ - bin/console
100
+ - bin/setup
101
+ - lib/amka.rb
102
+ - lib/amka/luhn.rb
103
+ - lib/amka/utils.rb
104
+ - lib/amka/version.rb
105
+ homepage: https://github.com/ioagel/amka
106
+ licenses:
107
+ - MIT
108
+ metadata: {}
109
+ post_install_message:
110
+ rdoc_options: []
111
+ require_paths:
112
+ - lib
113
+ required_ruby_version: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ required_rubygems_version: !ruby/object:Gem::Requirement
119
+ requirements:
120
+ - - ">="
121
+ - !ruby/object:Gem::Version
122
+ version: '0'
123
+ requirements: []
124
+ rubyforge_project:
125
+ rubygems_version: 2.5.0
126
+ signing_key:
127
+ specification_version: 4
128
+ summary: AMKA/Luhn IDs Generator and Validator
129
+ test_files: []