Begin forwarded message:

> From: Kai WeingçÓtner <KaiWeing / gmx.net>
> Date: May 5, 2007 7:48:53 AM CDT
> To: submission / rubyquiz.com
> Subject: Please Forward: Ruby Quiz Submission (please update)
>
>
> Hello,
>
> I first sent you my solution as a tar attachement. This version is  
> plain text and much easier to read ;-)
> Could you please replace my solution?
>
> Thank You!
>
> Kai WeingçÓtner
>
> The card check implementation:
>
> class CardCheck
>   attr_reader :number
>
>   @@types = {
>     'AMEX' => {:starts_with => [34, 37], :length => [15]},
>     'Discover' => {:starts_with => [6011], :length => [16]},
>     'MasterCard' => {:starts_with => (51..55), :length => [16]},
>     'Visa' => {:starts_with => [4], :length => [13, 16]}
>   }
>
>   def initialize(num)
>     @number = num.to_s
>   end
>
>   def type
>     @@types.each do |card_name, type_checks|
>       starts_with = type_checks[:starts_with]
>       lengths = type_checks[:length]
>       fits_length = lengths.any? {|length| @number.length == length}
>       fits_start = starts_with.any? {|start| @number.match('^' +  
> start.to_s)}
>       return card_name if (fits_length and fits_start)
>     end
>     return 'Unknown'
>   end
>
>   def calc_luhn
>     elements = []
>     @number.reverse.split(//).each_with_index do |digit, index|
>       if (index.even?)
>         elements << digit
>       else
>         elements << (digit.to_i * 2).to_s.split(//)
>       end
>     end
>     return elements.flatten.sum
>   end
>
>   def is_valid?
>     return (calc_luhn % 10) == 0
>   end
>
>   private :calc_luhn
> end
>
> class Integer
>   def even?
>     (to_i % 2) == 0
>   end
> end
>
> module Enumerable
>   def to_i
>     collect {|x| x.to_i}
>   end
>
>   def sum
>     to_i.inject {|sum, x| sum + x}
>   end
>
> The command line interpreter
>
> require 'card_check'
>
> unless ARGV[0]
>   print <<-USAGE
>     Checks card vendor and validity
>     Usage: provide the card number
>     USAGE
>     exit
> end
>
> card = CardCheck.new(ARGV[0])
> puts "Card type: #{card.type}\n"
> puts "Number valid? #{card.is_valid?}\n"
>
> some tests...
>
> require 'card_check'
> require 'test/unit'
> class TestCardCheck < Test::Unit::TestCase
>   def test_validity
>     assert_equal(true, CardCheck.new("4408041234567893").is_valid?)
>     assert_equal(false, CardCheck.new("4417123456789112").is_valid?)
>   end
>
>   def test_type
>     assert_equal('Visa', CardCheck.new("4408041234567893").type)
>     assert_equal('AMEX', CardCheck.new("340804123456789").type)
>     assert_equal('Discover', CardCheck.new("6011440804123456").type)
>     assert_equal('MasterCard', CardCheck.new("5308041234567893").type)
>     assert_equal('Visa', CardCheck.new("4408041234567").type)
>     assert_equal('Unknown', CardCheck.new("9408041234567893").type)
>   end
> end
>