Forum: Ruby 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.
Fd1925c8356bb0ece18731063b25141d?d=identicon&s=25 Ruy Díaz Jara (Guest)
on 2007-04-29 20:05
(Received via mailing list)
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
81d609425e306219d54d793a0ad98bce?d=identicon&s=25 Matthew Moss (Guest)
on 2007-04-30 22:08
(Received via mailing list)
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
This topic is locked and can not be replied to.