From: Brian Krahmer Date: 2007-05-02T07:20:46+09:00 Subject: [SOLUTION] [QUIZ] Checking Credit Cards (#122) Here is my submission. My first version was a bit shorter and more concise, where I had embedded the allowed lengths into the regex. I already had it written before the topic of 12 digits starting with 4 came up. So, upon James' first decision to call that an invalid Visa, I refactored and left it that way. cheers, brian if ARGV.size == 0 puts "You must supply a credit card number to be checked." abort end input = ARGV.join class CardCompany class << self def is_issuer_of?(data) data =~ self::ValidRegex end def valid_card?(data) return false if invalid_length?(data) reversed = data.reverse sum = 0 1.step(reversed.length - 1, 2) do |i| digit = reversed[i..i].to_i if digit < 5 sum += digit * 2 else sum += ((digit * 2) % 10) + 1 end end 0.step(reversed.length - 1, 2) do |i| sum += reversed[i..i].to_i end sum % 10 == 0 end def invalid_length?(data) return false if self::ValidLengths.empty? for length in self::ValidLengths return false if data.size == length end true end end end class AmexCardCo < CardCompany ValidRegex = /^3[47]\d+$/ ValidLengths = [15] Name = 'AMEX' end class DiscoCardCo < CardCompany ValidRegex = /^6011\d+$/ ValidLengths = [16] Name = 'Discover' end class MasterCardCo < CardCompany ValidRegex = /^5[1-5]\d+$/ ValidLengths = [16] Name = 'MasterCard' end class VisaCardCo < CardCompany ValidRegex = /^4\d+$/ ValidLengths = [13, 16] Name = 'Visa' end class UnknownCardCo < CardCompany ValidRegex = /^\d+$/ ValidLengths = [] Name = 'Unknown' end SYSTEMS = [ AmexCardCo, DiscoCardCo, MasterCardCo, VisaCardCo, UnknownCardCo ] for system in SYSTEMS if system.is_issuer_of?(input) found = true valid = system.valid_card?(input) puts "#{system::Name} #{valid ? 'Valid' : 'Invalid'}" break end end puts "Invalid input" if !found