credit_card_validations 1.5.1 → 2.0.0
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/.travis.yml +4 -1
- data/Changelog.md +85 -0
- data/README.md +32 -9
- data/Rakefile +4 -4
- data/credit_card_validations.gemspec +2 -2
- data/lib/active_model/credit_card_number_validator.rb +67 -2
- data/lib/credit_card_validations.rb +25 -17
- data/lib/credit_card_validations/detector.rb +110 -27
- data/lib/credit_card_validations/factory.rb +66 -0
- data/lib/credit_card_validations/luhn.rb +5 -0
- data/lib/credit_card_validations/mmi.rb +18 -13
- data/lib/credit_card_validations/string.rb +11 -1
- data/lib/credit_card_validations/version.rb +1 -1
- data/lib/data/brands.yaml +238 -0
- data/spec/active_model_spec.rb +69 -0
- data/spec/credit_card_validations_spec.rb +168 -0
- data/spec/factory_spec.rb +21 -0
- data/{test → spec}/fixtures/invalid_cards.yml +0 -0
- data/{test → spec}/fixtures/valid_cards.yml +1 -0
- data/spec/models/credit_card.rb +19 -0
- data/spec/string_spec.rb +43 -0
- data/{test → spec}/test_helper.rb +5 -4
- metadata +25 -17
- data/lib/credit_card_validations/card_rules.rb +0 -84
- data/test/credit_card_validations_test.rb +0 -151
- data/test/models/any_credit_card.rb +0 -6
- data/test/models/credit_card.rb +0 -5
@@ -0,0 +1,168 @@
|
|
1
|
+
require_relative 'test_helper'
|
2
|
+
|
3
|
+
describe CreditCardValidations do
|
4
|
+
|
5
|
+
|
6
|
+
before do
|
7
|
+
CreditCardValidations.reload!
|
8
|
+
end
|
9
|
+
|
10
|
+
describe "MMI" do
|
11
|
+
it "should detect issuer category" do
|
12
|
+
d = detector(VALID_NUMBERS[:visa].first)
|
13
|
+
d.issuer_category.must_equal CreditCardValidations::Mmi::ISSUER_CATEGORIES[d.number[0]]
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
describe "Luhn#valid?" do
|
18
|
+
let(:card_detector) {
|
19
|
+
detector(VALID_NUMBERS[:unionpay].first)
|
20
|
+
}
|
21
|
+
it "should call Luhn.valid? once" do
|
22
|
+
CreditCardValidations::Luhn.expects(:valid?).with(card_detector.number).once
|
23
|
+
card_detector.valid?(:visa, :unionpay).must_equal true
|
24
|
+
end
|
25
|
+
|
26
|
+
it "should call Luhn.valid? twice" do
|
27
|
+
CreditCardValidations::Luhn.expects(:valid?).with(card_detector.number).twice
|
28
|
+
card_detector.valid?(:visa, :mastercard).must_equal false
|
29
|
+
end
|
30
|
+
|
31
|
+
it "should not call Luhn.valid?" do
|
32
|
+
|
33
|
+
CreditCardValidations::Luhn.expects(:valid?).never
|
34
|
+
card_detector.valid?(:unionpay).must_equal true
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
|
39
|
+
|
40
|
+
it "should check luhn" do
|
41
|
+
VALID_NUMBERS.each do |brand, card_numbers|
|
42
|
+
if has_luhn_check_rule?(brand)
|
43
|
+
card_numbers.each do |number|
|
44
|
+
luhn_valid?(detector(number).number).must_equal true
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
it "should check valid brand" do
|
51
|
+
VALID_NUMBERS.each do |brand, card_numbers|
|
52
|
+
card_numbers.each do |card_number|
|
53
|
+
detector(card_number).send("#{brand}?").must_equal true
|
54
|
+
detector(card_number).brand.must_equal brand
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
it "should check if card invalid" do
|
60
|
+
INVALID_NUMBERS.each do |card_number|
|
61
|
+
detector(card_number).valid?.must_equal false
|
62
|
+
detector(card_number).brand.must_be_nil
|
63
|
+
VALID_NUMBERS.keys.each do |brand|
|
64
|
+
detector(card_number).send("#{brand}?").must_equal false
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
it "should detect by full brand name" do
|
70
|
+
amex = CreditCardValidations::Factory.random(:amex)
|
71
|
+
detector(amex).valid?('American Express').must_equal true
|
72
|
+
visa = CreditCardValidations::Factory.random(:visa)
|
73
|
+
detector(visa).valid?('American Express').must_equal false
|
74
|
+
end
|
75
|
+
|
76
|
+
it "should support multiple brands for single check" do
|
77
|
+
VALID_NUMBERS.slice(:visa, :mastercard).each do |key, value|
|
78
|
+
detector(value.first).brand(:visa, :mastercard).must_equal key
|
79
|
+
end
|
80
|
+
|
81
|
+
VALID_NUMBERS.except(:visa, :mastercard).each do |_, value|
|
82
|
+
detector(value.first).brand(:visa, :mastercard).must_be_nil
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
it "should check if valid brand without arguments" do
|
87
|
+
VALID_NUMBERS.each do |key, value|
|
88
|
+
value.each do |card_number|
|
89
|
+
detector(card_number).valid?(key).must_equal true
|
90
|
+
assert detector(card_number).valid?.must_equal true
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
it "should not be valid? if wrong brand" do
|
96
|
+
detector(VALID_NUMBERS[:visa].first).valid?(:mastercard).must_equal false
|
97
|
+
detector(VALID_NUMBERS[:mastercard].first).valid?(:visa).must_equal false
|
98
|
+
end
|
99
|
+
|
100
|
+
it "should be valid? if right brand" do
|
101
|
+
detector(VALID_NUMBERS[:visa].first).valid?(:mastercard, :visa).must_equal true
|
102
|
+
detector(VALID_NUMBERS[:visa].first).valid?(:mastercard, :amex).must_equal false
|
103
|
+
end
|
104
|
+
|
105
|
+
|
106
|
+
describe "adding/removing brand" do
|
107
|
+
|
108
|
+
|
109
|
+
let(:voyager_number) {
|
110
|
+
'869926275400212'
|
111
|
+
}
|
112
|
+
|
113
|
+
it "should validate number as voyager" do
|
114
|
+
CreditCardValidations::Detector.add_brand(:voyager, {length: 15, prefixes: '86'})
|
115
|
+
detector(voyager_number).valid?(:voyager).must_equal true
|
116
|
+
detector(voyager_number).voyager?.must_equal true
|
117
|
+
detector(voyager_number).brand.must_equal :voyager
|
118
|
+
end
|
119
|
+
|
120
|
+
|
121
|
+
describe "Add voyager rule" do
|
122
|
+
before do
|
123
|
+
CreditCardValidations::Detector.add_brand(:voyager, {length: 15, prefixes: '86'})
|
124
|
+
end
|
125
|
+
|
126
|
+
it "should validate number as voyager" do
|
127
|
+
|
128
|
+
detector(voyager_number).valid?(:voyager).must_equal true
|
129
|
+
detector(voyager_number).voyager?.must_equal true
|
130
|
+
detector(voyager_number).brand.must_equal :voyager
|
131
|
+
|
132
|
+
end
|
133
|
+
|
134
|
+
describe "Remove voyager rule" do
|
135
|
+
before do
|
136
|
+
CreditCardValidations::Detector.delete_brand(:voyager)
|
137
|
+
end
|
138
|
+
|
139
|
+
it "should not validate number as voyager" do
|
140
|
+
detector(voyager_number).respond_to?(:voyager?).must_equal false
|
141
|
+
detector(voyager_number).brand.must_be_nil
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
end
|
146
|
+
|
147
|
+
|
148
|
+
it "should raise RuntimeError" do
|
149
|
+
proc { CreditCardValidations::Detector::add_rule(:undefined_brand, 20, [20]) }.must_raise RuntimeError
|
150
|
+
end
|
151
|
+
|
152
|
+
end
|
153
|
+
|
154
|
+
|
155
|
+
def luhn_valid?(number)
|
156
|
+
CreditCardValidations::Luhn.valid?(number)
|
157
|
+
end
|
158
|
+
|
159
|
+
def detector(number)
|
160
|
+
CreditCardValidations::Detector.new(number)
|
161
|
+
end
|
162
|
+
|
163
|
+
|
164
|
+
def has_luhn_check_rule?(key)
|
165
|
+
CreditCardValidations::Detector.has_luhn_check_rule?(key)
|
166
|
+
end
|
167
|
+
|
168
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require_relative 'test_helper'
|
2
|
+
|
3
|
+
describe CreditCardValidations::Factory do
|
4
|
+
|
5
|
+
it "should generate random brand" do
|
6
|
+
number = CreditCardValidations::Factory.random
|
7
|
+
CreditCardValidations::Detector.new(number).valid?.must_equal true
|
8
|
+
end
|
9
|
+
|
10
|
+
CreditCardValidations::Detector.brands.keys.sort.each do |key|
|
11
|
+
describe "#{key}" do
|
12
|
+
|
13
|
+
it "should generate valid #{key}" do
|
14
|
+
number = CreditCardValidations::Factory.random(key)
|
15
|
+
CreditCardValidations::Detector.new(number).valid?(key).must_equal true
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
File without changes
|
@@ -0,0 +1,19 @@
|
|
1
|
+
class CreditCard
|
2
|
+
attr_accessor :number, :number2, :number3, :number4, :number5, :number6, :card_type
|
3
|
+
include ActiveModel::Validations
|
4
|
+
validates :number, credit_card_number: {brands: [:amex, :maestro]} , allow_blank: true
|
5
|
+
validates :number2, credit_card_number: {only: [:amex, :maestro]}, allow_blank: true
|
6
|
+
validates :number3, credit_card_number: {except: [:amex, :maestro]} , allow_blank: true
|
7
|
+
validates :number4, credit_card_number: {brands: :any} , allow_blank: true
|
8
|
+
validates :number5, credit_card_number: true , allow_blank: true
|
9
|
+
validates :number6, credit_card_number: { brands: ->(record){ record.supported_brand } } , allow_blank: true
|
10
|
+
|
11
|
+
|
12
|
+
def supported_brand
|
13
|
+
{
|
14
|
+
"Master Card" => :mastercard,
|
15
|
+
"Visa" => :visa
|
16
|
+
}[self.card_type]
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
data/spec/string_spec.rb
ADDED
@@ -0,0 +1,43 @@
|
|
1
|
+
require_relative 'test_helper'
|
2
|
+
require 'credit_card_validations/string'
|
3
|
+
|
4
|
+
describe "String ext" do
|
5
|
+
|
6
|
+
let(:mastercard) {
|
7
|
+
CreditCardValidations::Factory.random(:mastercard)
|
8
|
+
}
|
9
|
+
|
10
|
+
let(:visa) {
|
11
|
+
CreditCardValidations::Factory.random(:visa)
|
12
|
+
}
|
13
|
+
|
14
|
+
let(:invalid) {
|
15
|
+
INVALID_NUMBERS.sample
|
16
|
+
}
|
17
|
+
|
18
|
+
it "should allow detect brand for mastercard" do
|
19
|
+
|
20
|
+
mastercard.credit_card_brand.must_equal :mastercard
|
21
|
+
mastercard.credit_card_brand_name.must_equal 'MasterCard'
|
22
|
+
mastercard.valid_credit_card_brand?(:mastercard).must_equal true
|
23
|
+
mastercard.valid_credit_card_brand?('MasterCard').must_equal true
|
24
|
+
mastercard.valid_credit_card_brand?(:visa, :amex).must_equal false
|
25
|
+
end
|
26
|
+
|
27
|
+
it "should allow detect brand for visa" do
|
28
|
+
|
29
|
+
visa.credit_card_brand.must_equal :visa
|
30
|
+
visa.credit_card_brand_name.must_equal 'Visa'
|
31
|
+
visa.valid_credit_card_brand?(:mastercard).must_equal false
|
32
|
+
visa.valid_credit_card_brand?(:visa, :amex).must_equal true
|
33
|
+
end
|
34
|
+
|
35
|
+
it "should not allow detect brand for invalid card" do
|
36
|
+
|
37
|
+
invalid.credit_card_brand.must_be_nil
|
38
|
+
invalid.credit_card_brand_name.must_be_nil
|
39
|
+
invalid.valid_credit_card_brand?(:mastercard).must_equal false
|
40
|
+
invalid.valid_credit_card_brand?(:visa, :amex).must_equal false
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
@@ -1,19 +1,20 @@
|
|
1
1
|
require 'coveralls'
|
2
2
|
Coveralls.wear!
|
3
|
+
|
3
4
|
require 'minitest/autorun'
|
4
5
|
require 'i18n'
|
5
6
|
require 'mocha/mini_test'
|
6
7
|
|
7
8
|
lib = File.expand_path("#{File.dirname(__FILE__)}/../lib")
|
8
|
-
|
9
|
+
specs = File.expand_path("#{File.dirname(__FILE__)}/../spec")
|
9
10
|
$:.unshift(lib)
|
10
|
-
$:.unshift(
|
11
|
+
$:.unshift(specs)
|
11
12
|
|
12
13
|
I18n.config.enforce_available_locales = true
|
13
14
|
|
14
15
|
require 'credit_card_validations'
|
15
16
|
require 'models/credit_card'
|
16
|
-
require 'models/any_credit_card'
|
17
|
-
|
18
17
|
|
18
|
+
VALID_NUMBERS = YAML.load_file File.join(File.dirname(__FILE__), 'fixtures/valid_cards.yml')
|
19
|
+
INVALID_NUMBERS = YAML.load_file File.join(File.dirname(__FILE__), 'fixtures/invalid_cards.yml')
|
19
20
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: credit_card_validations
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 2.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Igor
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2015-01-14 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activemodel
|
@@ -78,7 +78,7 @@ dependencies:
|
|
78
78
|
- - "~>"
|
79
79
|
- !ruby/object:Gem::Version
|
80
80
|
version: '10'
|
81
|
-
description: A ruby gem for validating credit card numbers
|
81
|
+
description: A ruby gem for validating credit card numbers
|
82
82
|
email:
|
83
83
|
- fedoronchuk@gmail.com
|
84
84
|
executables: []
|
@@ -86,6 +86,7 @@ extensions: []
|
|
86
86
|
extra_rdoc_files: []
|
87
87
|
files:
|
88
88
|
- ".travis.yml"
|
89
|
+
- Changelog.md
|
89
90
|
- Gemfile
|
90
91
|
- LICENSE.txt
|
91
92
|
- README.md
|
@@ -93,18 +94,21 @@ files:
|
|
93
94
|
- credit_card_validations.gemspec
|
94
95
|
- lib/active_model/credit_card_number_validator.rb
|
95
96
|
- lib/credit_card_validations.rb
|
96
|
-
- lib/credit_card_validations/card_rules.rb
|
97
97
|
- lib/credit_card_validations/detector.rb
|
98
|
+
- lib/credit_card_validations/factory.rb
|
98
99
|
- lib/credit_card_validations/luhn.rb
|
99
100
|
- lib/credit_card_validations/mmi.rb
|
100
101
|
- lib/credit_card_validations/string.rb
|
101
102
|
- lib/credit_card_validations/version.rb
|
102
|
-
-
|
103
|
-
-
|
104
|
-
-
|
105
|
-
-
|
106
|
-
-
|
107
|
-
-
|
103
|
+
- lib/data/brands.yaml
|
104
|
+
- spec/active_model_spec.rb
|
105
|
+
- spec/credit_card_validations_spec.rb
|
106
|
+
- spec/factory_spec.rb
|
107
|
+
- spec/fixtures/invalid_cards.yml
|
108
|
+
- spec/fixtures/valid_cards.yml
|
109
|
+
- spec/models/credit_card.rb
|
110
|
+
- spec/string_spec.rb
|
111
|
+
- spec/test_helper.rb
|
108
112
|
homepage: https://github.com/Fivell/credit_card_validations
|
109
113
|
licenses:
|
110
114
|
- MIT
|
@@ -128,11 +132,15 @@ rubyforge_project:
|
|
128
132
|
rubygems_version: 2.2.2
|
129
133
|
signing_key:
|
130
134
|
specification_version: 4
|
131
|
-
summary: gem for credit card numbers validation, card brands detections
|
135
|
+
summary: gem should be used for credit card numbers validation, card brands detections,
|
136
|
+
luhn checks
|
132
137
|
test_files:
|
133
|
-
-
|
134
|
-
-
|
135
|
-
-
|
136
|
-
-
|
137
|
-
-
|
138
|
-
-
|
138
|
+
- spec/active_model_spec.rb
|
139
|
+
- spec/credit_card_validations_spec.rb
|
140
|
+
- spec/factory_spec.rb
|
141
|
+
- spec/fixtures/invalid_cards.yml
|
142
|
+
- spec/fixtures/valid_cards.yml
|
143
|
+
- spec/models/credit_card.rb
|
144
|
+
- spec/string_spec.rb
|
145
|
+
- spec/test_helper.rb
|
146
|
+
has_rdoc:
|
@@ -1,84 +0,0 @@
|
|
1
|
-
module CreditCardValidations
|
2
|
-
module CardRules
|
3
|
-
######## most used brands #########
|
4
|
-
mattr_accessor :rules
|
5
|
-
|
6
|
-
self.rules = {
|
7
|
-
visa: [
|
8
|
-
{length: [13, 16], prefixes: ['4']}
|
9
|
-
],
|
10
|
-
mastercard: [
|
11
|
-
{length: [16], prefixes: ['51', '52', '53', '54', '55']}
|
12
|
-
],
|
13
|
-
|
14
|
-
amex: [
|
15
|
-
{length: [15], prefixes: ['34', '37']}
|
16
|
-
],
|
17
|
-
######## other brands ########
|
18
|
-
diners: [
|
19
|
-
{length: [14], prefixes: ['300', '301', '302', '303', '304', '305', '36', '38']},
|
20
|
-
],
|
21
|
-
|
22
|
-
#There are Diners Club (North America) cards that begin with 5. These are a joint venture between Diners Club and MasterCard, and are processed like a MasterCard
|
23
|
-
# will be removed in next major version
|
24
|
-
|
25
|
-
diners_us: [
|
26
|
-
{length: [16], prefixes: ['54', '55']}
|
27
|
-
],
|
28
|
-
|
29
|
-
discover: [
|
30
|
-
{length: [16], prefixes: ['6011', '644', '645', '646', '647', '648',
|
31
|
-
'649', '65']}
|
32
|
-
],
|
33
|
-
|
34
|
-
jcb: [
|
35
|
-
{length: [15,16], prefixes: ['3528', '3529', '353', '354', '355', '356', '357', '358']},
|
36
|
-
{length: [15], prefixes: ['1800', '2131']}
|
37
|
-
],
|
38
|
-
|
39
|
-
|
40
|
-
laser: [
|
41
|
-
{length: [16, 17, 18, 19], prefixes: ['6304', '6706', '6771']}
|
42
|
-
],
|
43
|
-
|
44
|
-
solo: [
|
45
|
-
{length: [16, 18, 19], prefixes: ['6334', '6767']}
|
46
|
-
],
|
47
|
-
|
48
|
-
switch: [
|
49
|
-
{length: [16, 18, 19], prefixes: ['633110', '633312', '633304', '633303', '633301', '633300']}
|
50
|
-
|
51
|
-
],
|
52
|
-
|
53
|
-
maestro: [
|
54
|
-
{length: [12, 13, 14, 15, 16, 17, 18, 19], prefixes: ['5010', '5011', '5012', '5013', '5014', '5015', '5016', '5017', '5018',
|
55
|
-
'502', '503', '504', '505', '506', '507', '508',
|
56
|
-
'56','57', '58', '59',
|
57
|
-
'6010', '6012', '6013', '6014', '6015', '6016', '6017', '6018', '6019',
|
58
|
-
'602', '603', '604', '605', '6060',
|
59
|
-
'621', '627', '629',
|
60
|
-
'670','671', '672','673', '674', '675', '677',
|
61
|
-
'6760', '6761', '6762', '6763', '6764', '6765', '6766', '6768', '6769',
|
62
|
-
'679'
|
63
|
-
]}
|
64
|
-
],
|
65
|
-
|
66
|
-
# Luhn validation are skipped for union pay cards because they have unknown generation algoritm
|
67
|
-
unionpay: [
|
68
|
-
{length: [16, 17, 18, 19], prefixes: ['622', '624', '625', '626', '628'], skip_luhn: true}
|
69
|
-
],
|
70
|
-
|
71
|
-
dankrot: [
|
72
|
-
{length: [16], prefixes: ['5019']}
|
73
|
-
],
|
74
|
-
|
75
|
-
rupay: [
|
76
|
-
{length: [16], prefixes: ['6061', '6062', '6063', '6064', '6065', '6066', '6067', '6068', '6069', '607', '608'], skip_luhn: true}
|
77
|
-
],
|
78
|
-
|
79
|
-
hipercard: [
|
80
|
-
length: [19], prefixes: ['384']
|
81
|
-
]
|
82
|
-
}
|
83
|
-
end
|
84
|
-
end
|