credit_card_validator 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +4 -0
- data/Manifest.txt +8 -0
- data/README.rdoc +70 -0
- data/Rakefile +27 -0
- data/lib/credit_card_validator.rb +8 -0
- data/lib/credit_card_validator/validator.rb +87 -0
- data/test/test_credit_card_validator.rb +86 -0
- data/test/test_helper.rb +3 -0
- metadata +86 -0
data/History.txt
ADDED
data/Manifest.txt
ADDED
data/README.rdoc
ADDED
@@ -0,0 +1,70 @@
|
|
1
|
+
= credit_card_validator
|
2
|
+
|
3
|
+
* http://github.com/tobias/credit_card_validator
|
4
|
+
|
5
|
+
== DESCRIPTION:
|
6
|
+
|
7
|
+
A gem that provides credit card validation. It is basically a ruby port of the javascript credit card validator by Thomas Fuchs (madrobby) (http://github.com/madrobby/creditcard_js).
|
8
|
+
|
9
|
+
== SYNOPSIS:
|
10
|
+
|
11
|
+
Usage:
|
12
|
+
CreditCardValidator::Validator.valid?('1111 2222 3333 4444')
|
13
|
+
|
14
|
+
# allow test numbers to be valid (for development)
|
15
|
+
CreditCardValidator::Validator.options[:test_numbers_are_valid] = true
|
16
|
+
CreditCardValidator::Validator.valid?('1111 2222 3333 4444')
|
17
|
+
|
18
|
+
# limit the card types you allow
|
19
|
+
CreditCardValidator::Validator.options[:allowed_card_types] = [:visa, :mastercard]
|
20
|
+
CreditCardValidator::Validator.valid?('1111 2222 3333 4444')
|
21
|
+
|
22
|
+
Supported card types:
|
23
|
+
:amex, :discover, :diners_club, :master_card, :visa
|
24
|
+
|
25
|
+
Whitespace is stripped from the number automatically.
|
26
|
+
|
27
|
+
The following things are tested:
|
28
|
+
1. does the luhn validation code add up? (see http://en.wikipedia.org/wiki/Luhn_algorithm)
|
29
|
+
2. does the number range and length seem right? (see http://en.wikipedia.org/wiki/Bank_card_number)
|
30
|
+
3. is it one of several well-known test numbers?
|
31
|
+
|
32
|
+
Note: this only validates that the number is of a valid format, it does not check if it is an actual credit card number. You will need to talk to your payment gateway to learn that.
|
33
|
+
|
34
|
+
You can also use the validator to learn about the type of the card:
|
35
|
+
|
36
|
+
# gives the type back as a string (visa, master_card, etc)
|
37
|
+
CreditCardValidator::Validator.card_type(number)
|
38
|
+
|
39
|
+
CreditCardValidator::Validator.is_visa?(number)
|
40
|
+
CreditCardValidator::Validator.is_master_card?(number)
|
41
|
+
# etc. - works for all of the supported card types
|
42
|
+
|
43
|
+
CreditCardValidator::Validator.is_allowed_card_type?(number)
|
44
|
+
|
45
|
+
== INSTALL:
|
46
|
+
|
47
|
+
* gem install tobias-credit_card_validator --source http://gems.github.com
|
48
|
+
|
49
|
+
== LICENSE:
|
50
|
+
|
51
|
+
Copyright (c) 2009 Tobias Crawley & Bruce Hauman
|
52
|
+
|
53
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
54
|
+
a copy of this software and associated documentation files (the
|
55
|
+
'Software'), to deal in the Software without restriction, including
|
56
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
57
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
58
|
+
permit persons to whom the Software is furnished to do so, subject to
|
59
|
+
the following conditions:
|
60
|
+
|
61
|
+
The above copyright notice and this permission notice shall be
|
62
|
+
included in all copies or substantial portions of the Software.
|
63
|
+
|
64
|
+
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
65
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
66
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
67
|
+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
68
|
+
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
69
|
+
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
70
|
+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/Rakefile
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
%w[rubygems rake rake/clean fileutils newgem rubigen].each { |f| require f }
|
2
|
+
require File.dirname(__FILE__) + '/lib/credit_card_validator'
|
3
|
+
|
4
|
+
# Generate all the Rake tasks
|
5
|
+
# Run 'rake -T' to see list of generated tasks (from gem root directory)
|
6
|
+
$hoe = Hoe.new('credit_card_validator', CreditCardValidator::VERSION) do |p|
|
7
|
+
p.developer('Tobias Crawley', 'tcrawley@gmail.com')
|
8
|
+
p.changes = p.paragraphs_of("History.txt", 0..1).join("\n\n")
|
9
|
+
p.rubyforge_name = p.name # TODO this is default value
|
10
|
+
# p.extra_deps = [
|
11
|
+
# ['activesupport','>= 2.0.2'],
|
12
|
+
# ]
|
13
|
+
p.extra_dev_deps = [
|
14
|
+
['newgem', ">= #{::Newgem::VERSION}"]
|
15
|
+
]
|
16
|
+
|
17
|
+
p.clean_globs |= %w[**/.DS_Store tmp *.log]
|
18
|
+
path = (p.rubyforge_name == p.name) ? p.rubyforge_name : "\#{p.rubyforge_name}/\#{p.name}"
|
19
|
+
p.remote_rdoc_dir = File.join(path.gsub(/^#{p.rubyforge_name}\/?/,''), 'rdoc')
|
20
|
+
p.rsync_args = '-av --delete --ignore-errors'
|
21
|
+
end
|
22
|
+
|
23
|
+
require 'newgem/tasks' # load /tasks/*.rake
|
24
|
+
Dir['tasks/**/*.rake'].each { |t| load t }
|
25
|
+
|
26
|
+
# TODO - want other tests/tasks run by default? Add them to the list
|
27
|
+
# task :default => [:spec, :features]
|
@@ -0,0 +1,8 @@
|
|
1
|
+
$:.unshift(File.dirname(__FILE__)) unless
|
2
|
+
$:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
|
3
|
+
|
4
|
+
require File.join(File.dirname(__FILE__), 'credit_card_validator', 'validator')
|
5
|
+
|
6
|
+
module CreditCardValidator
|
7
|
+
VERSION = '0.1.0'
|
8
|
+
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
module CreditCardValidator
|
2
|
+
CARD_TYPES = {
|
3
|
+
:visa => /^4[0-9]{12}(?:[0-9]{3})?$/,
|
4
|
+
:master_card => /^5[1-5][0-9]{14}$/,
|
5
|
+
:diners_club => /^3(?:0[0-5]|[68][0-9])[0-9]{11}$/,
|
6
|
+
:amex => /^3[47][0-9]{13}$/,
|
7
|
+
:discover => /^6(?:011|5[0-9]{2})[0-9]{12}$/
|
8
|
+
}
|
9
|
+
|
10
|
+
TEST_NUMBERS = %w{
|
11
|
+
378282246310005 371449635398431 378734493671000
|
12
|
+
30569309025904 38520000023237 6011111111111117
|
13
|
+
6011000990139424 5555555555554444 5105105105105100
|
14
|
+
4111111111111111 4012888888881881 4222222222222
|
15
|
+
}
|
16
|
+
|
17
|
+
class Validator
|
18
|
+
class << self
|
19
|
+
def valid?(number)
|
20
|
+
is_allowed_card_type?(number) and
|
21
|
+
verify_luhn(number) and
|
22
|
+
card_type(number) and
|
23
|
+
(options[:test_numbers_are_valid] ? true : !is_test_number(number))
|
24
|
+
end
|
25
|
+
|
26
|
+
def options
|
27
|
+
@@options ||= {}
|
28
|
+
end
|
29
|
+
|
30
|
+
def card_type(number)
|
31
|
+
CARD_TYPES.keys.each do |t|
|
32
|
+
return t.to_s if card_is(t, number)
|
33
|
+
end
|
34
|
+
nil
|
35
|
+
end
|
36
|
+
|
37
|
+
def is_allowed_card_type?(number)
|
38
|
+
card_type = card_type(number)
|
39
|
+
if options[:allowed_card_types] and options[:allowed_card_types].respond_to?('include?')
|
40
|
+
options[:allowed_card_types].include?(card_type.to_sym)
|
41
|
+
else
|
42
|
+
!card_type.nil?
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def is_test_number(number)
|
47
|
+
TEST_NUMBERS.include?(strip(number))
|
48
|
+
end
|
49
|
+
|
50
|
+
def verify_luhn(number)
|
51
|
+
total = strip(number).reverse().split(//).inject([0,0]) do |accum,n|
|
52
|
+
n = n.to_i
|
53
|
+
accum[0] += (accum[1] % 2 == 1 ? rotate(n * 2) : n)
|
54
|
+
accum[1] += 1
|
55
|
+
accum
|
56
|
+
end
|
57
|
+
|
58
|
+
(total[0] % 10 == 0)
|
59
|
+
end
|
60
|
+
|
61
|
+
CARD_TYPES.keys.each do |card_type|
|
62
|
+
self.class_eval do
|
63
|
+
define_method "is_#{card_type.to_s}?" do |number|
|
64
|
+
card_is(card_type, number)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
protected
|
70
|
+
def strip(number)
|
71
|
+
number.gsub(/\s/,'')
|
72
|
+
end
|
73
|
+
|
74
|
+
def rotate(number)
|
75
|
+
if number > 9
|
76
|
+
number = number % 10 + 1
|
77
|
+
end
|
78
|
+
number
|
79
|
+
end
|
80
|
+
|
81
|
+
def card_is(type, number)
|
82
|
+
type = type.to_sym
|
83
|
+
(CARD_TYPES[type] and strip(number) =~ CARD_TYPES[type])
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
@@ -0,0 +1,86 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/test_helper.rb'
|
2
|
+
|
3
|
+
class TestCreditCardValidator < Test::Unit::TestCase
|
4
|
+
|
5
|
+
def setup
|
6
|
+
@v = CreditCardValidator::Validator
|
7
|
+
@v.options.clear
|
8
|
+
end
|
9
|
+
|
10
|
+
|
11
|
+
def test_recognize_card_type
|
12
|
+
assert_equal 'visa', @v.card_type('4111111111111111')
|
13
|
+
assert_equal 'master_card', @v.card_type('5555555555554444')
|
14
|
+
assert_equal 'diners_club', @v.card_type('30569309025904')
|
15
|
+
assert_equal 'amex', @v.card_type('371449635398431')
|
16
|
+
assert_equal 'discover', @v.card_type('6011000990139424')
|
17
|
+
|
18
|
+
end
|
19
|
+
|
20
|
+
def test_detect_specific_types
|
21
|
+
assert @v.is_visa?('4111111111111111')
|
22
|
+
assert !@v.is_visa?('5555555555554444')
|
23
|
+
assert !@v.is_visa?('30569309025904')
|
24
|
+
assert !@v.is_visa?('371449635398431')
|
25
|
+
assert !@v.is_visa?('6011000990139424')
|
26
|
+
assert @v.is_master_card?('5555555555554444')
|
27
|
+
assert @v.is_diners_club?('30569309025904')
|
28
|
+
assert @v.is_amex?('371449635398431')
|
29
|
+
assert @v.is_discover?('6011000990139424')
|
30
|
+
end
|
31
|
+
|
32
|
+
def test_luhn_verification
|
33
|
+
assert @v.verify_luhn('49927398716')
|
34
|
+
assert @v.verify_luhn('049927398716')
|
35
|
+
assert @v.verify_luhn('0049927398716')
|
36
|
+
assert !@v.verify_luhn('49927398715')
|
37
|
+
assert !@v.verify_luhn('49927398717')
|
38
|
+
end
|
39
|
+
|
40
|
+
def test_ignore_whitespace
|
41
|
+
assert_equal '4111111111111111', @v.send('strip', '4111 1111 1111 1111 ')
|
42
|
+
|
43
|
+
assert_equal 'visa', @v.card_type('4111 1111 1111 1111 ')
|
44
|
+
assert_equal 'visa', @v.card_type(' 4111 1111 1111 1111 ')
|
45
|
+
assert_equal 'visa', @v.card_type("\n4111 1111\t 1111 1111 ")
|
46
|
+
assert @v.verify_luhn(' 004 992739 87 16')
|
47
|
+
assert @v.is_test_number('601 11111111111 17')
|
48
|
+
end
|
49
|
+
|
50
|
+
def test_should_recognize_test_numbers
|
51
|
+
%w(
|
52
|
+
378282246310005 371449635398431 378734493671000
|
53
|
+
30569309025904 38520000023237 6011111111111117
|
54
|
+
6011000990139424 5555555555554444 5105105105105100
|
55
|
+
4111111111111111 4012888888881881 4222222222222
|
56
|
+
).each do |n|
|
57
|
+
assert @v.is_test_number(n)
|
58
|
+
end
|
59
|
+
|
60
|
+
assert !@v.is_test_number('1234')
|
61
|
+
end
|
62
|
+
|
63
|
+
def test_test_number_validity_cases
|
64
|
+
assert !@v.valid?('378282246310005')
|
65
|
+
@v.options[:test_numbers_are_valid] = true
|
66
|
+
assert @v.valid?('378282246310005')
|
67
|
+
end
|
68
|
+
|
69
|
+
def test_is_allowed_card_type
|
70
|
+
assert @v.is_allowed_card_type?('378282246310005')
|
71
|
+
@v.options[:allowed_card_types] = [:visa]
|
72
|
+
assert @v.is_allowed_card_type?('4012888888881881')
|
73
|
+
assert !@v.is_allowed_card_type?('378282246310005')
|
74
|
+
|
75
|
+
end
|
76
|
+
|
77
|
+
def test_card_type_allowance
|
78
|
+
@v.options[:test_numbers_are_valid] = true
|
79
|
+
assert @v.valid?('378282246310005')
|
80
|
+
@v.options[:allowed_card_types] = [:visa]
|
81
|
+
assert @v.valid?('4012888888881881')
|
82
|
+
assert !@v.valid?('378282246310005')
|
83
|
+
|
84
|
+
end
|
85
|
+
|
86
|
+
end
|
data/test/test_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,86 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: credit_card_validator
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Tobias Crawley
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2009-12-04 00:00:00 -05:00
|
13
|
+
default_executable:
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: newgem
|
17
|
+
type: :development
|
18
|
+
version_requirement:
|
19
|
+
version_requirements: !ruby/object:Gem::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ">="
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: 1.2.3
|
24
|
+
version:
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: hoe
|
27
|
+
type: :development
|
28
|
+
version_requirement:
|
29
|
+
version_requirements: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 1.8.0
|
34
|
+
version:
|
35
|
+
description: A gem that provides credit card validation. It is basically a ruby port of the javascript credit card validator by Thomas Fuchs (madrobby) (http://github.com/madrobby/creditcard_js).
|
36
|
+
email:
|
37
|
+
- tcrawley@gmail.com
|
38
|
+
executables: []
|
39
|
+
|
40
|
+
extensions: []
|
41
|
+
|
42
|
+
extra_rdoc_files:
|
43
|
+
- History.txt
|
44
|
+
- Manifest.txt
|
45
|
+
- README.rdoc
|
46
|
+
files:
|
47
|
+
- History.txt
|
48
|
+
- Manifest.txt
|
49
|
+
- README.rdoc
|
50
|
+
- Rakefile
|
51
|
+
- lib/credit_card_validator.rb
|
52
|
+
- lib/credit_card_validator/validator.rb
|
53
|
+
- test/test_credit_card_validator.rb
|
54
|
+
- test/test_helper.rb
|
55
|
+
has_rdoc: true
|
56
|
+
homepage: http://github.com/tobias/credit_card_validator
|
57
|
+
licenses: []
|
58
|
+
|
59
|
+
post_install_message:
|
60
|
+
rdoc_options:
|
61
|
+
- --main
|
62
|
+
- README.rdoc
|
63
|
+
require_paths:
|
64
|
+
- lib
|
65
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
66
|
+
requirements:
|
67
|
+
- - ">="
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: "0"
|
70
|
+
version:
|
71
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: "0"
|
76
|
+
version:
|
77
|
+
requirements: []
|
78
|
+
|
79
|
+
rubyforge_project: credit_card_validator
|
80
|
+
rubygems_version: 1.3.5
|
81
|
+
signing_key:
|
82
|
+
specification_version: 3
|
83
|
+
summary: A gem that provides credit card validation
|
84
|
+
test_files:
|
85
|
+
- test/test_credit_card_validator.rb
|
86
|
+
- test/test_helper.rb
|