credit_card_validations 1.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.
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: