From: Raj Sahae on
My second ever rubyquiz submission, so be nice.
Sorry if the submission is a little early (by about an hour and a half),
but I won't be around a comp tomorrow.

Raj Sahae

# ccc.rb
# Checking Credit Cards
# By Raj Sahae

class String
def begins_with?(str)
temp = self.slice(0...str.length)
temp == str
end
end

class Array
def collect_with_index
self.each_with_index do |x, i|
self[i] = yield(x, i)
end
end
end

class CCNumber
#This data was taken from http://en.wikipedia.org/wiki/Credit_card_number
TYPES = [
Hash['type' => 'American Express', 'key' => [34,
37], 'length' => [15]],
Hash['type' => 'China Union Pay', 'key' =>
(622126..622925).to_a, 'length' => [16]],
Hash['type' => 'Diners Club Carte Blanche', 'key' =>
(300..305).to_a, 'length' => [14]],
Hash['type' => 'Diners Club International', 'key' =>
[36], 'length' => [14]],
Hash['type' => 'Diners Club US & Canada', 'key' =>
[55], 'length' => [16]],
Hash['type' => 'Discover', 'key' =>
[6011, 65], 'length' => [16]],
Hash['type' => 'JCB', 'key' =>
[35], 'length' => [16]],
Hash['type' => 'JCB', 'key' =>
[1800, 2131], 'length' => [15]],
Hash['type' => 'Maestro', 'key' =>
[5020, 5038, 6759], 'length' => [16]],
Hash['type' => 'MasterCard', 'key' =>
(51..55).to_a, 'length' => [16]],
Hash['type' => 'Solo', 'key' =>
[6334, 6767], 'length' => [16, 18, 19]],
Hash['type' => 'Switch', 'key' =>
[4903, 4905, 4911, 4936, 564182, 633110, 6333, 6759],

'length' => [16, 18, 19]],
Hash['type' => 'Visa', 'key' =>
[4], 'length' => [13, 16]],
Hash['type' => 'Visa Electron', 'key' => [417500,
4917, 4913], 'length' => [16]]
]

#number should be an array of numbers as strings e.g. ["1", "2", "3"]
def initialize(array)
@number = array.collect{|num| num.to_i}
end

def type
TYPES.each do |company|
company['key'].each do |key|
if company['length'].include?(@number.length) and
@number.join.begins_with?(key.to_s)
return company['type']
end
end
end
"Unknown"
end

def valid?
temp = @number.reverse.collect_with_index{|num, index| index%2 == 0
? num*2 : num}
sum = temp.collect{|num|num > 9 ? [1, num%10] :
num}.flatten.inject{|s, n| s+n}
sum%10 == 0
end

def process
puts "The card type is #{self.type}"
puts "The card number is #{self.valid? ? 'valid' : 'invalid'}"
end
end

if $0 == __FILE__
abort "You must enter a number!" if ARGV.empty?
CCNumber.new(ARGV.join.strip.split(//)).process
end


From: anansi on
Raj Sahae wrote:
> My second ever rubyquiz submission, so be nice.
> Sorry if the submission is a little early (by about an hour and a half),
> but I won't be around a comp tomorrow.
>
> Raj Sahae
>

I'll wait with my solution for a further hour ;) but a comment to your
solution:
try out: ruby ccc.rb 5508 0412 3456 7893
it should show: Diners Club US & Canada or Mastercard
but shows just Mastercaards

--
greets
(
)
(
/\ .-"""-. /\
//\\/ ,,, \//\\
|/\| ,;;;;;, |/\|
//\\\;-"""-;///\\
// \/ . \/ \\
(| ,-_| \ | / |_-, |)
//`__\.-.-./__`\\
// /.-(() ())-.\ \\
(\ |) '---' (| /)
` (| |) `
jgs \) (/


one must still have chaos in oneself to be able to give birth to a
dancing star
From: anansi on
48 hours are past so here is my first solution. I'm just coding ruby for
a few days so any feedback is welcome :)

My script recognizes 12 different creditcard companys and of course says
if a card could belong to two different companys at the same time or if
it is unknown.

I think the companycheck part could be done better by calling check.call
from a loop but I couldn't figure out how to pass such an hash:

hash = Hash.new { |hash, key| hash[key] = [] }
raw_data = [ [1,"American Express"],[1,/^34|^37/], [1, "15"],
[2,"Diners CLub Blanche"],[2,/^30[0-5]/], [2, "14"],
[3,"Solo"],[3,/^6334|^6767/],[3,"16"],[3,"18"],[3,"19"]]
raw_data.each { |x,y| hash[x] << y }

to

check = lambda{|reg,c,*d| if number =~ reg: @company += " or " + c if
d.include?(number.length) end }

in a loop. Any idea how to do this?

here the solution:


#!/usr/bin/ruby -w
# validate.rb
######################################################
# validator for creditcard numbers #
# by anansi #
# 29/04/07 on comp.lang.rub #
# #
# [QUIZ] Checking Credit Cards (#122) #
######################################################
# recognizes: #
# American Express, #
# Diners CLub Blanche, #
# Diners CLub International, #
# Diners Club US & Canada, #
# Discover, #
# JCB, #
# Maestro (debit card), #
# Mastercard, #
# Solo, #
# Switch, #
# Visa, #
# Visa Electron #
######################################################

class CreditCard


def initialize(number)
number.scan(/\D/) { |x| # scans number for every not-digit symbol
puts x + " is no valid credit card
symbol.\nJust digits allowed!!"
exit
}
end



def companycheck(number)
@company= ""
# block check compares the length and sets the company value
check = lambda{|reg,c,*d| if number =~ reg: @company += " or " + c
if d.include?(number.length) end }
# adding a new bank is quite easy, just put a new check.call in with:
# check.call(regular expressions for the starting
bytes,"Company-name",length1,length2,...)
# I'm sure this can be done somehow better invoking check.call by a
loop
# but I couldn't figure out how to pass a array with dynamic
variable count into check.call
check.call( /^34|^37/ , "American Express" , 15 )
check.call( /^30[0-5]/ ,"Diners CLub Blanche",14)
check.call( /^36/ , "Diners CLub International",14)
check.call( /^55/ , "Diners Club US & Canada",16)
check.call( /^6011|^65/ , "Discover",16)
check.call( /^35/ , "JCB" , 16)
check.call( /^1800|^2131/ , "JCB" , 15)
check.call( /^5020|^5038|^6759/ , "Maestro (debit card)" , 16)
check.call( /^5[0-5]/ , "Mastercard" , 16)
check.call( /^6334|^6767/ , "Solo" , 16 , 18 , 19)
check.call( /^4903|^4905|^4911|^4936|^564182|^633110|^6333|^6759/ ,
"Switch" , 16 , 18 , 19)
check.call( /^4/ , "Visa" , 13 , 16)
check.call( /^417500|^4917|^4913/ , "Visa Electron" , 16)
if @company == ""
puts "Company : Unknown"
else
puts "Company : #{@company.slice(4..(a)company.length)}"
end
end



def crossfoot(digit)
digit = "%2d" % digit # converts
integer to string
if digit[0] == 32
digit = (digit[1].to_i) -48
else # if the doubled
digit has more than 2 digits
digit= (digit[0].to_i) + (digit[1].to_i) -96 # adds the single
digits and converts back to integer
end
end

def validation(number)
math = lambda { |dig| number[@count-dig]-48 } # block math converts
str to int of the current digit
@duplex = false
@count = number.length
@result = 0
for i in (1..(a)count)
if @duplex == false # for every first digit from the back
@result += math.call i # add to result
@duplex = true
else # for every second digit
from the back
@result += crossfoot((math.call i)*2) # mutl. digit with 2, do the
crossfoot and add to result
@duplex = false
end
end
@result.modulo(10)
end


end


#### begin

if ARGV.length == 0 # checks if argument is passed
puts "no input\nusage, e.g.: ruby validate.rb 4408 0412 3456 7893"
exit
end


number = ARGV.join('').gsub(" ","") # reads args and kills all
spaces and newlinefeed

my_creditcard = CreditCard.new(number) # checks if just digits are
inputed otherwise: abort.

my_creditcard.companycheck(number) # checks for known or unknown
company

if my_creditcard.validation(number) == 0 # checks validation with
luhn-algo
puts "Validation: successful"
else
puts "Validation: failure"
end

### eof




--
greets
(
)
(
/\ .-"""-. /\
//\\/ ,,, \//\\
|/\| ,;;;;;, |/\|
//\\\;-"""-;///\\
// \/ . \/ \\
(| ,-_| \ | / |_-, |)
//`__\.-.-./__`\\
// /.-(() ())-.\ \\
(\ |) '---' (| /)
` (| |) `
jgs \) (/


one must still have chaos in oneself to be able to give birth to a
dancing star
From: Harry on
On 4/27/07, Ruby Quiz <james(a)grayproductions.net> wrote:
>
> This week's Ruby Quiz is to write a program that accepts a credit card number as
> a command-line argument. The program should print the card's type (or Unknown)
> as well a Valid/Invalid indication of whether or not the card passes the Luhn
> algorithm.
>
>

Here is my solution.

######
# Check Starting numbers and length
def card_ok(str,info)
check = "UNKNOWN"
info.each do |t|
pref = t[0]
leng = t[1]
name = t[2]
pref.each do |x|
if x == str.slice(0...x.length)
leng.each do |y|
if y.to_i == str.length
check = name.dup
end
end
end
end
end
return check
end

# Check Luhn algorithm
def luhn(str)
luhn_hash = Hash.new("INVALID")
if str.length != 0
luhn_hash[0] = "VALID"
arr = str.split(//).reverse
arr2 = []
arr3 = []
(0...arr.length).each do |u|
arr2 << arr[u] if u %2 == 0
arr2 << (arr[u].to_i * 2).to_s if u %2 != 0
end

arr2.each do |r|
arr3 << r.split(//).inject(0) {|sum,i| sum + i.to_i}
end

val = arr3.inject(0) {|sum,i| sum + i} % 10
end
return luhn_hash[val]
end

# Card information
test = []
test << [["31","34"],["15"],"AMEX"]
test << [["6011"],["16"],"DISCOVER"]
test << [("51".."55").to_a,["16"],"MASTERCARD"]
test << [["4"],["13","16"],"VISA"]
#test << [("3528".."3589").to_a,["16"],"JCB"]
#test << [[("3000".."3029").to_a + ("3040".."3059").to_a +
#("3815".."3889").to_a + ["36","389"]].flatten!,["14"],"DINERS"]

# Main
str = ARGV.join
arr = []
arr << card_ok(str,test)
arr << luhn(str)
puts arr
######

Harry


--
http://www.kakueki.com/ruby/list.html
A Look into Japanese Ruby List in English

From: Joseph Seaton on
My solution (the second I've submitted, so please be nice :).
Suggestions welcome.

###
BCTYPES = {
[[34,37],[15]] => "AMEX",
[[6011],[16]] => "Discoverer",
[(51..57).to_a,16] => "MasterCard",
[[4],[13,16]] => "Visa"}

def ctype(num)
BCTYPES.each { |n,t| n[0].each { |s|
return t if num.grep(/^#{s}/).any? && n[1].include?(num.length)
} }
"Unknown"
end

def luhncheck(num)
e = false
num.split(//).reverse.collect { |a| e=!e
a.to_i*(e ? 1:2)
}.join.split(//).inject(0) {|a,b| a+b.to_i} % 10 == 0 ? "Valid" :
"Invalid"
end

card = ARGV.join.gsub(/ /, '')
if card == ""
puts "Usage: #{$0} <card number>"
else
puts ctype(card)
puts luhncheck(card)
end
###

Joe