luhn-check 0.0.2 → 0.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.rspec +1 -0
- data/Gemfile +5 -0
- data/README.md +10 -8
- data/Rakefile +13 -5
- data/lib/luhn.rb +1 -74
- data/lib/luhn/base.rb +64 -0
- data/lib/luhn/version.rb +1 -1
- data/luhn-check.gemspec +1 -3
- data/spec/lib/luhn/base_spec.rb +102 -0
- data/spec/lib/luhn_spec.rb +8 -0
- data/spec/spec_helper.rb +9 -0
- metadata +11 -35
- data/test/luhn_test.rb +0 -102
- data/test/test_helper.rb +0 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 38fde38a04d580ba1a409e99ccf4d3040ed3ab6c
|
4
|
+
data.tar.gz: ce07177a330063ee447a983a877372ebc36e1570
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c755af25e01c4fc9f1605f0a57503ec3918edf05fe80d3622eb1aa2664b0ec12caf1ebd6f24b5b35edef9a9b44cf2e69855285790425374cf68929ca90b5c7bf
|
7
|
+
data.tar.gz: 9315757d6e9df937d731ce557a742a6b939ff4873bb0e28f6d3129ec9d05f21948b990625d3d56c2866af3378543e5ea66851b093ca3000c51c567fdc6df27d7
|
data/.rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--color
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -1,14 +1,18 @@
|
|
1
1
|
# Luhn check
|
2
2
|
|
3
|
-
With the luhn-check you can
|
3
|
+
With the luhn-check gem you can validate a number with the Luhn algoritme.
|
4
4
|
|
5
5
|
## Installation
|
6
6
|
### Version
|
7
|
-
`0.0.
|
7
|
+
`0.0.3`
|
8
|
+
|
9
|
+
###Gemfile
|
10
|
+
|
11
|
+
Since that the namespace in the `lib` directory is different than the name of the gem. You need to require the namespace of the class defined in the `lib` directory.
|
8
12
|
|
9
13
|
Add this line to your application's Gemfile:
|
10
14
|
|
11
|
-
gem 'luhn-check'
|
15
|
+
gem 'luhn-check', '~> 0.0.3', require: 'luhn'
|
12
16
|
|
13
17
|
And then execute:
|
14
18
|
|
@@ -20,17 +24,15 @@ Or install it yourself as:
|
|
20
24
|
|
21
25
|
## Usage
|
22
26
|
|
23
|
-
After the gem is installed.
|
24
|
-
|
25
|
-
To check if the number is valid with the Luhn algorithm:
|
27
|
+
After the gem is installed. You can use this method to validate the number with the Luhn algoritme:
|
26
28
|
|
27
29
|
```ruby
|
28
30
|
Luhn.valid?(number)
|
29
|
-
Luhn.calculate_check_digit(number)
|
30
|
-
Luhn.double_digits(number) # Array with digits for checksum
|
31
31
|
```
|
32
32
|
|
33
|
+
|
33
34
|
## Contributing
|
35
|
+
Pretty standard:
|
34
36
|
|
35
37
|
1. Fork it
|
36
38
|
2. Create your feature branch (`git checkout -b my-new-feature`)
|
data/Rakefile
CHANGED
@@ -1,7 +1,15 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
#!/usr/bin/env rake
|
2
|
+
begin
|
3
|
+
require 'bundler/setup'
|
4
|
+
require 'bundler/gem_tasks'
|
5
|
+
rescue LoadError
|
6
|
+
puts 'You must run `gem install bundler` and `bundle install` to run rake tasks'
|
7
|
+
end
|
8
|
+
|
9
|
+
require 'rspec/core/rake_task'
|
3
10
|
|
4
|
-
|
5
|
-
|
6
|
-
t.pattern = 'test/**/*_test.rb'
|
11
|
+
RSpec::Core::RakeTask.new(:core) do |spec|
|
12
|
+
spec.rspec_opts = ['--backtrace']
|
7
13
|
end
|
14
|
+
|
15
|
+
task :default => [:core]
|
data/lib/luhn.rb
CHANGED
@@ -1,77 +1,4 @@
|
|
1
|
-
require '
|
1
|
+
require 'luhn/base'
|
2
2
|
|
3
3
|
module Luhn
|
4
|
-
|
5
|
-
class << self
|
6
|
-
|
7
|
-
def ping
|
8
|
-
'pong'
|
9
|
-
end
|
10
|
-
|
11
|
-
def valid?(number)
|
12
|
-
checksum(number)
|
13
|
-
end
|
14
|
-
|
15
|
-
def calculate_check_digit(number)
|
16
|
-
number_without_check_digit = number.to_s[0...-1] + '0'
|
17
|
-
doubles = double_digits(number_without_check_digit.to_i)
|
18
|
-
sum = sum_of_all(doubles) unless null?(doubles)
|
19
|
-
product = sum * 9
|
20
|
-
get_check_digit(product)
|
21
|
-
end
|
22
|
-
|
23
|
-
def get_check_digit(number)
|
24
|
-
number.to_s[-1].to_i
|
25
|
-
end
|
26
|
-
|
27
|
-
def double_digits(number)
|
28
|
-
doubles = []
|
29
|
-
digits = all_digits(number).reverse
|
30
|
-
digits.each_with_index do |d, i|
|
31
|
-
if i.odd?
|
32
|
-
sum = d * 2
|
33
|
-
if sum && sum > 9
|
34
|
-
split_sum = sum.to_s.split(//).map(&:to_i)
|
35
|
-
make_sum = split_sum.inject { |sum, n| sum + n }
|
36
|
-
doubles << make_sum
|
37
|
-
else
|
38
|
-
doubles << sum
|
39
|
-
end
|
40
|
-
else
|
41
|
-
doubles << d
|
42
|
-
end
|
43
|
-
end
|
44
|
-
return doubles
|
45
|
-
end
|
46
|
-
|
47
|
-
protected
|
48
|
-
|
49
|
-
def checksum(number)
|
50
|
-
if null?(number)
|
51
|
-
return false
|
52
|
-
else
|
53
|
-
doubles = double_digits(number)
|
54
|
-
sum = sum_of_all(doubles)
|
55
|
-
sum % 10 == 0 ? true : false
|
56
|
-
end
|
57
|
-
end
|
58
|
-
|
59
|
-
def sum_of_all(doubles)
|
60
|
-
doubles.inject { |sum, n| sum + n }
|
61
|
-
end
|
62
|
-
|
63
|
-
def all_digits(number)
|
64
|
-
number.to_s.split(//).map(&:to_i)
|
65
|
-
end
|
66
|
-
|
67
|
-
def null?(number)
|
68
|
-
checked_number = all_digits(number).reject! { |d| d.eql?(0) }
|
69
|
-
if checked_number.nil?
|
70
|
-
return false
|
71
|
-
else
|
72
|
-
checked_number.empty? ? true : false
|
73
|
-
end
|
74
|
-
end
|
75
|
-
|
76
|
-
end
|
77
4
|
end
|
data/lib/luhn/base.rb
ADDED
@@ -0,0 +1,64 @@
|
|
1
|
+
class Base
|
2
|
+
attr_reader :number_to_validate
|
3
|
+
|
4
|
+
def initialize(number_to_validate)
|
5
|
+
@number_to_validate = number_to_validate
|
6
|
+
end
|
7
|
+
|
8
|
+
def self.valid?(number)
|
9
|
+
new(number).validate
|
10
|
+
end
|
11
|
+
|
12
|
+
def validate
|
13
|
+
checksum % 10 == 0 if number_meets_requirements?
|
14
|
+
end
|
15
|
+
|
16
|
+
def check_digit
|
17
|
+
checksum.to_s[-1].to_i
|
18
|
+
end
|
19
|
+
|
20
|
+
def checksum
|
21
|
+
@checksum ||= double_digit_on_even_position.inject(:+)
|
22
|
+
end
|
23
|
+
|
24
|
+
def double_digit_on_even_position
|
25
|
+
total = []
|
26
|
+
# Offset of 1, so you can call even? instead of odd? on a number_position
|
27
|
+
digits_of_number_to_validate.to_enum.with_index(1).each do |digit, number_position|
|
28
|
+
if number_position.even? && product_of_digit_exceeds_nine(digit)
|
29
|
+
digits_of_product = split_to_number_array multiply(digit)
|
30
|
+
total << digits_of_product.inject(:+)
|
31
|
+
elsif number_position.even? && !product_of_digit_exceeds_nine(digit)
|
32
|
+
total << multiply(digit)
|
33
|
+
else
|
34
|
+
total << digit
|
35
|
+
end
|
36
|
+
end
|
37
|
+
total
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
def number_meets_requirements?
|
43
|
+
true unless number_to_validate.class == String ||
|
44
|
+
number_to_validate == 0
|
45
|
+
end
|
46
|
+
|
47
|
+
def digits_of_number_to_validate
|
48
|
+
# Reverse number_to_validate to start
|
49
|
+
# the itteration from right to left
|
50
|
+
split_to_number_array(number_to_validate).reverse
|
51
|
+
end
|
52
|
+
|
53
|
+
def split_to_number_array(numbers)
|
54
|
+
numbers.to_s.split(//).map(&:to_i)
|
55
|
+
end
|
56
|
+
|
57
|
+
def product_of_digit_exceeds_nine(digit)
|
58
|
+
multiply(digit) > 9
|
59
|
+
end
|
60
|
+
|
61
|
+
def multiply(digit)
|
62
|
+
digit * 2
|
63
|
+
end
|
64
|
+
end
|
data/lib/luhn/version.rb
CHANGED
data/luhn-check.gemspec
CHANGED
@@ -16,11 +16,9 @@ Gem::Specification.new do |spec|
|
|
16
16
|
|
17
17
|
spec.files = `git ls-files`.split($/)
|
18
18
|
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
19
|
-
spec.test_files = spec.files.grep(%r{^(
|
19
|
+
spec.test_files = spec.files.grep(%r{^(spec)/})
|
20
20
|
spec.require_paths = ["lib"]
|
21
21
|
|
22
|
-
spec.add_development_dependency 'pry'
|
23
|
-
spec.add_development_dependency 'minitest'
|
24
22
|
spec.add_development_dependency "bundler", "~> 1.3"
|
25
23
|
spec.add_development_dependency "rake"
|
26
24
|
end
|
@@ -0,0 +1,102 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Base do
|
4
|
+
let(:base) { described_class.new(12345) }
|
5
|
+
|
6
|
+
describe 'attributes' do
|
7
|
+
it 'responds to attribute' do
|
8
|
+
[:number_to_validate].each do |attr|
|
9
|
+
expect(base).to respond_to attr
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
## Class methods
|
15
|
+
describe '.valid?' do
|
16
|
+
context 'validate numbers' do
|
17
|
+
# Different test creditcardnumbers from: Visa,
|
18
|
+
# American Express, Diners Club and Mastercard
|
19
|
+
let(:validate_numbers) { [4556974027974373, 4539085529167499, 5247381631434707, 4111111111111111,
|
20
|
+
5555555555554444, 5511828555531982, 371449635398431, 4716165622199,
|
21
|
+
869940826641794, 180002230256255, 3096704907107219, 214937935327366,
|
22
|
+
6011312159763625, 38442242218311] }
|
23
|
+
|
24
|
+
it 'returns true' do
|
25
|
+
validate_numbers.each do |number|
|
26
|
+
expect(described_class.valid?(number)).to be_true
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
context 'invalid numbers' do
|
32
|
+
let(:invalid_numbers) { [3844224221831, 601111111111117, 1234123412341234, 1234567890123456, 111111,
|
33
|
+
22222222222000, 1111111111111111, 00010000, 23.67, 0000000000000000, '123']}
|
34
|
+
|
35
|
+
it 'returns false' do
|
36
|
+
invalid_numbers.each do |number|
|
37
|
+
expect(described_class.valid?(number)).to be_false
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
## Instance methods
|
44
|
+
describe '.validate' do
|
45
|
+
describe 'validates the checksum' do
|
46
|
+
context 'modulo 10 is equal to 0' do
|
47
|
+
before { described_class.any_instance.
|
48
|
+
stub(:checksum).and_return 60 }
|
49
|
+
|
50
|
+
it 'returns true' do
|
51
|
+
expect(base.validate).to be_true
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
context 'modulo 10 is NOT equal to 0' do
|
56
|
+
before { described_class.any_instance.
|
57
|
+
stub(:checksum).and_return 12 }
|
58
|
+
|
59
|
+
it 'returns false' do
|
60
|
+
expect(base.validate).to be_false
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
describe '.check_digit' do
|
67
|
+
before { described_class.any_instance.
|
68
|
+
stub(:checksum).and_return 126 }
|
69
|
+
|
70
|
+
it 'calculates the check_digit out of the checksum' do
|
71
|
+
expect(base.check_digit).to eql 6
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
describe '.checksum' do
|
76
|
+
before { described_class.any_instance.
|
77
|
+
stub(:double_digit_on_even_position).
|
78
|
+
and_return [1,2,3,4,5] }
|
79
|
+
|
80
|
+
it 'sums up the double_digit_on_even_position' do
|
81
|
+
expect(base.checksum).to eql 15
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
describe '.double_digit_on_even_position' do
|
86
|
+
subject { described_class.new(7992739871).double_digit_on_even_position }
|
87
|
+
|
88
|
+
describe 'reverses the numberset and on a even position of a digit' do
|
89
|
+
it 'doubles and sums number' do
|
90
|
+
expect(subject).to eql [1, 5, 8, 9, 3, 5, 2, 9, 9, 5]
|
91
|
+
end
|
92
|
+
|
93
|
+
context 'number ends with 0' do
|
94
|
+
subject { described_class.new(8960).double_digit_on_even_position }
|
95
|
+
|
96
|
+
it 'keeps the 0, doubles and sums number' do
|
97
|
+
expect(subject).to eql [0,3,9,7]
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
data/spec/spec_helper.rb
ADDED
metadata
CHANGED
@@ -1,43 +1,15 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: luhn-check
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jan van der Pas
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2013-
|
11
|
+
date: 2013-11-25 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
|
-
- !ruby/object:Gem::Dependency
|
14
|
-
name: pry
|
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
|
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
13
|
- !ruby/object:Gem::Dependency
|
42
14
|
name: bundler
|
43
15
|
requirement: !ruby/object:Gem::Requirement
|
@@ -74,15 +46,18 @@ extensions: []
|
|
74
46
|
extra_rdoc_files: []
|
75
47
|
files:
|
76
48
|
- .gitignore
|
49
|
+
- .rspec
|
77
50
|
- Gemfile
|
78
51
|
- LICENSE.txt
|
79
52
|
- README.md
|
80
53
|
- Rakefile
|
81
54
|
- lib/luhn.rb
|
55
|
+
- lib/luhn/base.rb
|
82
56
|
- lib/luhn/version.rb
|
83
57
|
- luhn-check.gemspec
|
84
|
-
-
|
85
|
-
-
|
58
|
+
- spec/lib/luhn/base_spec.rb
|
59
|
+
- spec/lib/luhn_spec.rb
|
60
|
+
- spec/spec_helper.rb
|
86
61
|
homepage: https://github.com/JanDintel/luhn-check
|
87
62
|
licenses:
|
88
63
|
- MIT
|
@@ -103,10 +78,11 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
103
78
|
version: '0'
|
104
79
|
requirements: []
|
105
80
|
rubyforge_project:
|
106
|
-
rubygems_version: 2.
|
81
|
+
rubygems_version: 2.1.11
|
107
82
|
signing_key:
|
108
83
|
specification_version: 4
|
109
84
|
summary: Check a number with the Luhn algorithm
|
110
85
|
test_files:
|
111
|
-
-
|
112
|
-
-
|
86
|
+
- spec/lib/luhn/base_spec.rb
|
87
|
+
- spec/lib/luhn_spec.rb
|
88
|
+
- spec/spec_helper.rb
|
data/test/luhn_test.rb
DELETED
@@ -1,102 +0,0 @@
|
|
1
|
-
require 'test_helper'
|
2
|
-
|
3
|
-
describe 'Luhn' do
|
4
|
-
|
5
|
-
it 'returns pong' do
|
6
|
-
Luhn.ping.must_equal('pong')
|
7
|
-
end
|
8
|
-
|
9
|
-
describe 'check_digit' do
|
10
|
-
|
11
|
-
describe 'only for valid numbers' do
|
12
|
-
|
13
|
-
describe '.calculate_check_digit' do
|
14
|
-
|
15
|
-
it 'computes the check digit' do
|
16
|
-
Luhn.calculate_check_digit(79927398713).must_equal(3)
|
17
|
-
Luhn.calculate_check_digit(4539085529167499).must_equal(9)
|
18
|
-
Luhn.calculate_check_digit(6011312159763625).must_equal(5)
|
19
|
-
Luhn.calculate_check_digit(4111111111111111).must_equal(1)
|
20
|
-
Luhn.calculate_check_digit(180002230256255).must_equal(5)
|
21
|
-
Luhn.calculate_check_digit(6011312159763625).must_equal(5)
|
22
|
-
end
|
23
|
-
end
|
24
|
-
end
|
25
|
-
|
26
|
-
describe 'for all numbers' do
|
27
|
-
|
28
|
-
describe '.get_check_digit' do
|
29
|
-
|
30
|
-
it 'get last digit of number' do
|
31
|
-
Luhn.get_check_digit(123).must_equal(3)
|
32
|
-
Luhn.get_check_digit(7992739871).must_equal(1)
|
33
|
-
Luhn.get_check_digit(492965255140195).must_equal(5)
|
34
|
-
Luhn.get_check_digit(402400711116634).must_equal(4)
|
35
|
-
Luhn.get_check_digit(199600).must_equal(0)
|
36
|
-
Luhn.get_check_digit(4556974027974373).must_equal(3)
|
37
|
-
end
|
38
|
-
end
|
39
|
-
end
|
40
|
-
end
|
41
|
-
|
42
|
-
describe '.double_digits' do
|
43
|
-
|
44
|
-
describe 'sum is greater than 9' do
|
45
|
-
|
46
|
-
it 'computes the sum the digits of the sum' do
|
47
|
-
Luhn.double_digits(50).must_equal([0,1])
|
48
|
-
Luhn.double_digits(60).must_equal([0,3])
|
49
|
-
Luhn.double_digits(9).must_equal([9])
|
50
|
-
Luhn.double_digits(90).must_equal([0,9])
|
51
|
-
Luhn.double_digits(123).must_equal([3,4,1])
|
52
|
-
Luhn.double_digits(4992739871).must_equal([1, 5, 8, 9, 3, 5, 2, 9, 9, 8])
|
53
|
-
Luhn.double_digits(7992739871).must_equal([1, 5, 8, 9, 3, 5, 2, 9, 9, 5])
|
54
|
-
end
|
55
|
-
end
|
56
|
-
|
57
|
-
describe 'sum is less or equal than 9' do
|
58
|
-
|
59
|
-
it 'computes the double of the digit' do
|
60
|
-
Luhn.double_digits(10).must_equal([0,2])
|
61
|
-
Luhn.double_digits(40).must_equal([0,8])
|
62
|
-
Luhn.double_digits(50531).must_equal([1,6,5,0,5])
|
63
|
-
end
|
64
|
-
end
|
65
|
-
|
66
|
-
end
|
67
|
-
|
68
|
-
describe 'all 0' do
|
69
|
-
|
70
|
-
it 'rejects number with all 0' do
|
71
|
-
Luhn.valid?(0000000000000000).must_equal(false)
|
72
|
-
end
|
73
|
-
end
|
74
|
-
|
75
|
-
describe '.valid?' do
|
76
|
-
|
77
|
-
describe 'valid number' do
|
78
|
-
valid_numbers = [4556974027974373, 4539085529167499, 5247381631434707, 4111111111111111, 5555555555554444,
|
79
|
-
5511828555531982, 371449635398431, 4716165622199, 869940826641794, 180002230256255,
|
80
|
-
3096704907107219, 214937935327366, 6011312159763625, 38442242218311]
|
81
|
-
it 'is valid' do
|
82
|
-
valid_numbers.each do |n|
|
83
|
-
Luhn.valid?(n).must_equal(true)
|
84
|
-
end
|
85
|
-
end
|
86
|
-
|
87
|
-
end
|
88
|
-
|
89
|
-
describe 'invalid number' do
|
90
|
-
invalid_numbers = [3844224221831, 601111111111117, 1234123412341234, 1234567890123456, 111111, 22222222222000,
|
91
|
-
1111111111111111, 00010000, 23.67, 0000000000000000]
|
92
|
-
|
93
|
-
it 'is invalid' do
|
94
|
-
invalid_numbers.each do |n|
|
95
|
-
Luhn.valid?(n).must_equal(false)
|
96
|
-
end
|
97
|
-
end
|
98
|
-
|
99
|
-
end
|
100
|
-
end
|
101
|
-
|
102
|
-
end
|