credit_card_detector 0.3

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: b275b2204494c66c28dfb5eb23925b6ab6afc37b
4
+ data.tar.gz: 8baec80bedec36a582aab73f65b6f552255459d2
5
+ SHA512:
6
+ metadata.gz: 8d7bc3057b56ff82481011092797d445d651f63bb3e04a81e551da38fa54157cc3740b5f5624bd233e721e5869d1a5bb46a92d28363f9fdf6155ff4fef501d91
7
+ data.tar.gz: 762b2d41da9ff1779d406f9c6672e1c73addfd302ca240303c7b78c173566ee0f1c531a3d1e98eeae7cf9560afa9a9015072d4694fb04be4dd8a7e5b05b4d31d
data/.hound.yml ADDED
@@ -0,0 +1,2 @@
1
+ StringLiterals:
2
+ EnforcedStyle: single_quotes
data/.travis.yml ADDED
@@ -0,0 +1,25 @@
1
+ language: ruby
2
+ rvm:
3
+ - 1.9.3
4
+ - 2.0.0
5
+ - 2.1.9
6
+ - 2.2.5
7
+ - 2.3.1
8
+ - jruby-19mode # JRuby in 1.9 mode
9
+ gemfile:
10
+ - gemfiles/rails1-4.gemfile
11
+ - gemfiles/rails5.gemfile
12
+ matrix:
13
+ exclude:
14
+ - gemfile: gemfiles/rails5.gemfile
15
+ rvm: 1.9.3
16
+ - gemfile: gemfiles/rails5.gemfile
17
+ rvm: 2.0.0
18
+ - gemfile: gemfiles/rails5.gemfile
19
+ rvm: 2.1.9
20
+ - gemfile: gemfiles/rails5.gemfile
21
+ rvm: jruby-19mode
22
+ before_install:
23
+ - gem install bundler # use the very latest Bundler
24
+ - gem update --system
25
+ - gem --version
data/Changelog.md ADDED
@@ -0,0 +1,8 @@
1
+ # 0.2
2
+
3
+ Refactor the source code completely to have cleaner objects that are easier to test.
4
+
5
+ # 0.1
6
+
7
+ Fork [credit_card_validations](https://github.com/Fivell/credit_card_validations) gem to have credit card validation and detector without any extra dependency (specifically, ActiveModel).
8
+
data/Gemfile ADDED
@@ -0,0 +1,7 @@
1
+ source 'https://rubygems.org'
2
+ group :test do
3
+ gem 'coveralls', require: false # Test coverage website. Go to https://coveralls.io
4
+ end
5
+ # Specify your gem's dependencies in credit_card_detector.gemspec
6
+ gemspec
7
+
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Igor Fedoronchuk
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,74 @@
1
+ # CreditCardDetector
2
+
3
+ Gem provides credit card number validator and type detector.
4
+
5
+ It checks whether or not a given number actually falls within the ranges of possible numbers for given brands and provides an optional Luhn check.
6
+
7
+ More info about card BIN numbers http://en.wikipedia.org/wiki/Bank_card_number
8
+
9
+ ## Installation
10
+
11
+ Add this line to your application's Gemfile:
12
+
13
+ gem 'credit_card_detector'
14
+
15
+ And then execute:
16
+
17
+ $ bundle
18
+
19
+ Or install it yourself as:
20
+
21
+ $ gem install credit_card_detector
22
+
23
+ ## Usage
24
+
25
+
26
+ The following issuing institutes are accepted:
27
+
28
+ Name | Key |
29
+ --------------------- | ------------|
30
+ [American Express](http://en.wikipedia.org/wiki/American_Express) | :amex
31
+ [China UnionPay](http://en.wikipedia.org/wiki/China_UnionPay) | :unionpay
32
+ [Dankort](http://en.wikipedia.org/wiki/Dankort) | :dankort
33
+ [Diners Club](http://en.wikipedia.org/wiki/Diners_Club_International) | :diners
34
+ [Elo](https://pt.wikipedia.org/wiki/Elo_Participa%C3%A7%C3%B5es_S/A) | :elo
35
+ [Discover](http://en.wikipedia.org/wiki/Discover_Card) | :discover
36
+ [Hipercard](http://pt.wikipedia.org/wiki/Hipercard) | :hipercard
37
+ [JCB](http://en.wikipedia.org/wiki/Japan_Credit_Bureau) | :jcb
38
+ [Maestro](http://en.wikipedia.org/wiki/Maestro_%28debit_card%29) | :maestro
39
+ [MasterCard](http://en.wikipedia.org/wiki/MasterCard) | :mastercard
40
+ [Rupay](http://en.wikipedia.org/wiki/RuPay) | :rupay
41
+ [Solo](http://en.wikipedia.org/wiki/Solo_(debit_card)) | :solo
42
+ [Switch](http://en.wikipedia.org/wiki/Switch_(debit_card)) | :switch
43
+ [Visa](http://en.wikipedia.org/wiki/Visa_Inc.) | :visa
44
+
45
+
46
+ ### Examples
47
+
48
+ ```ruby
49
+ number = "4111111111111111"
50
+ detector = CreditCardDetector::Detector.new(number)
51
+ detector.brand # Visa brand
52
+ detector.brand_name # Visa
53
+ detector.valid?(:mastercard, :maestro) #false
54
+ detector.valid?(:visa, :mastercard) #true
55
+ ```
56
+
57
+ ### Check luhn
58
+
59
+ ```ruby
60
+ CreditCardDetector::Detector.new(number).valid_luhn?
61
+ ```
62
+
63
+ ## Contributing
64
+
65
+ 1. Fork it
66
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
67
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
68
+ 4. Push to the branch (`git push origin my-new-feature`)
69
+ 5. Create new Pull Request
70
+
71
+ ## Original version
72
+
73
+ [credit_card_validations](https://github.com/Fivell/credit_card_validations) - provides more extended API, but dependes on activemodel and activesupport.
74
+
data/Rakefile ADDED
@@ -0,0 +1,14 @@
1
+ require "bundler/gem_tasks"
2
+
3
+ require "rake"
4
+ require "rake/testtask"
5
+
6
+ task default: [:specs]
7
+
8
+ desc "Run basic specs"
9
+ Rake::TestTask.new("specs") { |t|
10
+ t.pattern = "spec/*_spec.rb"
11
+ t.verbose = true
12
+ t.warning = true
13
+ t.libs << "lib" << "spec"
14
+ }
@@ -0,0 +1,24 @@
1
+ lib = File.expand_path("../lib", __FILE__)
2
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
+
4
+ require "credit_card_detector/version"
5
+
6
+ Gem::Specification.new do |gem|
7
+ gem.name = "credit_card_detector"
8
+ gem.version = CreditCardDetector::VERSION
9
+ gem.authors = ["Andrew Volozhanin", "Igor"]
10
+ gem.email = ["scarfacedeb@gmail.com", "fedoronchuk@gmail.com"]
11
+ gem.description = %q{A ruby gem for validating credit card numbers}
12
+ gem.summary = "Gem provides basic credit card number validation and type detection without any extra dependencies"
13
+ gem.homepage = ""
14
+ gem.license = "MIT"
15
+
16
+ gem.files = `git ls-files`.split($/)
17
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
18
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
19
+ gem.require_paths = ["lib"]
20
+
21
+ gem.add_development_dependency "rake", "~> 10.5"
22
+ gem.add_development_dependency "minitest", "~> 5.9"
23
+ gem.add_development_dependency "pry"
24
+ end
@@ -0,0 +1,26 @@
1
+ require "credit_card_detector/rule"
2
+
3
+ module CreditCardDetector
4
+ class Brand
5
+ attr_reader :id, :name, :options
6
+
7
+ def initialize(id, data)
8
+ @id = id
9
+ @name = data.fetch(:name)
10
+ @raw_rules = data.fetch(:rules)
11
+ @options = data.fetch(:options, {})
12
+ end
13
+
14
+ def matches?(number)
15
+ rules.any? { |rule| rule.matches? number }
16
+ end
17
+
18
+ def luhn?
19
+ !@options.fetch(:skip_luhn, false)
20
+ end
21
+
22
+ def rules
23
+ @rules ||= @raw_rules.map { |rule| Rule.new rule }
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,22 @@
1
+ require "yaml"
2
+ require "credit_card_detector/brand"
3
+
4
+ module CreditCardDetector
5
+ module Data
6
+ DATA = File.expand_path("../../data/brands.yaml", __FILE__)
7
+
8
+ class << self
9
+ def brands
10
+ @data ||= raw_data.map { |key, data| Brand.new key, data }
11
+ end
12
+
13
+ def ids
14
+ @ids ||= brands.map(&:id)
15
+ end
16
+
17
+ def raw_data
18
+ YAML.load_file DATA
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,51 @@
1
+ require "credit_card_detector/data"
2
+ require "credit_card_detector/luhn"
3
+
4
+ module CreditCardDetector
5
+ class Detector
6
+ def initialize(number)
7
+ @number = number.to_s.tr('- ', '')
8
+ end
9
+
10
+ def valid?(*brands)
11
+ brands.compact!
12
+
13
+ if brands.empty?
14
+ !brand.nil?
15
+ else
16
+ validate_brands(brands)
17
+ brands.include?(brand.id)
18
+ end
19
+ end
20
+
21
+ def valid_luhn?
22
+ @valid_luhn ||= Luhn.valid?(@number)
23
+ end
24
+
25
+ def brand
26
+ @brand ||= Data.brands.find { |brand| matches_brand? brand }
27
+ end
28
+
29
+ def brand_id
30
+ brand.id if brand
31
+ end
32
+
33
+ def brand_name
34
+ brand.name if brand
35
+ end
36
+
37
+ protected
38
+
39
+ def matches_brand?(brand)
40
+ return if brand.luhn? && !valid_luhn?
41
+ brand.matches?(@number)
42
+ end
43
+
44
+ def validate_brands(brands)
45
+ brands.each do |key|
46
+ next if Data.ids.include?(key)
47
+ fail Error, "brand #{key} is undefined"
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,4 @@
1
+ module CreditCardDetector
2
+ class Error < StandardError
3
+ end
4
+ end
@@ -0,0 +1,18 @@
1
+ module CreditCardDetector
2
+ # Class to validate Luhn numbers.
3
+ class Luhn
4
+ def self.valid?(number)
5
+ s1 = s2 = 0
6
+
7
+ number.to_s.reverse.chars.each_slice(2) do |odd, even|
8
+ s1 += odd.to_i
9
+
10
+ double = even.to_i * 2
11
+ double -= 9 if double >= 10
12
+ s2 += double
13
+ end
14
+
15
+ (s1 + s2) % 10 == 0
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,26 @@
1
+ module CreditCardDetector
2
+ class Rule
3
+ def initialize(length:, prefixes:)
4
+ @length = length
5
+ @regexp = compile_regexp(prefixes)
6
+ end
7
+
8
+ def matches?(number)
9
+ matches_length?(number.to_s) && matches_prefix?(number.to_s)
10
+ end
11
+
12
+ def matches_length?(number)
13
+ @length.include? number.size
14
+ end
15
+
16
+ def matches_prefix?(number)
17
+ !!(number =~ @regexp)
18
+ end
19
+
20
+ private
21
+
22
+ def compile_regexp(prefixes)
23
+ Regexp.new("^(#{prefixes.join("|")})")
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,4 @@
1
+ module CreditCardDetector
2
+ VERSION = "0.3"
3
+ end
4
+
@@ -0,0 +1,6 @@
1
+ require "credit_card_detector/version"
2
+ require "credit_card_detector/error"
3
+ require "credit_card_detector/detector"
4
+
5
+ module CreditCardDetector
6
+ end
@@ -0,0 +1,281 @@
1
+ ---
2
+ :visa:
3
+ :name: Visa
4
+ :rules:
5
+ - :length:
6
+ - 13
7
+ - 16
8
+ :prefixes:
9
+ - '4'
10
+ :mastercard:
11
+ :name: MasterCard
12
+ :rules:
13
+ - :length:
14
+ - 16
15
+ :prefixes:
16
+ - '2221'
17
+ - '2222'
18
+ - '2223'
19
+ - '2224'
20
+ - '2225'
21
+ - '2226'
22
+ - '2227'
23
+ - '2228'
24
+ - '2229'
25
+ - '223'
26
+ - '224'
27
+ - '225'
28
+ - '226'
29
+ - '227'
30
+ - '228'
31
+ - '229'
32
+ - '23'
33
+ - '24'
34
+ - '25'
35
+ - '26'
36
+ - '271'
37
+ - '2720'
38
+ - '51'
39
+ - '52'
40
+ - '53'
41
+ - '54'
42
+ - '55'
43
+ :amex:
44
+ :name: American Express
45
+ :rules:
46
+ - :length:
47
+ - 15
48
+ :prefixes:
49
+ - '34'
50
+ - '37'
51
+ :diners:
52
+ :name: Diners Club
53
+ :rules:
54
+ - :length:
55
+ - 14
56
+ :prefixes:
57
+ - '300'
58
+ - '301'
59
+ - '302'
60
+ - '303'
61
+ - '304'
62
+ - '305'
63
+ - '36'
64
+ - '38'
65
+ :discover:
66
+ :name: Discover
67
+ :rules:
68
+ - :length:
69
+ - 16
70
+ :prefixes:
71
+ - '6011'
72
+ - '644'
73
+ - '645'
74
+ - '646'
75
+ - '647'
76
+ - '648'
77
+ - '649'
78
+ - '65'
79
+ :jcb:
80
+ :name: JCB
81
+ :rules:
82
+ - :length:
83
+ - 15
84
+ - 16
85
+ :prefixes:
86
+ - '3528'
87
+ - '3529'
88
+ - '353'
89
+ - '354'
90
+ - '355'
91
+ - '356'
92
+ - '357'
93
+ - '358'
94
+ - :length:
95
+ - 15
96
+ :prefixes:
97
+ - '1800'
98
+ - '2131'
99
+ - :length:
100
+ - 19
101
+ :prefixes:
102
+ - '357266'
103
+ :solo:
104
+ :name: Solo
105
+ :rules:
106
+ - :length:
107
+ - 16
108
+ - 18
109
+ - 19
110
+ :prefixes:
111
+ - '6334'
112
+ - '6767'
113
+ :switch:
114
+ :name: Switch
115
+ :rules:
116
+ - :length:
117
+ - 16
118
+ - 18
119
+ - 19
120
+ :prefixes:
121
+ - '633110'
122
+ - '633312'
123
+ - '633304'
124
+ - '633303'
125
+ - '633301'
126
+ - '633300'
127
+ :maestro:
128
+ :name: Maestro
129
+ :rules:
130
+ - :length:
131
+ - 12
132
+ - 13
133
+ - 14
134
+ - 15
135
+ - 16
136
+ - 17
137
+ - 18
138
+ - 19
139
+ :prefixes:
140
+ - '500'
141
+ - '5010'
142
+ - '5011'
143
+ - '5012'
144
+ - '5013'
145
+ - '5014'
146
+ - '5015'
147
+ - '5016'
148
+ - '5017'
149
+ - '5018'
150
+ - '502'
151
+ - '503'
152
+ - '504'
153
+ - '505'
154
+ - '506'
155
+ - '507'
156
+ - '508'
157
+ - '509'
158
+ - '56'
159
+ - '57'
160
+ - '58'
161
+ - '59'
162
+ - '6010'
163
+ - '6012'
164
+ - '6013'
165
+ - '6014'
166
+ - '6015'
167
+ - '6016'
168
+ - '6017'
169
+ - '6018'
170
+ - '6019'
171
+ - '602'
172
+ - '603'
173
+ - '604'
174
+ - '605'
175
+ - '6060'
176
+ - '621'
177
+ - '627'
178
+ - '629'
179
+ - '6304'
180
+ - '6390'
181
+ - '670'
182
+ - '671'
183
+ - '672'
184
+ - '673'
185
+ - '674'
186
+ - '675'
187
+ - '677'
188
+ - '6760'
189
+ - '6761'
190
+ - '6762'
191
+ - '6763'
192
+ - '6764'
193
+ - '6765'
194
+ - '6766'
195
+ - '6768'
196
+ - '6769'
197
+ - '6771'
198
+ - '679'
199
+ :unionpay:
200
+ :name: China UnionPay
201
+ :rules:
202
+ - :length:
203
+ - 16
204
+ - 17
205
+ - 18
206
+ - 19
207
+ :prefixes:
208
+ - '622'
209
+ - '624'
210
+ - '625'
211
+ - '626'
212
+ - '628'
213
+ :options:
214
+ :skip_luhn: true
215
+ :dankort:
216
+ :name: Dankort
217
+ :rules:
218
+ - :length:
219
+ - 16
220
+ :prefixes:
221
+ - '5019'
222
+ :rupay:
223
+ :name: Rupay
224
+ :rules:
225
+ - :length:
226
+ - 16
227
+ :prefixes:
228
+ - '6061'
229
+ - '6062'
230
+ - '6063'
231
+ - '6064'
232
+ - '6065'
233
+ - '6066'
234
+ - '6067'
235
+ - '6068'
236
+ - '6069'
237
+ - '607'
238
+ - '608'
239
+ :options:
240
+ :skip_luhn: true
241
+ :hipercard:
242
+ :name: Hipercard
243
+ :rules:
244
+ - :length:
245
+ - 19
246
+ :prefixes:
247
+ - '384'
248
+ :elo:
249
+ :name: Elo
250
+ :rules:
251
+ - :length:
252
+ - 16
253
+ :prefixes:
254
+ - '4011'
255
+ - '438935'
256
+ - '451416'
257
+ - '4576'
258
+ - '504175'
259
+ - '506699'
260
+ - '5067'
261
+ - '509040'
262
+ - '509042'
263
+ - '509043'
264
+ - '509045'
265
+ - '509046'
266
+ - '509047'
267
+ - '509048'
268
+ - '509049'
269
+ - '509050'
270
+ - '509051'
271
+ - '509052'
272
+ - '509064'
273
+ - '509066'
274
+ - '509067'
275
+ - '509068'
276
+ - '509069'
277
+ - '509074'
278
+ - '636297'
279
+ - '63636'
280
+ :options:
281
+ :skip_luhn: true
@@ -0,0 +1,70 @@
1
+ require "test_helper"
2
+ require "credit_card_detector/brand"
3
+
4
+ module CreditCardDetector
5
+ describe Brand do
6
+ describe "#matches?" do
7
+ let(:data) { { name: "Visa", rules: rules, options: {} } }
8
+ let(:brand) { Brand.new(:visa, data) }
9
+
10
+ describe "when brand doesn't have any rules" do
11
+ let(:rules) { [] }
12
+ it "doesn't matches any number" do
13
+ assert_equal brand.matches?("1234"), false
14
+ assert_equal brand.matches?(""), false
15
+ assert_equal brand.matches?("4012888888881881"), false
16
+ end
17
+ end
18
+
19
+ describe "when brand has a single rule" do
20
+ let(:rules) {
21
+ [ { length: [16, 13], prefixes: ['4'] } ]
22
+ }
23
+
24
+ it "matches valid numbers" do
25
+ numbers = VALID_NUMBERS.fetch(:visa)
26
+ numbers.each do |number|
27
+ assert_equal brand.matches?(number.tr("- ", "")), true
28
+ end
29
+ end
30
+
31
+ it "doesn't match invalid numbers" do
32
+ assert_equal brand.matches?("42222222222221"), false
33
+ end
34
+ end
35
+
36
+ describe "when brand has multiple rules" do
37
+ let(:rules) {
38
+ [
39
+ { length: [15, 16], prefixes: ['357', '356', '353'] },
40
+ { length: [15], prefixes: ['1800'] },
41
+ { length: [19], prefixes: ['357266'] }
42
+ ]
43
+ }
44
+
45
+ it "matches valid numbers" do
46
+ numbers = VALID_NUMBERS.fetch(:jcb)
47
+ numbers.each do |number|
48
+ assert_equal brand.matches?(number.tr("- ", "")), true
49
+ end
50
+ end
51
+
52
+ it "doesn't match invalid numbers" do
53
+ assert_equal brand.matches?("1800016382773921"), false
54
+ end
55
+ end
56
+ end
57
+
58
+ describe "#luhn?" do
59
+ it "returns true when NO skip_luhn option is set on brand" do
60
+ brand = Brand.new(:maestro, name: "maestro", options: {}, rules: [])
61
+ assert_equal brand.luhn?, true
62
+ end
63
+
64
+ it "returns false when skip_luhn option is set on brand" do
65
+ brand = Brand.new(:maestro, name: "rupay", options: { skip_luhn: true }, rules: [])
66
+ assert_equal brand.luhn?, false
67
+ end
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,78 @@
1
+ require "test_helper"
2
+ require "credit_card_detector/detector"
3
+
4
+ module CreditCardDetector
5
+ describe Detector do
6
+ describe "#valid?" do
7
+ def perform(numbers, expected, *brands)
8
+ numbers.each do |number|
9
+ valid = Detector.new(number).valid?(*brands)
10
+ assert_equal valid, expected, number
11
+ end
12
+ end
13
+
14
+ it "validates valid numbers against all of the available brands" do
15
+ VALID_NUMBERS.each do |_, numbers|
16
+ perform numbers, true
17
+ end
18
+ end
19
+
20
+ it "validates invalid numbers against all of the available brands" do
21
+ perform INVALID_NUMBERS, false
22
+ end
23
+
24
+ it "returns true when numbers belong to the given brand" do
25
+ visa = VALID_NUMBERS.fetch(:visa)
26
+ perform visa, true, :visa
27
+ end
28
+
29
+ it "returns false when numbers belong to another brand" do
30
+ mastercard = VALID_NUMBERS.fetch(:mastercard)
31
+ perform mastercard, false, :visa
32
+ end
33
+
34
+ it "validates number against multiple brands" do
35
+ visa = VALID_NUMBERS.fetch(:visa)
36
+ mastercard = VALID_NUMBERS.fetch(:mastercard)
37
+ maestro = VALID_NUMBERS.fetch(:maestro)
38
+
39
+ perform (visa + maestro), true, :visa, :maestro, :jcb
40
+ perform mastercard, false, :visa, :rupay
41
+ end
42
+
43
+ describe "when brand doesn't support luhn check" do
44
+ it "returns true when number fails luhn check" do
45
+ unionpay = VALID_NUMBERS.fetch(:unionpay)
46
+ perform unionpay, true
47
+ end
48
+ end
49
+ end
50
+
51
+ describe "#brand" do
52
+ it "returns matched brand for valid number" do
53
+ detector = Detector.new("4012888888881881")
54
+ assert_instance_of Brand, detector.brand
55
+ assert_equal detector.brand.id, :visa
56
+ end
57
+
58
+ it "returns nil when number is invalid" do
59
+ detector = Detector.new("40128888")
60
+ assert_equal detector.brand, nil
61
+ end
62
+ end
63
+
64
+ describe "#brand_id" do
65
+ it "returns brand id" do
66
+ detector = Detector.new("4012888888881881")
67
+ assert_equal detector.brand_id, :visa
68
+ end
69
+ end
70
+
71
+ describe "#brand_name" do
72
+ it "returns brand name" do
73
+ detector = Detector.new("4012888888881881")
74
+ assert_equal detector.brand_name, "Visa"
75
+ end
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,6 @@
1
+ ---
2
+ - '1111111111111111'
3
+ - '00000000000000'
4
+ - fakenumber
5
+ - c4111111111111111
6
+ - 4111111111111111i
@@ -0,0 +1,115 @@
1
+ ---
2
+ :visa:
3
+ - 4012 8888 8888 1881
4
+ - 4111 1111 1111 1111
5
+ - 4222 2222 2222 2
6
+ - 4917 6100 0000 0000
7
+ :mastercard:
8
+ - 5274 5763 9425 9961
9
+ - 5555 5555 5555 4444
10
+ - 5105 1051 0510 5100
11
+ - 2720 1700 0000 0006
12
+ - 2223 4800 0000 0001
13
+ - 2223 0400 0000 0003
14
+ - 2223 0700 0000 0000
15
+ - 2223 2700 0000 0006
16
+ - 2720 3500 0000 0004
17
+ - 2223 1000 0000 0005
18
+ - 2720 0500 0000 0000
19
+ :diners:
20
+ - 3020 4169 3226 43
21
+ - 3021 8047 1965 57
22
+ - 3022 1511 5632 52
23
+ - 3600 0000 0000 08
24
+ - 3614 8900 6479 13
25
+ - 3670 0102 0000 00
26
+ - 3852 0000 0232 37
27
+ - 3056 9309 0259 04
28
+ - 3020 4169 3226 43
29
+ :amex:
30
+ - 3714 4963 5398 431
31
+ - 3787 3449 3671 000
32
+ - 3400 0000 0000 009
33
+ - 3411 1111 1111 111
34
+ - 3434 3434 3434 343
35
+ - 3468 2763 0435 344
36
+ - 3700 0000 0000 002
37
+ - 3700 0020 0000 000
38
+ - 3704 0726 9909 809
39
+ - 3705 5601 9309 221
40
+ - 3714 4963 5398 431
41
+ - 3742 0000 0000 004
42
+ - 3764 6228 0921 451
43
+ - 3777 5274 9896 404
44
+ - 3782 8224 6310 005
45
+ :discover:
46
+ - 6011 1111 1111 1117
47
+ - 6011 0009 9013 9424
48
+ - 6011 0000 0000 0004
49
+ - 6011 0004 0000 0000
50
+ - 6011 1532 1637 1980
51
+ - 6011 6011 6011 6611
52
+ - 6011 6874 8256 4166
53
+ - 6011 8148 3690 5651
54
+ :maestro:
55
+ - 6759 6498 2643 8453
56
+ - 5641 8200 0000 0005
57
+ - 5033 9619 8909 17
58
+ - 5868 2416 0825 5333 38
59
+ - 6799 9901 0000 0000 019
60
+ - 6390 0200 0000 000003
61
+ - 6304 9506 0000 0000 00
62
+ - 6304 9000 1774 0292 441
63
+ :jcb:
64
+ - 3575 7591 5225 4876
65
+ - 3566 0020 2036 0505
66
+ - 1800 0163 8277 392
67
+ - 3569 9900 0000 0009
68
+ - 3530 1113 3330 0000
69
+ - 3572 6600 0000 0000 006
70
+ :solo:
71
+ - 6767 6222 2222 2222 222
72
+ - 6334 5805 0000 0000
73
+ - 6334 9000 0000 0005
74
+ - 6334 7306 0000 0000 00
75
+ - 6767 6767 6767 6767 671
76
+ :unionpay:
77
+ - 6264 1852 1292 2132 067
78
+ - 6288 9977 1545 2584
79
+ - 6269 9920 5813 4322
80
+ :dankort:
81
+ - 5019 7170 1010 3742
82
+ :switch:
83
+ - 6331 1019 9999 0016
84
+ :rupay:
85
+ - 6076 6000 0619 9992
86
+ - 6070 5500 5000 0047
87
+ :hipercard:
88
+ - 3841 0058 9908 8180 330
89
+ :elo:
90
+ - '4011 4141 3850 9070'
91
+ - '4389 3555 4728 7502'
92
+ - '4514 1620 5642 0699'
93
+ - '4576 5598 7564 9522'
94
+ - '5041 7572 2687 1008'
95
+ - '5066 9917 1703 9876'
96
+ - '5067 5391 6526 0388'
97
+ - '5090 4071 4078 7707'
98
+ - '5090 4270 1119 7080'
99
+ - '5090 4344 4788 5021'
100
+ - '5090 4514 6675 8555'
101
+ - '5090 4673 1437 9707'
102
+ - '5090 4791 2220 0924'
103
+ - '5090 4854 1570 5059'
104
+ - '5090 4968 1280 8652'
105
+ - '5090 5097 0678 9193'
106
+ - '5090 5157 9762 1083'
107
+ - '5090 5225 6947 6964'
108
+ - '5090 6473 8030 4070'
109
+ - '5090 6644 0324 2820'
110
+ - '5090 6724 8089 9317'
111
+ - '5090 6888 2173 4488'
112
+ - '5090 6948 3784 4758'
113
+ - '5090 7463 8779 6948'
114
+ - '6362 9745 2190 7765'
115
+ - '6363 6850 2897 2643'
data/spec/luhn_spec.rb ADDED
@@ -0,0 +1,20 @@
1
+ require "test_helper"
2
+ require "credit_card_detector/luhn"
3
+
4
+ module CreditCardDetector
5
+ describe Luhn do
6
+ describe ".valid?" do
7
+ it "returns true when number is valid" do
8
+ LUHN_ENABLED.each do |brand, card_numbers|
9
+ card_numbers.each do |number|
10
+ assert_equal Luhn.valid?(number.to_s.tr("- ", "")), true
11
+ end
12
+ end
13
+ end
14
+
15
+ it "returns false when number is invalid" do
16
+ assert_equal Luhn.valid?("4111111111111110"), false
17
+ end
18
+ end
19
+ end
20
+ end
data/spec/rule_spec.rb ADDED
@@ -0,0 +1,26 @@
1
+ require "test_helper"
2
+ require "credit_card_detector/rule"
3
+
4
+ module CreditCardDetector
5
+ describe Rule do
6
+ describe "#matches?" do
7
+ let(:rule) { Rule.new(length: [8, 9], prefixes: [1234, 2345]) }
8
+
9
+ it "matches when number has correct length AND starts from any prefix" do
10
+ assert_equal rule.matches?(12345678), true
11
+ assert_equal rule.matches?(234567890), true
12
+ end
13
+
14
+ it "doesn't match when number has incorrect length" do
15
+ assert_equal rule.matches?(123), false
16
+ assert_equal rule.matches?(""), false
17
+ assert_equal rule.matches?(1234567890123), false
18
+ end
19
+
20
+ it "doesn't match when number doesn't start from any prefix" do
21
+ assert_equal rule.matches?(01234567), false
22
+ assert_equal rule.matches?(00000000), false
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,9 @@
1
+ require "minitest/autorun"
2
+ require "credit_card_detector"
3
+
4
+ VALID_NUMBERS = YAML.load_file File.join(File.dirname(__FILE__), "fixtures/valid_cards.yml")
5
+ INVALID_NUMBERS = YAML.load_file File.join(File.dirname(__FILE__), "fixtures/invalid_cards.yml")
6
+
7
+ SKIP_LUHN = [:rupay, :elo, :unionpay]
8
+ LUHN_ENABLED = VALID_NUMBERS.reject { |k, _| SKIP_LUHN.include?(k) }
9
+ LUHN_DISABLED = VALID_NUMBERS.select { |k, _| SKIP_LUHN.include?(k) }
metadata ADDED
@@ -0,0 +1,120 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: credit_card_detector
3
+ version: !ruby/object:Gem::Version
4
+ version: '0.3'
5
+ platform: ruby
6
+ authors:
7
+ - Andrew Volozhanin
8
+ - Igor
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2016-09-20 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rake
16
+ requirement: !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - "~>"
19
+ - !ruby/object:Gem::Version
20
+ version: '10.5'
21
+ type: :development
22
+ prerelease: false
23
+ version_requirements: !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - "~>"
26
+ - !ruby/object:Gem::Version
27
+ version: '10.5'
28
+ - !ruby/object:Gem::Dependency
29
+ name: minitest
30
+ requirement: !ruby/object:Gem::Requirement
31
+ requirements:
32
+ - - "~>"
33
+ - !ruby/object:Gem::Version
34
+ version: '5.9'
35
+ type: :development
36
+ prerelease: false
37
+ version_requirements: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - "~>"
40
+ - !ruby/object:Gem::Version
41
+ version: '5.9'
42
+ - !ruby/object:Gem::Dependency
43
+ name: pry
44
+ requirement: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - ">="
47
+ - !ruby/object:Gem::Version
48
+ version: '0'
49
+ type: :development
50
+ prerelease: false
51
+ version_requirements: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - ">="
54
+ - !ruby/object:Gem::Version
55
+ version: '0'
56
+ description: A ruby gem for validating credit card numbers
57
+ email:
58
+ - scarfacedeb@gmail.com
59
+ - fedoronchuk@gmail.com
60
+ executables: []
61
+ extensions: []
62
+ extra_rdoc_files: []
63
+ files:
64
+ - ".hound.yml"
65
+ - ".travis.yml"
66
+ - Changelog.md
67
+ - Gemfile
68
+ - LICENSE.txt
69
+ - README.md
70
+ - Rakefile
71
+ - credit_card_detector.gemspec
72
+ - lib/credit_card_detector.rb
73
+ - lib/credit_card_detector/brand.rb
74
+ - lib/credit_card_detector/data.rb
75
+ - lib/credit_card_detector/detector.rb
76
+ - lib/credit_card_detector/error.rb
77
+ - lib/credit_card_detector/luhn.rb
78
+ - lib/credit_card_detector/rule.rb
79
+ - lib/credit_card_detector/version.rb
80
+ - lib/data/brands.yaml
81
+ - spec/brand_spec.rb
82
+ - spec/detector_spec.rb
83
+ - spec/fixtures/invalid_cards.yml
84
+ - spec/fixtures/valid_cards.yml
85
+ - spec/luhn_spec.rb
86
+ - spec/rule_spec.rb
87
+ - spec/test_helper.rb
88
+ homepage: ''
89
+ licenses:
90
+ - MIT
91
+ metadata: {}
92
+ post_install_message:
93
+ rdoc_options: []
94
+ require_paths:
95
+ - lib
96
+ required_ruby_version: !ruby/object:Gem::Requirement
97
+ requirements:
98
+ - - ">="
99
+ - !ruby/object:Gem::Version
100
+ version: '0'
101
+ required_rubygems_version: !ruby/object:Gem::Requirement
102
+ requirements:
103
+ - - ">="
104
+ - !ruby/object:Gem::Version
105
+ version: '0'
106
+ requirements: []
107
+ rubyforge_project:
108
+ rubygems_version: 2.5.1
109
+ signing_key:
110
+ specification_version: 4
111
+ summary: Gem provides basic credit card number validation and type detection without
112
+ any extra dependencies
113
+ test_files:
114
+ - spec/brand_spec.rb
115
+ - spec/detector_spec.rb
116
+ - spec/fixtures/invalid_cards.yml
117
+ - spec/fixtures/valid_cards.yml
118
+ - spec/luhn_spec.rb
119
+ - spec/rule_spec.rb
120
+ - spec/test_helper.rb