bank_card 0.0.4 → 0.1.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.
- data/README.rdoc +12 -2
- data/lib/bank_card/brands.rb +76 -0
- data/lib/bank_card/version.rb +1 -1
- data/lib/bank_card.rb +1 -0
- data/spec/lib/brands_spec.rb +154 -0
- metadata +24 -23
data/README.rdoc
CHANGED
@@ -5,15 +5,25 @@
|
|
5
5
|
|
6
6
|
== Description
|
7
7
|
|
8
|
-
This gem contains
|
8
|
+
This gem contains
|
9
|
+
* validation methods to check card number with Luhn method, card expiration date
|
10
|
+
* brand detection method for Visa, MasterCard, JCB, Discover, Maestro, Diners Club, American Express.
|
9
11
|
|
10
|
-
==
|
12
|
+
== Example
|
11
13
|
|
12
14
|
class CreditCard < ActiveRecord::Base
|
13
15
|
include BankCard::Validations
|
16
|
+
include BankCard::Brands
|
14
17
|
|
15
18
|
validates :number, :luhn => true
|
16
19
|
validates_expiration_of :date
|
20
|
+
|
21
|
+
before_create :set_brand
|
22
|
+
|
23
|
+
private
|
24
|
+
def set_brand
|
25
|
+
self.brand = detect_brand(number)
|
26
|
+
end
|
17
27
|
end
|
18
28
|
|
19
29
|
You can get more info from specs
|
@@ -0,0 +1,76 @@
|
|
1
|
+
module BankCard
|
2
|
+
module Brands
|
3
|
+
|
4
|
+
def detect_brand(number)
|
5
|
+
brand = [:visa, :american_express, :master, :jcb, :diners_club, :discover, :maestro].
|
6
|
+
detect { |brand| send("#{brand}?", number.to_s) }
|
7
|
+
|
8
|
+
brand ? brand : :unknown
|
9
|
+
end
|
10
|
+
|
11
|
+
private
|
12
|
+
# begin with 4 length 13, 16 or more
|
13
|
+
def visa?(number)
|
14
|
+
number =~ /^
|
15
|
+
4( # begin with 4
|
16
|
+
(\d{12})| # and length 13
|
17
|
+
(\d{15,}) # and length 16 or more
|
18
|
+
)
|
19
|
+
$/x
|
20
|
+
end
|
21
|
+
|
22
|
+
# begin with 34 or 37 and length 15
|
23
|
+
def american_express?(number)
|
24
|
+
number =~ /^3[47]\d{13}$/
|
25
|
+
end
|
26
|
+
|
27
|
+
# begin from 51 to 55 and length 16
|
28
|
+
def master?(number)
|
29
|
+
number =~ /^5[1-5]\d{14}$/
|
30
|
+
end
|
31
|
+
|
32
|
+
# begin from 3528 to 3589 and length 16
|
33
|
+
def jcb?(number)
|
34
|
+
number =~ /^ # begin with
|
35
|
+
35( # 35
|
36
|
+
(2[89])| # 28 to 29
|
37
|
+
([3-8][0-9]) # 30 to 89
|
38
|
+
)
|
39
|
+
\d{12} # and length 16
|
40
|
+
$/x
|
41
|
+
end
|
42
|
+
|
43
|
+
# begin from 300 to 305 and length 14
|
44
|
+
# or begin from 36 and length 14
|
45
|
+
def diners_club?(number)
|
46
|
+
number =~ /^ # begin
|
47
|
+
(30[0-5]\d{11})| # from 300 to 305 and length 14
|
48
|
+
(36\d{12}) # with 36 and length 14
|
49
|
+
$/x
|
50
|
+
end
|
51
|
+
|
52
|
+
# begin with 6011, 65, from 644 to 649, from 622126 to 622925 and length 16
|
53
|
+
def discover?(number)
|
54
|
+
number =~ /^ # begin with
|
55
|
+
(6011\d{12})| # 6011 and length 16
|
56
|
+
(65\d{14})| # 65 and length 16
|
57
|
+
(64[4-9]\d{13})| # 644 to 649 and length 16
|
58
|
+
(622 # 622
|
59
|
+
(
|
60
|
+
(12[6-9])| # 126 to 129
|
61
|
+
(1[3-9][0-9])| # 130 to 199
|
62
|
+
([2-8]\d{2})| # 200 to 899
|
63
|
+
(9[01]\d)| # 900 to 919
|
64
|
+
(92[0-5]) # 920 to 925
|
65
|
+
)\d{10} # and length 16
|
66
|
+
)
|
67
|
+
$/x
|
68
|
+
end
|
69
|
+
|
70
|
+
# begin with 5018, 5020, 5038, 6304, 6759, 6761, 6762, 6763 and length from 12 to 19
|
71
|
+
def maestro?(number)
|
72
|
+
number =~ /^(5018|5020|5038|6304|6759|6761|6762|6763)\d{8,15}$/
|
73
|
+
end
|
74
|
+
|
75
|
+
end
|
76
|
+
end
|
data/lib/bank_card/version.rb
CHANGED
data/lib/bank_card.rb
CHANGED
@@ -0,0 +1,154 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
class CreditCard
|
4
|
+
include BankCard::Brands
|
5
|
+
|
6
|
+
attr_accessor :number
|
7
|
+
end
|
8
|
+
|
9
|
+
describe BankCard::Brands do
|
10
|
+
describe "detected brand" do
|
11
|
+
let(:card) { CreditCard.new }
|
12
|
+
subject { card.detect_brand(number) }
|
13
|
+
|
14
|
+
context "when card number begins with 4" do
|
15
|
+
context "and its length 13 digits" do
|
16
|
+
let(:number) { '4234567890123' }
|
17
|
+
it { should == :visa }
|
18
|
+
end
|
19
|
+
|
20
|
+
context "and its length 16 digits" do
|
21
|
+
let(:number) { '4200000000000000' }
|
22
|
+
it { should == :visa }
|
23
|
+
end
|
24
|
+
|
25
|
+
context "and its length more than 16 digits" do
|
26
|
+
let(:number) { '420000000000000012' }
|
27
|
+
it { should == :visa }
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
[34, 37].each do |card_begin|
|
32
|
+
context "when card number begins with #{card_begin} and its length 15" do
|
33
|
+
let(:number) { "#{card_begin}3456789012345" }
|
34
|
+
it { should == :american_express }
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
(51..55).each do |card_begin|
|
39
|
+
context "when card number begins with #{card_begin} and its length 16" do
|
40
|
+
let(:number) { "#{card_begin}34567890123456" }
|
41
|
+
it { should == :master }
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
(3528..3589).each do |card_begin|
|
46
|
+
context "when card number begins with #{card_begin} and its length 16" do
|
47
|
+
let(:number) { "#{card_begin}567890123456" }
|
48
|
+
it { should == :jcb }
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
(300..305).each do |card_begin|
|
53
|
+
context "when card number begins with #{card_begin} and its length 14" do
|
54
|
+
let(:number) { "#{card_begin}45678901234" }
|
55
|
+
it { should == :diners_club }
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
context "when card number begins with 36 and its length 14" do
|
60
|
+
let(:number) { "36345678901234" }
|
61
|
+
it { should == :diners_club }
|
62
|
+
end
|
63
|
+
|
64
|
+
# 6011, 622126-622925, 644-649, 65 discover
|
65
|
+
context "when card number begins with 6011 and its length 16" do
|
66
|
+
let(:number) { "6011567890123456" }
|
67
|
+
it { should == :discover }
|
68
|
+
end
|
69
|
+
|
70
|
+
context "when card number begins with 65 and its length 16" do
|
71
|
+
let(:number) { "6534567890123456" }
|
72
|
+
it { should == :discover }
|
73
|
+
end
|
74
|
+
|
75
|
+
(644..649).each do |card_begin|
|
76
|
+
context "when card number begins with #{card_begin} and its length 16" do
|
77
|
+
let(:number) { "#{card_begin}4567890123456" }
|
78
|
+
it { should == :discover }
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
# discover begin from 622126 to 622925 and its length 16 - a lot of tests
|
83
|
+
# tested only the boundary cases
|
84
|
+
context "when card number begins with 622126 and its length 16" do
|
85
|
+
let(:number) { "6221267890123456" }
|
86
|
+
it { should == :discover }
|
87
|
+
end
|
88
|
+
context "when card number begins with 622129 and its length 16" do
|
89
|
+
let(:number) { "6221297890123456" }
|
90
|
+
it { should == :discover }
|
91
|
+
end
|
92
|
+
context "when card number begins with 622130 and its length 16" do
|
93
|
+
let(:number) { "6221307890123456" }
|
94
|
+
it { should == :discover }
|
95
|
+
end
|
96
|
+
context "when card number begins with 622199 and its length 16" do
|
97
|
+
let(:number) { "6221997890123456" }
|
98
|
+
it { should == :discover }
|
99
|
+
end
|
100
|
+
context "when card number begins with 622200 and its length 16" do
|
101
|
+
let(:number) { "6222007890123456" }
|
102
|
+
it { should == :discover }
|
103
|
+
end
|
104
|
+
context "when card number begins with 622899 and its length 16" do
|
105
|
+
let(:number) { "6228997890123456" }
|
106
|
+
it { should == :discover }
|
107
|
+
end
|
108
|
+
context "when card number begins with 622900 and its length 16" do
|
109
|
+
let(:number) { "6229007890123456" }
|
110
|
+
it { should == :discover }
|
111
|
+
end
|
112
|
+
context "when card number begins with 622919 and its length 16" do
|
113
|
+
let(:number) { "6229197890123456" }
|
114
|
+
it { should == :discover }
|
115
|
+
end
|
116
|
+
context "when card number begins with 622920 and its length 16" do
|
117
|
+
let(:number) { "6229207890123456" }
|
118
|
+
it { should == :discover }
|
119
|
+
end
|
120
|
+
context "when card number begins with 622925 and its length 16" do
|
121
|
+
let(:number) { "6229257890123456" }
|
122
|
+
it { should == :discover }
|
123
|
+
end
|
124
|
+
|
125
|
+
shared_examples_for "card length" do
|
126
|
+
context "and its length 12" do
|
127
|
+
let(:number) { "#{card_begin}#{'1'*(12 - card_begin.length)}" }
|
128
|
+
it { should == :maestro }
|
129
|
+
end
|
130
|
+
context "and its length greate than 12 and less then 19" do
|
131
|
+
let(:number) { "#{card_begin}#{'1'*(15 - card_begin.length)}" }
|
132
|
+
it { should == :maestro }
|
133
|
+
end
|
134
|
+
context "and its length 19" do
|
135
|
+
let(:number) { "#{card_begin}#{'1'*(19 - card_begin.length)}" }
|
136
|
+
it { should == :maestro }
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
[5018, 5020, 5038, 6304, 6759, 6761, 6762, 6763].each do |card_begin|
|
141
|
+
context "when card number begins with #{card_begin}" do
|
142
|
+
let(:card_begin) { card_begin.to_s }
|
143
|
+
it_should_behave_like "card length"
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
context "when not detect brand" do
|
148
|
+
let(:number) { "111213131290899" }
|
149
|
+
it { should == :unknown }
|
150
|
+
end
|
151
|
+
|
152
|
+
end
|
153
|
+
|
154
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: bank_card
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 0.1.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,12 +9,11 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
13
|
-
default_executable:
|
12
|
+
date: 2012-02-22 00:00:00.000000000Z
|
14
13
|
dependencies:
|
15
14
|
- !ruby/object:Gem::Dependency
|
16
15
|
name: rspec
|
17
|
-
requirement: &
|
16
|
+
requirement: &2153585680 !ruby/object:Gem::Requirement
|
18
17
|
none: false
|
19
18
|
requirements:
|
20
19
|
- - ! '>='
|
@@ -22,10 +21,10 @@ dependencies:
|
|
22
21
|
version: '0'
|
23
22
|
type: :development
|
24
23
|
prerelease: false
|
25
|
-
version_requirements: *
|
24
|
+
version_requirements: *2153585680
|
26
25
|
- !ruby/object:Gem::Dependency
|
27
26
|
name: guard
|
28
|
-
requirement: &
|
27
|
+
requirement: &2153585220 !ruby/object:Gem::Requirement
|
29
28
|
none: false
|
30
29
|
requirements:
|
31
30
|
- - ! '>='
|
@@ -33,10 +32,10 @@ dependencies:
|
|
33
32
|
version: '0'
|
34
33
|
type: :development
|
35
34
|
prerelease: false
|
36
|
-
version_requirements: *
|
35
|
+
version_requirements: *2153585220
|
37
36
|
- !ruby/object:Gem::Dependency
|
38
37
|
name: guard-rspec
|
39
|
-
requirement: &
|
38
|
+
requirement: &2153584680 !ruby/object:Gem::Requirement
|
40
39
|
none: false
|
41
40
|
requirements:
|
42
41
|
- - ! '>='
|
@@ -44,10 +43,10 @@ dependencies:
|
|
44
43
|
version: '0'
|
45
44
|
type: :development
|
46
45
|
prerelease: false
|
47
|
-
version_requirements: *
|
46
|
+
version_requirements: *2153584680
|
48
47
|
- !ruby/object:Gem::Dependency
|
49
48
|
name: guard-bundler
|
50
|
-
requirement: &
|
49
|
+
requirement: &2153584140 !ruby/object:Gem::Requirement
|
51
50
|
none: false
|
52
51
|
requirements:
|
53
52
|
- - ! '>='
|
@@ -55,10 +54,10 @@ dependencies:
|
|
55
54
|
version: '0'
|
56
55
|
type: :development
|
57
56
|
prerelease: false
|
58
|
-
version_requirements: *
|
57
|
+
version_requirements: *2153584140
|
59
58
|
- !ruby/object:Gem::Dependency
|
60
59
|
name: ruby-debug19
|
61
|
-
requirement: &
|
60
|
+
requirement: &2153583720 !ruby/object:Gem::Requirement
|
62
61
|
none: false
|
63
62
|
requirements:
|
64
63
|
- - ! '>='
|
@@ -66,10 +65,10 @@ dependencies:
|
|
66
65
|
version: '0'
|
67
66
|
type: :development
|
68
67
|
prerelease: false
|
69
|
-
version_requirements: *
|
68
|
+
version_requirements: *2153583720
|
70
69
|
- !ruby/object:Gem::Dependency
|
71
70
|
name: shoulda-matchers
|
72
|
-
requirement: &
|
71
|
+
requirement: &2153582420 !ruby/object:Gem::Requirement
|
73
72
|
none: false
|
74
73
|
requirements:
|
75
74
|
- - ! '>='
|
@@ -77,10 +76,10 @@ dependencies:
|
|
77
76
|
version: '0'
|
78
77
|
type: :development
|
79
78
|
prerelease: false
|
80
|
-
version_requirements: *
|
79
|
+
version_requirements: *2153582420
|
81
80
|
- !ruby/object:Gem::Dependency
|
82
81
|
name: timecop
|
83
|
-
requirement: &
|
82
|
+
requirement: &2153562380 !ruby/object:Gem::Requirement
|
84
83
|
none: false
|
85
84
|
requirements:
|
86
85
|
- - ! '>='
|
@@ -88,10 +87,10 @@ dependencies:
|
|
88
87
|
version: '0'
|
89
88
|
type: :development
|
90
89
|
prerelease: false
|
91
|
-
version_requirements: *
|
90
|
+
version_requirements: *2153562380
|
92
91
|
- !ruby/object:Gem::Dependency
|
93
92
|
name: activemodel
|
94
|
-
requirement: &
|
93
|
+
requirement: &2153561820 !ruby/object:Gem::Requirement
|
95
94
|
none: false
|
96
95
|
requirements:
|
97
96
|
- - ! '>='
|
@@ -99,10 +98,10 @@ dependencies:
|
|
99
98
|
version: '0'
|
100
99
|
type: :runtime
|
101
100
|
prerelease: false
|
102
|
-
version_requirements: *
|
101
|
+
version_requirements: *2153561820
|
103
102
|
- !ruby/object:Gem::Dependency
|
104
103
|
name: activesupport
|
105
|
-
requirement: &
|
104
|
+
requirement: &2153561340 !ruby/object:Gem::Requirement
|
106
105
|
none: false
|
107
106
|
requirements:
|
108
107
|
- - ! '>='
|
@@ -110,7 +109,7 @@ dependencies:
|
|
110
109
|
version: '0'
|
111
110
|
type: :runtime
|
112
111
|
prerelease: false
|
113
|
-
version_requirements: *
|
112
|
+
version_requirements: *2153561340
|
114
113
|
description: Gem includes validations, card brand detection method, etc.
|
115
114
|
email:
|
116
115
|
- alovak@gmail.com
|
@@ -125,13 +124,14 @@ files:
|
|
125
124
|
- Rakefile
|
126
125
|
- bank_card.gemspec
|
127
126
|
- lib/bank_card.rb
|
127
|
+
- lib/bank_card/brands.rb
|
128
128
|
- lib/bank_card/locale/en.yml
|
129
129
|
- lib/bank_card/validations/expiration_validator.rb
|
130
130
|
- lib/bank_card/validations/luhn_validator.rb
|
131
131
|
- lib/bank_card/version.rb
|
132
|
+
- spec/lib/brands_spec.rb
|
132
133
|
- spec/lib/validations_spec.rb
|
133
134
|
- spec/spec_helper.rb
|
134
|
-
has_rdoc: true
|
135
135
|
homepage: ''
|
136
136
|
licenses: []
|
137
137
|
post_install_message:
|
@@ -152,10 +152,11 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
152
152
|
version: '0'
|
153
153
|
requirements: []
|
154
154
|
rubyforge_project: bank_card
|
155
|
-
rubygems_version: 1.
|
155
|
+
rubygems_version: 1.8.12
|
156
156
|
signing_key:
|
157
157
|
specification_version: 3
|
158
158
|
summary: Bunch of methods to work with credit cards
|
159
159
|
test_files:
|
160
|
+
- spec/lib/brands_spec.rb
|
160
161
|
- spec/lib/validations_spec.rb
|
161
162
|
- spec/spec_helper.rb
|