Checking Credit Cards (#122)

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

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