Forum: Ruby [QUIZ] Checking Credit Cards (#122)

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
Brian Krahmer (Guest)
on 2007-05-02 02:21
(Received via mailing list)
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
This topic is locked and can not be replied to.