From: Alex Wayne <alex@beautifulpixel.com>
Date: May 1, 2007 8:08:59 PM CDT
To: submission@rubyquiz.com
Subject: Please Forward: Ruby Quiz SubmissionA simple approach. It has 2 classes. One class parses the card number, the other provides a command line interface to the first class. The harder part (the Luhn calculation) is heavily commented for clarity.
For brevity on the command line, I named the program ccinfo.rb. The long winded "cc_validator_class.rb" is for the library that does allthe heavily lifting but is not called directly. To use it stick both files in a directory and type:
ruby ccinfo.rb 4111111111111111
Thanks for the quizzes!
-Alex Wayne
http://beautifulpixel.com
class CCValidatorattr_reader :number, :card_type
def initialize(number)
@number = number.to_s
@card_type = parse_type(number)
@valid = parse_valid(number)
enddef valid?
@valid
endprivate
# A simple Regex case statement returns the card type
def parse_type(number)
case number
when /^3(4|7)\d{13}$/
:amex
when /^6011\d{12}$/
:discover
when /^5[1-5]\d{14}$/
:mastercard
when /^4(\d{12}|\d{15})$/
:visa
else
:unknown
end
end# Calculate number validity
def parse_valid(number)
# Rather than starting to double on the second to last number, we decide wether or
# not we can start on the first number by how many digits the number has. If it's
# even the first number gets double and then every other number after. If it's odd
# start double on the second digit, thereby "offset"-ing the progression.
offset = (number.size % 2 == 0) ? 0 : 1# covert number string to an array of integer digits.
digits = number.split('').collect { |digit| digit.to_i }# Iterate through the digit array, double every other digit. Each is not used here
# because we need to keep track of the index and stuff the result back in the original
# array.
digits.size.times do |i|
if (i + offset) % 2 == 0
digits[i] = digits[i] * 2
end
end# convert array with doubled integer digits, into strings. Then split all elements
# back into single digits.
digits = digits.collect { |digit| digit.to_s.split('') }# Flatten the potentialilly nested arrays and convert all digits back to integers for
# addition.
digits = digits.flatten.collect { |digit| digit.to_i }# Add up the digits and see if the result is a multiple of 10, proving that the card
# number is valid.
digits.inject(0) { |sum, digit| sum + digit } % 10 == 0
endend
require "cc_validator_class"class CCValidator
class CommandLine
def initialize
if @number = ARGV.shift
write_output
else
write_usage
end
enddef write_output
result = CCValidator.new(@number)
puts <<-OUTPUTCredit Card Validator
Card Number: #{result.number}
Type: #{result.card_type.to_s.capitalize}
Valid: #{result.valid? ? 'YES' : 'NO'}OUTPUT
enddef write_usage
puts <<-USAGECredit Card Validator
This program will tell the type of credit card and if the number is valid. To use, simply
provide a credit card number on the command line, and the results will be immediately
displayed.EXAMPLE:
ruby ccinfo.rb 4111111111111111USAGE
end
end
endCCValidator::CommandLine.new
ยทยทยท
Begin forwarded message: