Skip to content

Commit

Permalink
Merge 89b3154 into 8c914db
Browse files Browse the repository at this point in the history
  • Loading branch information
Fivell committed Jul 15, 2015
2 parents 8c914db + 89b3154 commit 879af0c
Show file tree
Hide file tree
Showing 16 changed files with 130 additions and 95 deletions.
4 changes: 3 additions & 1 deletion Changelog.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
# 2.0.3
# 3.0.0
* Remove Laser brand because Laser cards were withdrawn from the market on February 28 2014
* Remove Diners US brand for similar reason
* Move Laser ranges to Maestro. Add 6390 range to Maestro
* Add plugins for removed brands

# 2.0.2
* fix using ActiveModel Validator's message option
Expand Down
82 changes: 43 additions & 39 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,25 +31,34 @@ Or install it yourself as:

The following issuing institutes are accepted:

<table><tr><td>name</td> <td>key</td> </tr>

<tr><td>[American Express](http://en.wikipedia.org/wiki/American_Express) </td> <td> :amex </td> </tr>
<tr><td>[China UnionPay ](http://en.wikipedia.org/wiki/China_UnionPay) </td> <td> :unionpay </td> </tr>
<tr><td>[Dankort ](http://en.wikipedia.org/wiki/Dankort) </td> <td> :dankort </td> </tr>
<tr><td>[Diners Club ](http://en.wikipedia.org/wiki/Diners_Club_International) </td> <td> :diners </td> </tr>
<tr><td>[Dinner Club US](http://en.wikipedia.org/wiki/Diners_Club_International#MasterCard_alliance) </td> <td> :diners_us </td> </tr>
<tr><td>[Discover](http://en.wikipedia.org/wiki/Discover_Card) </td> <td> :discover </td> </tr>
<tr><td>[Hipercard ](http://pt.wikipedia.org/wiki/Hipercard) </td> <td> :hipercard </td> </tr>
<tr><td>[JCB ](http://en.wikipedia.org/wiki/Japan_Credit_Bureau) </td> <td> :jcb </td> </tr>
<tr><td>[Maestro](http://en.wikipedia.org/wiki/Maestro_%28debit_card%29) </td> <td> :maestro </td> </tr>
<tr><td>[MasterCard ](http://en.wikipedia.org/wiki/MasterCard) </td> <td> :mastercard </td> </tr>
<tr><td>[Rupay ](http://en.wikipedia.org/wiki/RuPay) </td> <td> :rupay </td>
<tr><td>[Solo ](http://en.wikipedia.org/wiki/Solo_(debit_card)) </td> <td> :solo </td> </tr>
<tr><td>[Switch ](http://en.wikipedia.org/wiki/Switch_(debit_card)) </td> <td> :switch </td> </tr>
<tr><td>[Visa ](http://en.wikipedia.org/wiki/Visa_Inc.) </td> <td> :visa </td> </tr>
</table>

Examples using string monkey patch
Name | Key |
--------------------- | ------------|
[American Express](http://en.wikipedia.org/wiki/American_Express) | :amex
[China UnionPay](http://en.wikipedia.org/wiki/China_UnionPay) | :unionpay
[Dankort](http://en.wikipedia.org/wiki/Dankort) | :dankort
[Diners Club](http://en.wikipedia.org/wiki/Diners_Club_International) | :diners
[Discover](http://en.wikipedia.org/wiki/Discover_Card) | :discover
[Hipercard](http://pt.wikipedia.org/wiki/Hipercard) | :hipercard
[JCB](http://en.wikipedia.org/wiki/Japan_Credit_Bureau) | :jcb
[Maestro](http://en.wikipedia.org/wiki/Maestro_%28debit_card%29) | :maestro
[MasterCard](http://en.wikipedia.org/wiki/MasterCard) | :mastercard
[Rupay](http://en.wikipedia.org/wiki/RuPay) | :rupay
[Solo](http://en.wikipedia.org/wiki/Solo_(debit_card)) | :solo
[Switch](http://en.wikipedia.org/wiki/Switch_(debit_card)) | :switch
[Visa](http://en.wikipedia.org/wiki/Visa_Inc.) | :visa


The following are supported with with plugins

Name | Key |
--------------------- | ------------|
[Diners Club US](http://en.wikipedia.org/wiki/Diners_Club_International#MasterCard_alliance) | :diners_us
[EnRoute](https://en.wikipedia.org/wiki/EnRoute_(credit_card)) | :en_route
[Laser](https://en.wikipedia.org/wiki/Laser_%28debit_card%29) | :laser



### Examples using string monkey patch

```ruby
require 'credit_card_validations/string'
Expand All @@ -60,7 +69,7 @@ Examples using string monkey patch
'5274 5763 9425 9961'.valid_credit_card_brand?('MasterCard') #=> true
```

ActiveModel support
### ActiveModel support

only for certain brads

Expand All @@ -78,7 +87,7 @@ for all known brands
validates :number, presence: true, credit_card_number: true
```

Examples using CreditCardValidations::Detector class
### Examples using CreditCardValidations::Detector class

```ruby
number = "4111111111111111"
Expand All @@ -90,46 +99,32 @@ Examples using CreditCardValidations::Detector class
detector.issuer_category #"Banking and financial"
```

Also You can add your own brand rules to detect other credit card brands/types
### Also You can add your own brand rules to detect other credit card brands/types
passing name,length(integer/array of integers) and prefix(string/array of strings)
Example

```ruby
CreditCardValidations.add_brand(:voyager, {length: 15, prefixes: '86'})
CreditCardValidations.add_brand(:en_route, {length: 15, prefixes: ['2014', '2149']}, {skip_luhn: true}) #skip luhn
CreditCardValidations.add_brand(:laser, {length: 18, prefixes: ['6304', '6706', '6771']})

voyager_test_card_number = '869926275400212'
CreditCardValidations::Detector.new(voyager_test_card_number).brand #:voyager
CreditCardValidations::Detector.new(voyager_test_card_number).voyager? #true

en_route_test_card_number = '2014-0000-0000-001'
CreditCardValidations::Detector.new(en_route_test_card_number).brand #:en_route
CreditCardValidations::Detector.new(en_route_test_card_number).en_route? #true

laser_test_card_number = '6304 9506 0000 0000 00'
CreditCardValidations.delete_brand(:maestro) # Maestro is crossing Laser range
CreditCardValidations::Detector.new(laser_test_card_number).brand #:laser
CreditCardValidations::Detector.new(laser_test_card_number).laser? #true
```

Remove brands also supported
### Remove brands also supported

```ruby
CreditCardValidations.delete_brand(:maestro)
```



Check luhn
### Check luhn

```ruby
CreditCardValidations::Detector.new(@credit_card_number).valid_luhn?
#or
CreditCardValidations::Luhn.valid?(@credit_card_number)
```

Generate credit card numbers that pass validation
### Generate credit card numbers that pass validation

```ruby
CreditCardValidations::Factory.random(:amex)
Expand All @@ -138,6 +133,15 @@ Generate credit card numbers that pass validation
# => "6010430241237266856"
```

### Plugins

```ruby
require 'credit_card_validations/plugins/en_route'
require 'credit_card_validations/plugins/laser'
require 'credit_card_validations/plugins/diners_us'

```

## Contributing

1. Fork it
Expand Down
1 change: 1 addition & 0 deletions lib/credit_card_validations.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
require 'credit_card_validations/version'
require 'credit_card_validations/error'
require 'active_model'
require 'active_support/core_ext'
require 'active_model/validations'
Expand Down
7 changes: 1 addition & 6 deletions lib/credit_card_validations/detector.rb
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,6 @@ def brand_name(brand_key)
else
nil
end

end

def brand_key(brand_name)
Expand All @@ -120,7 +119,7 @@ def delete_brand(key)
#create rule for detecting brand
def add_rule(key, length, prefixes)
unless brands.has_key?(key)
raise RuntimeError.new("brand #{key} is undefined, please use #add_brand method")
raise CreditCardValidations::Error.new("brand #{key} is undefined, please use #add_brand method")
end
length, prefixes = Array(length), Array(prefixes)
brands[key][:rules] << {length: length, regexp: compile_regexp(prefixes), prefixes: prefixes}
Expand All @@ -139,14 +138,10 @@ def undef_brand_method(key)
undef_method "#{key}?".to_sym if method_defined? "#{key}?".to_sym
end


#create regexp by array of prefixes
def compile_regexp(prefixes)
Regexp.new("^((#{prefixes.join(")|(")}))")
end

end

end

end
4 changes: 4 additions & 0 deletions lib/credit_card_validations/error.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
module CreditCardValidations
class Error < StandardError
end
end
8 changes: 3 additions & 5 deletions lib/credit_card_validations/factory.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,11 @@ module CreditCardValidations
class Factory
class << self
def random(brand = nil)
if brand.nil?
brand = Detector.brands.keys.sample
else
raise RuntimeError.new("Unsupported brand") if Detector.brands[brand].nil?
brand = Detector.brands.keys.sample if brand.nil?
if Detector.brands[brand].nil?
raise CreditCardValidations::Error.new('Unsupported brand')
end
generate(Detector.brands[brand][:rules].sample)

end

def generate(rule)
Expand Down
5 changes: 5 additions & 0 deletions lib/credit_card_validations/plugins/diners_us.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
CreditCardValidations.add_brand(
:diners_us,
{ length: 16, prefixes: %w(54 55) },
{ brand_name: 'Diners Club US' }
)
5 changes: 5 additions & 0 deletions lib/credit_card_validations/plugins/en_route.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
CreditCardValidations.add_brand(
:en_route,
{ length: 15, prefixes: %w(2014 2149) },
{ skip_luhn: true }
)
4 changes: 4 additions & 0 deletions lib/credit_card_validations/plugins/laser.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
CreditCardValidations.add_brand(
:laser,
length: [16, 17, 18, 19], prefixes: %w(6304 6706 6771)
)
2 changes: 1 addition & 1 deletion lib/credit_card_validations/version.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
module CreditCardValidations
VERSION = "2.0.3"
VERSION = "3.0.0"
end
9 changes: 0 additions & 9 deletions lib/data/brands.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -42,15 +42,6 @@
- '38'
:options:
:brand_name: Diners Club
:diners_us:
:rules:
- :length:
- 16
:prefixes:
- '54'
- '55'
:options:
:brand_name: Diners Club US
:discover:
:rules:
- :length:
Expand Down
8 changes: 8 additions & 0 deletions lib/plugins/diners_us.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# :diners_us:
# :rules:
# - :length:
# - 16
# :prefixes:
# - '54'
# - '55'
CreditCardValidations.add_brand(:diners_us, {length: 16, prefixes: %w(54 55)}, {brand_name: 'Diners Club US'})
1 change: 1 addition & 0 deletions lib/plugins/en_route.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
CreditCardValidations.add_brand(:en_route, {length: 15, prefixes: %w(2014 2149)}, {skip_luhn: true})
12 changes: 12 additions & 0 deletions lib/plugins/laser.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# :laser:
# :rules:
# - :length:
# - 16
# - 17
# - 18
# - 19
# :prefixes:
# - '6304'
# - '6706'
# - '6771'
CreditCardValidations.add_brand(:laser, {length: [16, 17, 18, 19], prefixes: %w(6304 6706 6771)})
70 changes: 39 additions & 31 deletions spec/credit_card_validations_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -67,9 +67,9 @@
end

it "should detect by full brand name" do
amex = CreditCardValidations::Factory.random(:amex)
amex = CreditCardValidations::Factory.random(:amex)
detector(amex).valid?('American Express').must_equal true
visa = CreditCardValidations::Factory.random(:visa)
visa = CreditCardValidations::Factory.random(:visa)
detector(visa).valid?('American Express').must_equal false
end

Expand Down Expand Up @@ -105,53 +105,62 @@

describe "adding/removing brand" do

describe "adding rules" do

let(:voyager_number) {
'869926275400212'
}

it "should validate number as voyager" do
CreditCardValidations::Detector.add_brand(:voyager, {length: 15, prefixes: '86'})
detector(voyager_number).valid?(:voyager).must_equal true
detector(voyager_number).voyager?.must_equal true
detector(voyager_number).brand.must_equal :voyager
end


describe "Add voyager rule" do
before do
CreditCardValidations::Detector.add_brand(:voyager, {length: 15, prefixes: '86'})
end
let(:voyager_number) { '869926275400212' }

it "should validate number as voyager" do

CreditCardValidations::Detector.add_brand(:voyager, length: 15, prefixes: '86')
detector(voyager_number).valid?(:voyager).must_equal true
detector(voyager_number).voyager?.must_equal true
detector(voyager_number).brand.must_equal :voyager

end

describe "Remove voyager rule" do
describe "Add voyager rule" do
before do
CreditCardValidations::Detector.delete_brand(:voyager)
CreditCardValidations::Detector.add_brand(:voyager, length: 15, prefixes: '86')
end

it "should not validate number as voyager" do
detector(voyager_number).respond_to?(:voyager?).must_equal false
detector(voyager_number).brand.must_be_nil
it "should validate number as voyager" do
detector(voyager_number).valid?(:voyager).must_equal true
detector(voyager_number).voyager?.must_equal true
detector(voyager_number).brand.must_equal :voyager
end
end

end
describe "Remove voyager rule" do
before do
CreditCardValidations::Detector.delete_brand(:voyager)
end

it "should not validate number as voyager" do
detector(voyager_number).respond_to?(:voyager?).must_equal false
detector(voyager_number).brand.must_be_nil
end
end
end
end

it "should raise RuntimeError" do
proc { CreditCardValidations::Detector::add_rule(:undefined_brand, 20, [20]) }.must_raise RuntimeError
describe "plugins" do

[:diners_us, :en_route, :laser].each do |brand|
it "should support #{brand}" do
-> { CreditCardValidations::Factory.random(brand) }.
must_raise(CreditCardValidations::Error)
detector('somenumber').respond_to?("#{brand}?").must_equal false
require "credit_card_validations/plugins/#{brand}"
number = CreditCardValidations::Factory.random(brand)
CreditCardValidations::Detector.new(number).valid?("#{brand}".to_sym).must_equal true
detector('somenumber').respond_to?("#{brand}?").must_equal true
end
end
end

it "should raise Error if no brand added before" do
-> { CreditCardValidations::Detector::add_rule(:undefined_brand, 20, [20]) }.
must_raise(CreditCardValidations::Error)
end
end


def luhn_valid?(number)
CreditCardValidations::Luhn.valid?(number)
end
Expand All @@ -160,7 +169,6 @@ def detector(number)
CreditCardValidations::Detector.new(number)
end


def has_luhn_check_rule?(key)
CreditCardValidations::Detector.has_luhn_check_rule?(key)
end
Expand Down
Loading

0 comments on commit 879af0c

Please sign in to comment.