# Checking Credit Cards (#122)

**URL:** <https://www.ruby-forum.com/t/checking-credit-cards-122/93233>\
**Category:** Ruby\
**Created:** [April 29, 2007, 8:05pm UTC](https://www.ruby-forum.com/t/checking-credit-cards-122/93233 "2007-04-29T20:05:21Z")\
**Posts on this page:** 2\
**Page:** 1

<div class="post-metadata">

**Author:** ![Ruy\_DSSS\_az\_Jara](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/r/c89c15/32.png) [@Ruy\_DSSS\_az\_Jara](https://www.ruby-forum.com/u/Ruy_DSSS_az_Jara)\
**Post date:** [April 29, 2007, 8:05pm UTC](https://www.ruby-forum.com/t/checking-credit-cards-122/93233/1 "2007-04-29T20:05:21Z")

</div>

Hi everyone, like most of the other quiz solvers, I am also new to Ruby  
and  
the mailing list. This is my second Ruby program, so I am eagerly  
awaiting  
any comments on improvements, flaws, etc. Without further ado, my code:

* * *

@card\_types = [  
[“Mastercard”,/^5[1-5]\d{14}$/],  
[“Visa”,/^4(\d{12}|\d{15})$/],  
[“Discover”,/^6011\d{12}$/],  
[“AMEX”,/^3[47]\d{13}$/],  
[“Unknown”,/^\d\*$/]  
]

def card\_type( card\_number )  
card\_number.gsub!( /\s/, ‘’)  
@card\_types.each do |card\_type|  
return card\_type[0] if card\_type[1] =~ card\_number  
end  
raise “Invalid characters in input”  
end

def luhn( card\_number )  
sum = 0  
card\_number.length.downto( 1 ) do |i|  
doubled = ( i%2 + 1 ) \* ( card\_number[i-1, 1].to\_i )  
if doubled \>= 10  
doubled = (doubled % 10 ) + 1  
end  
sum += doubled  
end  
sum % 10 == 0  
end

def validate( card\_number )  
return card\_type( card\_number ), luhn( card\_number )  
end

p validate( ARGV.join.gsub( /\s/, ‘’) )

* * *

Ruy

---

<div class="post-metadata">

**Author:** ![Ruy\_DSSS\_az\_Jara](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/r/c89c15/32.png) [@Ruy\_DSSS\_az\_Jara](https://www.ruby-forum.com/u/Ruy_DSSS_az_Jara)\
**Post date:** [April 30, 2007, 10:08pm UTC](https://www.ruby-forum.com/t/checking-credit-cards-122/93233/2 "2007-04-30T22:08:49Z")

</div>

Here is my version… Note that it is probably incorrect w.r.t. the  
valid/invalid and known/unknown issue discussed earlier… However,  
after finishing my initial version, and despite how easy it would be  
to fix, I am pretty swamped with other tasks and so won’t fix it.

class Integer  
def digitSum  
self.to\_s.split(//).inject(0) { |s, d| s + d.to\_i }  
end  
end

class CreditCard

TYPE\_MATCH = {  
:visa =\> /^4/,  
:discover =\> /^6011/,  
:amex =\> /^3(4|7)/,  
:mastercard =\> /^5[1-5]/  
}

SIZE\_MATCH = {  
:visa =\> [13, 16],  
:discover =\> [16],  
:amex =\> [15],  
:mastercard =\> [16]  
}

CARD\_NAME = {  
:visa =\> “Visa”,  
:discover =\> “Discover”,  
:amex =\> “American Express”,  
:mastercard =\> “MasterCard”,  
:unknown =\> “unknown”,  
nil =\> “invalid”  
}

def initialize(cc)  
@cc = cc.delete(" ")  
end

def valid?  
self.type && (self.\_luhn % 10).zero?  
end

def type  
TYPE\_MATCH.each do |k, v|  
if @cc =~ v  
if SIZE\_MATCH[k].find { |n| @cc.size == n }  
return k  
else  
return nil  
end  
end  
end  
:unknown  
end

def name  
CARD\_NAME[self.type]  
end

def to\_s  
@cc  
end

def \_luhn  
sum = 0  
cc = @cc.split(//)  
until cc.empty?  
a, b = cc.pop.to\_i, cc.pop.to\_i  
sum += a + (2 \* b).digitSum  
end  
sum  
end  
end

cc = CreditCard.new(ARGV.join)  
if !cc.valid?  
puts “Card #{cc} is invalid.”  
elsif cc.type != :unknown  
puts “Card #{cc} is a valid #{cc.name}.”  
else  
puts “Card #{cc} is unknown type, may be valid.”  
end
