luhnacy 0.1.0 → 0.2.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 +38 -0
- data/VERSION +1 -1
- data/lib/luhnacy.rb +42 -2
- data/luhnacy.gemspec +55 -0
- data/spec/luhnacy_spec.rb +47 -0
- metadata +5 -4
data/README.rdoc
CHANGED
@@ -8,6 +8,8 @@ To require:
|
|
8
8
|
|
9
9
|
require 'luhnacy'
|
10
10
|
|
11
|
+
=== Generic Validation\Generation
|
12
|
+
|
11
13
|
To validate:
|
12
14
|
|
13
15
|
Luhnacy.valid?('49927398716')
|
@@ -20,6 +22,40 @@ To generate a string of 10 digits that does not satisfy Luhn algorithm:
|
|
20
22
|
|
21
23
|
invalid_string = Luhnacy.generate(10, :invalid => true)
|
22
24
|
|
25
|
+
To generate a string of 10 digits that satisfies Luhn and starts with predefined characters:
|
26
|
+
|
27
|
+
Luhnacy.generate(10, :prefix => '12345') #=> "1234597480"
|
28
|
+
|
29
|
+
=== Named Generators/Validators
|
30
|
+
|
31
|
+
There are named validators and generators for Visa, Mastercard and American Express credit cards. Note: Visa validation/generation only works for 16-digit credit card numbers.
|
32
|
+
|
33
|
+
Example usage (mastercard)
|
34
|
+
|
35
|
+
To validate a mastercard:
|
36
|
+
|
37
|
+
Luhnacy.mastercard?("5176290135048779")
|
38
|
+
|
39
|
+
To generate a mastercard number that satisfies Luhn:
|
40
|
+
|
41
|
+
Luhnacy.mastercard #=> "5151199732615386"
|
42
|
+
|
43
|
+
To generate a master card number that does not satisfy Luhn:
|
44
|
+
|
45
|
+
Luhnacy.mastercard(:invalid => true)
|
46
|
+
|
47
|
+
Similar usage exists for Visa and American Express:
|
48
|
+
|
49
|
+
Luhnacy.visa
|
50
|
+
Luhnacy.visa?
|
51
|
+
|
52
|
+
Luhnacy.amex
|
53
|
+
Luhnacy.amex?
|
54
|
+
|
55
|
+
== Planned changes
|
56
|
+
|
57
|
+
At some point it may make sense to store the patterns for the named generator in a seperate class/module or even in a YAML file. This will be driven by the need for additional named generators. If a YAML file is used, then the very next release may also include the ability to pass Luhnacy a custom YAML file for generating/validating strings.
|
58
|
+
|
23
59
|
== Note on Patches/Pull Requests
|
24
60
|
|
25
61
|
* Fork the project.
|
@@ -35,6 +71,8 @@ To generate a string of 10 digits that does not satisfy Luhn algorithm:
|
|
35
71
|
* http://blog.flame.org/2008/3/24/checking-credit-card-numbers-in-ruby
|
36
72
|
* http://www.missiondata.com/blog/web-development/25/credit-card-type-and-luhn-check-in-ruby/
|
37
73
|
* http://en.wikipedia.org/wiki/Luhn
|
74
|
+
* http://www.darkcoding.net/credit-card-numbers/
|
75
|
+
* http://en.wikipedia.org/wiki/Credit_card_number
|
38
76
|
|
39
77
|
== Copyright
|
40
78
|
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.2.0
|
data/lib/luhnacy.rb
CHANGED
@@ -1,11 +1,18 @@
|
|
1
1
|
class Luhnacy
|
2
|
+
@cards = {
|
3
|
+
:mastercard => { :prefixes => [ '51', '52', '53', '54', '55' ], :size => 16 },
|
4
|
+
:visa => { :prefixes => ['4'], :size => 16 },
|
5
|
+
:amex => { :prefixes => ['34','37'], :size => 15 }
|
6
|
+
}
|
2
7
|
def self.valid?(candidate)
|
3
8
|
calc_modulus(candidate) == 0
|
4
9
|
end
|
5
10
|
|
6
11
|
def self.generate(string_size, options={})
|
7
|
-
|
8
|
-
|
12
|
+
raise ArgumentError, "prefix must be numeric" if options[:prefix] && !(options[:prefix] =~ /^\d*$/)
|
13
|
+
|
14
|
+
output = options[:prefix] || ''
|
15
|
+
(string_size-output.size-1).times do |n|
|
9
16
|
output += rand(10).to_s
|
10
17
|
end
|
11
18
|
output += '0'
|
@@ -28,6 +35,14 @@ class Luhnacy
|
|
28
35
|
output
|
29
36
|
end
|
30
37
|
|
38
|
+
def self.method_missing(type, *args)
|
39
|
+
card_type, method_type = parse_method_name(type)
|
40
|
+
|
41
|
+
raise NoMethodError unless @cards[card_type] && @cards[card_type][:prefixes] && @cards[card_type][:size]
|
42
|
+
|
43
|
+
send(method_type, *(args.unshift(card_type)))
|
44
|
+
end
|
45
|
+
|
31
46
|
private
|
32
47
|
def self.double_and_fix(number)
|
33
48
|
2 * number > 9 ? ( (2 * number) % 10 + 1 ) : 2 * number
|
@@ -46,4 +61,29 @@ class Luhnacy
|
|
46
61
|
|
47
62
|
sum % 10
|
48
63
|
end
|
64
|
+
|
65
|
+
def self.parse_method_name(method_name)
|
66
|
+
method_name = method_name.to_s
|
67
|
+
case method_name
|
68
|
+
when /(.*)\?$/
|
69
|
+
[ $~[1].to_sym, :valid_card? ]
|
70
|
+
else
|
71
|
+
[ method_name.to_sym, :generate_card ]
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def self.valid_card?(card_type, card_number)
|
76
|
+
valid?(card_number) && valid_pattern?(card_type, card_number)
|
77
|
+
end
|
78
|
+
|
79
|
+
def self.generate_card(card_type, options={})
|
80
|
+
generate(@cards[card_type][:size], options.merge({:prefix => @cards[card_type][:prefixes][rand(@cards[card_type][:prefixes].size)]}))
|
81
|
+
end
|
82
|
+
|
83
|
+
def self.valid_pattern?(card_type, card_number)
|
84
|
+
@cards[card_type][:prefixes].each do |prefix|
|
85
|
+
return true if card_number =~ /^#{prefix}\d{#{@cards[card_type][:size] - prefix.size}}$/
|
86
|
+
end
|
87
|
+
false
|
88
|
+
end
|
49
89
|
end
|
data/luhnacy.gemspec
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = %q{luhnacy}
|
8
|
+
s.version = "0.2.0"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = ["Rory McKinley"]
|
12
|
+
s.date = %q{2010-08-07}
|
13
|
+
s.description = %q{luhnacy can be used to validate strings for Luhn compliance as well as generating valid or invalid strings for the purposes of testing }
|
14
|
+
s.email = %q{rorymckinley@gmail.com}
|
15
|
+
s.extra_rdoc_files = [
|
16
|
+
"LICENSE",
|
17
|
+
"README.rdoc"
|
18
|
+
]
|
19
|
+
s.files = [
|
20
|
+
".document",
|
21
|
+
".gitignore",
|
22
|
+
"LICENSE",
|
23
|
+
"README.rdoc",
|
24
|
+
"Rakefile",
|
25
|
+
"VERSION",
|
26
|
+
"lib/luhnacy.rb",
|
27
|
+
"luhnacy.gemspec",
|
28
|
+
"spec/luhnacy_spec.rb",
|
29
|
+
"spec/spec.opts",
|
30
|
+
"spec/spec_helper.rb"
|
31
|
+
]
|
32
|
+
s.homepage = %q{http://github.com/rorymckinley/luhnacy}
|
33
|
+
s.rdoc_options = ["--charset=UTF-8"]
|
34
|
+
s.require_paths = ["lib"]
|
35
|
+
s.rubygems_version = %q{1.3.7}
|
36
|
+
s.summary = %q{A gem tohelp with the tedium of validating Luhn-compliant strings}
|
37
|
+
s.test_files = [
|
38
|
+
"spec/luhnacy_spec.rb",
|
39
|
+
"spec/spec_helper.rb"
|
40
|
+
]
|
41
|
+
|
42
|
+
if s.respond_to? :specification_version then
|
43
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
44
|
+
s.specification_version = 3
|
45
|
+
|
46
|
+
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
47
|
+
s.add_development_dependency(%q<rspec>, [">= 1.2.9"])
|
48
|
+
else
|
49
|
+
s.add_dependency(%q<rspec>, [">= 1.2.9"])
|
50
|
+
end
|
51
|
+
else
|
52
|
+
s.add_dependency(%q<rspec>, [">= 1.2.9"])
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
data/spec/luhnacy_spec.rb
CHANGED
@@ -23,4 +23,51 @@ describe "Luhnacy" do
|
|
23
23
|
candidate = Luhnacy.generate(string_size, :invalid => true)
|
24
24
|
Luhnacy.valid?(candidate).should be_false
|
25
25
|
end
|
26
|
+
|
27
|
+
it "should return a string that satisfies luhn and includes a given prefix" do
|
28
|
+
prefix = '12345'
|
29
|
+
string_size = 15
|
30
|
+
candidate = Luhnacy.generate(string_size, :prefix => prefix)
|
31
|
+
candidate.should match /^#{prefix}\d{#{string_size - prefix.size}}$/
|
32
|
+
end
|
33
|
+
|
34
|
+
it "should return an error if the prefix contains any non-numeric characters" do
|
35
|
+
prefix = 'AB123'
|
36
|
+
string_size = 15
|
37
|
+
lambda { Luhnacy.generate(string_size, :prefix => prefix) }.should raise_error ArgumentError
|
38
|
+
end
|
39
|
+
|
40
|
+
context "Named generators and validators" do
|
41
|
+
it "should validate a correct number" do
|
42
|
+
number = '5354334446769063'
|
43
|
+
Luhnacy.mastercard?(number).should be_true
|
44
|
+
end
|
45
|
+
|
46
|
+
it "should not validate a number if it does not satisfy Luhn" do
|
47
|
+
number = '5354334446769064'
|
48
|
+
Luhnacy.mastercard?(number).should be_false
|
49
|
+
end
|
50
|
+
|
51
|
+
it "should not validate a number if it does not have the correct prefix" do
|
52
|
+
number = Luhnacy.generate(16, :prefix => '49')
|
53
|
+
Luhnacy.mastercard?(number).should be_false
|
54
|
+
end
|
55
|
+
|
56
|
+
it "should not validate a number if it does not have the correct length" do
|
57
|
+
number = Luhnacy.generate(12, :prefix => '52')
|
58
|
+
Luhnacy.mastercard?(number).should be_false
|
59
|
+
end
|
60
|
+
|
61
|
+
it "should generate a valid number" do
|
62
|
+
Luhnacy.mastercard?(Luhnacy.mastercard).should be_true
|
63
|
+
end
|
64
|
+
|
65
|
+
it "should generate an invalid number" do
|
66
|
+
Luhnacy.mastercard?(Luhnacy.mastercard(:invalid => true)).should be_false
|
67
|
+
end
|
68
|
+
|
69
|
+
it "should raise an error if there is no matcher or validator with a given name" do
|
70
|
+
lambda { Luhnacy.superawesomecard?('123') }.should raise_error NoMethodError
|
71
|
+
end
|
72
|
+
end
|
26
73
|
end
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: luhnacy
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 23
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 0
|
8
|
-
-
|
8
|
+
- 2
|
9
9
|
- 0
|
10
|
-
version: 0.
|
10
|
+
version: 0.2.0
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Rory McKinley
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2010-07
|
18
|
+
date: 2010-08-07 00:00:00 +02:00
|
19
19
|
default_executable:
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|
@@ -51,6 +51,7 @@ files:
|
|
51
51
|
- Rakefile
|
52
52
|
- VERSION
|
53
53
|
- lib/luhnacy.rb
|
54
|
+
- luhnacy.gemspec
|
54
55
|
- spec/luhnacy_spec.rb
|
55
56
|
- spec/spec.opts
|
56
57
|
- spec/spec_helper.rb
|