credit_card_validations 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in credit_card_validations.gemspec
4
+ gemspec
@@ -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.
@@ -0,0 +1,75 @@
1
+ # CreditCardValidations
2
+
3
+ Gem adds validator to check whether or not a given number actually falls within the ranges of possible numbers prior to performing such verification, and, as such, CreditCardValidations simply verifies that the credit card number provided is well-formed.
4
+ This is a port of Zend Framework `Zend\Validator\CreditCard` .
5
+
6
+ The following issuing institutes are accepted:
7
+
8
+
9
+ American Express
10
+ China UnionPay
11
+ Diners Club
12
+ Dinner Club US
13
+ Discover
14
+ JCB
15
+ Maestro
16
+ MasterCard
17
+ Solo
18
+ Visa
19
+
20
+
21
+
22
+ Also You can add your own rules to detect other credit card brands/types
23
+ passing name,length(integer/array of integers) and prefix(string/array of strings)
24
+ Example
25
+
26
+ CreditCardValidations::Detector.add_rule(:voyager, 15, '86')
27
+ voyager_test_card_number = '869926275400212'
28
+ CreditCardValidations::Detector.new(voyager_test_card_number).brand #:voyager
29
+ CreditCardValidations::Detector.new(voyager_test_card_number).voyager? #true
30
+
31
+
32
+
33
+ AvtiveModel support
34
+
35
+ only for certain brads
36
+
37
+ class CreditCardModel
38
+ attr_accessor :number
39
+ include ActiveModel::Validations
40
+ validates :number, presence: true, credit_card_number: {brands: [:amex, :maestro]}
41
+ end
42
+
43
+ for all known brands
44
+
45
+ validates :number, presence: true, credit_card_number: true
46
+
47
+
48
+
49
+
50
+
51
+ ## Installation
52
+
53
+ Add this line to your application's Gemfile:
54
+
55
+ gem 'credit_card_validations'
56
+
57
+ And then execute:
58
+
59
+ $ bundle
60
+
61
+ Or install it yourself as:
62
+
63
+ $ gem install credit_card_validations
64
+
65
+ ## Usage
66
+
67
+
68
+
69
+ ## Contributing
70
+
71
+ 1. Fork it
72
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
73
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
74
+ 4. Push to the branch (`git push origin my-new-feature`)
75
+ 5. Create new Pull Request
@@ -0,0 +1,13 @@
1
+ require 'bundler/gem_tasks'
2
+
3
+ require 'rake'
4
+ require 'rake/testtask'
5
+
6
+ task :default => [:test_units]
7
+
8
+ desc "Run basic tests"
9
+ Rake::TestTask.new("test_units") { |t|
10
+ t.pattern = 'test/*_test.rb'
11
+ t.verbose = true
12
+ t.warning = true
13
+ }
@@ -0,0 +1,22 @@
1
+ # -*- encoding: utf-8 -*-
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'credit_card_validations/version'
5
+
6
+ Gem::Specification.new do |gem|
7
+ gem.name = "credit_card_validations"
8
+ gem.version = CreditCardValidations::VERSION
9
+ gem.authors = ["Igor"]
10
+ gem.email = ["fedoronchuk@gmail.com"]
11
+ gem.description = %q{A ruby gem for validating credit card numbers (a port of ZF2 Zend\Validator\CreditCard) —}
12
+ gem.summary = "gem for credit card numbers validation, card brands detections"
13
+ gem.homepage = "https://github.com/Fivell/credit_card_validations"
14
+
15
+ gem.files = `git ls-files`.split($/)
16
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
17
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
18
+ gem.require_paths = ["lib"]
19
+
20
+ gem.add_dependency('activemodel', '~> 3.0')
21
+ gem.add_dependency('activesupport', '~> 3.0')
22
+ end
@@ -0,0 +1,11 @@
1
+ class CreditCardNumberValidator < ActiveModel::EachValidator
2
+
3
+ def validate_each(record, attribute, value)
4
+ brands = options.fetch(:brands)
5
+ record.errors[attribute] << (options[:message] || "is not valid") unless credit_card_valid?(value, Array.wrap(brands))
6
+ end
7
+
8
+ def credit_card_valid?(number, brands = [])
9
+ CreditCardValidations::Detector.new(number).valid?(*brands)
10
+ end
11
+ end
@@ -0,0 +1,13 @@
1
+ require 'credit_card_validations/version'
2
+ require 'active_model'
3
+ require 'active_support/all'
4
+ require 'active_model/validations'
5
+ require 'credit_card_number_validator'
6
+
7
+ module CreditCardValidations
8
+ extend ActiveSupport::Autoload
9
+ autoload :VERSION, 'credit_card_validations/version'
10
+ autoload :Luhn, 'credit_card_validations/luhn'
11
+ autoload :CardRules , 'credit_card_validations/card_rules'
12
+ autoload :Detector , 'credit_card_validations/detector'
13
+ end
@@ -0,0 +1,58 @@
1
+ module CreditCardValidations
2
+ module CardRules
3
+ ######## most used brands #########
4
+
5
+
6
+ VISA = [
7
+ {length: [16], prefixes: ['4']}
8
+ ]
9
+ MASTERCARD = [
10
+ {length: [16], prefixes: ['51', '52', '53', '54', '55']}
11
+ ]
12
+ ######## other brands ########
13
+ AMEX = [
14
+ {length: [15], prefixes: ['34', '37']}
15
+ ]
16
+
17
+ DINERS = [
18
+ {length: [14], prefixes: ['300', '301', '302', '303', '304', '305', '36']},
19
+ ]
20
+
21
+ #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
22
+ DINERS_US = [
23
+ {length: [16], prefixes: ['54', '55']}
24
+ ]
25
+
26
+ DISCOVER = [
27
+ {length: [16], prefixes: ['6011', '622126', '622127', '622128', '622129', '62213',
28
+ '62214', '62215', '62216', '62217', '62218', '62219',
29
+ '6222', '6223', '6224', '6225', '6226', '6227', '6228',
30
+ '62290', '62291', '622920', '622921', '622922', '622923',
31
+ '622924', '622925', '644', '645', '646', '647', '648',
32
+ '649', '65']}
33
+ ]
34
+
35
+ JCB = [
36
+ {length: [16], prefixes: ['3528', '3529', '353', '354', '355', '356', '357', '358']}
37
+ ]
38
+
39
+
40
+ LASER = [
41
+ {length: [16, 17, 18, 19], prefixes: ['6304', '6706', '6771', '6709']}
42
+ ]
43
+
44
+ MAESTRO = [
45
+ {length: [12, 13, 14, 15, 16, 17, 18, 19], prefixes: ['5018', '5020', '5038', '6304', '6759', '6761', '6763']}
46
+ ]
47
+
48
+ SOLO = [
49
+ {length: [16, 18, 19], prefixes: ['6334', '6767']}
50
+ ]
51
+
52
+ UNIONPAY = [
53
+ {length: [16, 17, 18, 19], prefixes: ['620', '621', '623', '625', '626']}
54
+ ]
55
+
56
+
57
+ end
58
+ end
@@ -0,0 +1,72 @@
1
+ module CreditCardValidations
2
+ class Detector
3
+ class_attribute :rules
4
+ self.rules = {}
5
+
6
+ attr_reader :number
7
+
8
+ def initialize(number)
9
+ @number = number.to_s.delete(' ')
10
+ end
11
+
12
+ # credit card number
13
+ def valid?(*brands)
14
+ !!valid_number?(*brands)
15
+ end
16
+
17
+ #brand name
18
+ def brand
19
+ valid_number?
20
+ end
21
+
22
+ def valid_number?(*brands)
23
+ return nil unless valid_luhn?
24
+ number_length = number.length
25
+ brand_rules = brands.blank? ? self.rules : self.rules.slice(*brands.map{|el| el.downcase })
26
+ unless brand_rules.blank?
27
+ brand_rules.each do |brand_name, rules|
28
+ rules.each do |rule|
29
+ return brand_name if (rule[:length].include?(number_length) and number.match(rule[:regexp]))
30
+ end
31
+ end
32
+ end
33
+ nil
34
+ end
35
+
36
+ #check if luhn valid
37
+ def valid_luhn?
38
+ Luhn.valid?(number)
39
+ end
40
+
41
+ class << self
42
+
43
+ #create regexp by array of prefixes
44
+ def compile_regexp(prefixes)
45
+ Regexp.new("^((#{prefixes.join(")|(")}))")
46
+ end
47
+
48
+ #create rule for detecting brand
49
+ def add_rule(brand, length, prefixes)
50
+ prefixes = Array.wrap(prefixes)
51
+ length = Array.wrap(length)
52
+ rules[brand] = [] if rules[brand].blank?
53
+ rules[brand] << {length: length, regexp: compile_regexp(prefixes), prefixes: prefixes}
54
+ #create methods like visa? mastercard? etc
55
+ class_eval <<-BOOLEAN_RULE, __FILE__, __LINE__
56
+ def #{brand}?
57
+ valid?(:#{brand})
58
+ end
59
+ BOOLEAN_RULE
60
+ end
61
+ end
62
+
63
+ CardRules.constants.each do |const_name|
64
+ CardRules.const_get(const_name).each do |const_value|
65
+ self.add_rule(const_name.to_s.downcase.to_sym , const_value[:length], const_value[:prefixes])
66
+ end
67
+
68
+ end
69
+ end
70
+
71
+
72
+ end
@@ -0,0 +1,17 @@
1
+ module CreditCardValidations
2
+ class Luhn
3
+ def self.valid?(number)
4
+ s1 = s2 = 0
5
+ number.to_s.reverse.chars.each_slice(2) do |odd, even|
6
+ s1 += odd.to_i
7
+
8
+ double = even.to_i * 2
9
+ double -= 9 if double >= 10
10
+ s2 += double
11
+ end
12
+ (s1 + s2) % 10 == 0
13
+ end
14
+ end
15
+ end
16
+
17
+
@@ -0,0 +1,3 @@
1
+ module CreditCardValidations
2
+ VERSION = "1.0.0"
3
+ end
@@ -0,0 +1,92 @@
1
+ require 'test/unit'
2
+ lib = File.expand_path("#{File.dirname(__FILE__)}/../lib")
3
+ unit_tests = File.expand_path("#{File.dirname(__FILE__)}/../test")
4
+ $:.unshift(lib)
5
+ $:.unshift(unit_tests)
6
+
7
+ require 'credit_card_validations'
8
+
9
+ class CreditCardValidationsTest < Test::Unit::TestCase
10
+
11
+ class CreditCardModel
12
+ attr_accessor :number
13
+ include ActiveModel::Validations
14
+ validates :number, presence: true, credit_card_number: {brands: [:amex, :maestro]}
15
+ end
16
+
17
+
18
+ def initialize name
19
+ super name
20
+ @test_numbers = {
21
+ visa: '4012 8888 8888 1881',
22
+ mastercard: '5274 5763 9425 9961',
23
+ diners: '3020 4169 3226 43',
24
+ amex: '3400 0000 0000 009',
25
+ discover: '6011 1111 1111 1117',
26
+ maestro: '6759 6498 2643 8453',
27
+ jcb: '3575 7591 5225 4876',
28
+ solo: '6767 6222 2222 2222 222',
29
+ unionpay: '6264185212922132067',
30
+
31
+ }
32
+ end
33
+
34
+ def test_card_brand_detection
35
+ @test_numbers.each do |key, value|
36
+ assert_equal key, detector(value).brand
37
+ assert detector(value).send("#{key}?")
38
+ end
39
+ end
40
+
41
+ def test_card_brand_is_nil_if_credit_card_invalid
42
+ assert_nil detector('1111111111111111').brand
43
+ end
44
+
45
+ def test_card_valid_method
46
+ @test_numbers.each do |key, value|
47
+ assert detector(value).valid?(key)
48
+ assert detector(value).valid?
49
+ end
50
+ assert !detector('1111111111111111').valid?
51
+ end
52
+
53
+
54
+ def test_card_particular_brand_valid
55
+ assert !detector(@test_numbers[:visa]).valid?(:mastercard)
56
+ assert !detector(@test_numbers[:mastercard]).valid?(:visa)
57
+ end
58
+
59
+
60
+ def test_card_particular_brands_valid
61
+ assert detector(@test_numbers[:visa]).valid?(:mastercard, :visa)
62
+ assert !detector(@test_numbers[:visa]).valid?(:mastercard, :amex)
63
+ end
64
+
65
+ #add rules which were not present before
66
+ def test_card_valid_after_rules_added
67
+ voyager_test_card_number = '869926275400212'
68
+ assert !detector(voyager_test_card_number).valid?
69
+ CreditCardValidations::Detector.add_rule(:voyager, 15, '86')
70
+ assert detector(voyager_test_card_number).valid?
71
+ assert_equal :voyager, detector(voyager_test_card_number).brand
72
+ assert detector(voyager_test_card_number).voyager?
73
+ assert !detector(voyager_test_card_number).visa?
74
+ assert !detector(voyager_test_card_number).mastercard?
75
+ end
76
+
77
+ def test_active_model_validator
78
+ cc = CreditCardModel.new
79
+ cc.number = @test_numbers[:mastercard]
80
+ assert !cc.valid?
81
+ cc.number = @test_numbers[:amex]
82
+ assert cc.valid?
83
+ end
84
+
85
+ protected
86
+
87
+ def detector(number)
88
+ CreditCardValidations::Detector.new(number)
89
+ end
90
+
91
+
92
+ end
metadata ADDED
@@ -0,0 +1,82 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: credit_card_validations
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Igor
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-03-19 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: activemodel
16
+ requirement: &70262684219780 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: '3.0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: *70262684219780
25
+ - !ruby/object:Gem::Dependency
26
+ name: activesupport
27
+ requirement: &70262684219080 !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ~>
31
+ - !ruby/object:Gem::Version
32
+ version: '3.0'
33
+ type: :runtime
34
+ prerelease: false
35
+ version_requirements: *70262684219080
36
+ description: A ruby gem for validating credit card numbers (a port of ZF2 Zend\Validator\CreditCard)
37
+
38
+ email:
39
+ - fedoronchuk@gmail.com
40
+ executables: []
41
+ extensions: []
42
+ extra_rdoc_files: []
43
+ files:
44
+ - Gemfile
45
+ - LICENSE.txt
46
+ - README.md
47
+ - Rakefile
48
+ - credit_card_validations.gemspec
49
+ - lib/credit_card_number_validator.rb
50
+ - lib/credit_card_validations.rb
51
+ - lib/credit_card_validations/card_rules.rb
52
+ - lib/credit_card_validations/detector.rb
53
+ - lib/credit_card_validations/luhn.rb
54
+ - lib/credit_card_validations/version.rb
55
+ - test/credit_card_validations_test.rb
56
+ homepage: https://github.com/Fivell/credit_card_validations
57
+ licenses: []
58
+ post_install_message:
59
+ rdoc_options: []
60
+ require_paths:
61
+ - lib
62
+ required_ruby_version: !ruby/object:Gem::Requirement
63
+ none: false
64
+ requirements:
65
+ - - ! '>='
66
+ - !ruby/object:Gem::Version
67
+ version: '0'
68
+ required_rubygems_version: !ruby/object:Gem::Requirement
69
+ none: false
70
+ requirements:
71
+ - - ! '>='
72
+ - !ruby/object:Gem::Version
73
+ version: '0'
74
+ requirements: []
75
+ rubyforge_project:
76
+ rubygems_version: 1.8.17
77
+ signing_key:
78
+ specification_version: 3
79
+ summary: gem for credit card numbers validation, card brands detections
80
+ test_files:
81
+ - test/credit_card_validations_test.rb
82
+ has_rdoc: