Credit Card Verification as an exercise

J

Jeffrey Moss

------=_NextPart_000_0062_01C52FC4.7DDBCEE0
Content-Type: text/plain;
charset="iso-8859-1"
Content-Transfer-Encoding: quoted-printable

Couldn't find any credit card verification code written in ruby so I =
wrote up my own. This code turns out a lot smaller than the perl =
version I have been using. I thought it was an interesting exercise, =
here is how its done, if anybody can improve on what I've done I'd be =
impressed.

Heres a howto guide on it
http://www.beachnet.com/~hstiles/cardtype.html

Feel free to use the code.




class CreditCard < ActiveRecord::Base

def before_save
if number_is_valid && number_matches_type
...
end
end

def number_is_valid
total =3D 0
number.gsub(/[^0-9]/, '').reverse.scan(/(\d)(\d){0,1}/) do |ud,ad|
(ad.to_i*2).to_s.each {|d| total =3D total + d.to_i} if ad
total =3D total + ud.to_i
end
total % 10 =3D=3D 0 ? false : true
end

def number_matches_type
digit_length =3D number.length
if card_type =3D=3D 'visa'
if (digit_length =3D=3D 16) || (digit_length =3D=3D 13)
return true if number[/^\d/].to_i =3D=3D 4
end
elsif card_type =3D=3D 'mastercard'
if digit_length =3D=3D 16
return true if (51..55).to_a.include?(number[0..1].to_i)
end
elsif card_type =3D=3D 'amex'
if digit_length =3D=3D 15
return true if [34,37].include?(number[0..1].to_i)
end
elsif card_type =3D=3D 'discover'
if digit_length =3D=3D 16
return true if number[0..3].to_i =3D=3D 6011
end
end
end
end


------=_NextPart_000_0062_01C52FC4.7DDBCEE0--
 
F

Florian Gross

Jeffrey said:
Couldn't find any credit card verification code written in ruby so I
wrote up my own. This code turns out a lot smaller than the perl
version I have been using. I thought it was an interesting exercise,
here is how its done, if anybody can improve on what I've done I'd be
impressed. %*

Nice code and I guess it will be quite useful as well! Thanks for
posting this here.
class CreditCard < ActiveRecord::Base

def before_save
if number_is_valid && number_matches_type
...
end
end

def number_is_valid

Guess, I'd rename this to 'number_valid?'. :)
total = 0
number.gsub(/[^0-9]/, '').reverse.scan(/(\d)(\d){0,1}/) do |ud,ad|
(ad.to_i*2).to_s.each {|d| total = total + d.to_i} if ad
total = total + ud.to_i
end
total % 10 == 0 ? false : true

Hm, why not simply "total % 10 != 0"?
end

def number_matches_type

Might be nice to append a question mark here as well.
digit_length = number.length
if card_type == 'visa'
if (digit_length == 16) || (digit_length == 13)
return true if number[/^\d/].to_i == 4
end
elsif card_type == 'mastercard'
if digit_length == 16
return true if (51..55).to_a.include?(number[0..1].to_i)

Hmmm, why the .to_a call?
end
elsif card_type == 'amex'
if digit_length == 15
return true if [34,37].include?(number[0..1].to_i)
end
elsif card_type == 'discover'
if digit_length == 16
return true if number[0..3].to_i == 6011
end
end
end
end

I think all this returns are superfluous -- after all Ruby will return
the result of evaluating the matching if clause.

Oh, and I think this is a good case for the case construct:

case card_type
when 'visa' then
[13, 16].include?(digit_length) and number[0, 1] == "4"
when 'mastercard' then
digit_length == 16 and ("51" .. "55").include?(number[0, 2])
when 'amex' then
digit_length == 15 and %w(34 37).include?(number[0, 2])
when 'discover' then
digit_length == 16 and number[0, 4] == "6011"
end
 
J

Jeffrey Moss

free your mind neo

right, there is no spoon

yeah

----- Original Message -----
From: "Florian Gross" <[email protected]>
Newsgroups: comp.lang.ruby
To: "ruby-talk ML" <[email protected]>
Sent: Wednesday, March 23, 2005 4:34 PM
Subject: Re: Credit Card Verification as an exercise

Jeffrey said:
Couldn't find any credit card verification code written in ruby so I
wrote up my own. This code turns out a lot smaller than the perl
version I have been using. I thought it was an interesting exercise,
here is how its done, if anybody can improve on what I've done I'd be
impressed. %*

Nice code and I guess it will be quite useful as well! Thanks for
posting this here.
class CreditCard < ActiveRecord::Base

def before_save
if number_is_valid && number_matches_type
...
end
end

def number_is_valid

Guess, I'd rename this to 'number_valid?'. :)
total = 0
number.gsub(/[^0-9]/, '').reverse.scan(/(\d)(\d){0,1}/) do |ud,ad|
(ad.to_i*2).to_s.each {|d| total = total + d.to_i} if ad
total = total + ud.to_i
end
total % 10 == 0 ? false : true

Hm, why not simply "total % 10 != 0"?
end

def number_matches_type

Might be nice to append a question mark here as well.
digit_length = number.length
if card_type == 'visa'
if (digit_length == 16) || (digit_length == 13)
return true if number[/^\d/].to_i == 4
end
elsif card_type == 'mastercard'
if digit_length == 16
return true if (51..55).to_a.include?(number[0..1].to_i)

Hmmm, why the .to_a call?
end
elsif card_type == 'amex'
if digit_length == 15
return true if [34,37].include?(number[0..1].to_i)
end
elsif card_type == 'discover'
if digit_length == 16
return true if number[0..3].to_i == 6011
end
end
end
end

I think all this returns are superfluous -- after all Ruby will return
the result of evaluating the matching if clause.

Oh, and I think this is a good case for the case construct:

case card_type
when 'visa' then
[13, 16].include?(digit_length) and number[0, 1] == "4"
when 'mastercard' then
digit_length == 16 and ("51" .. "55").include?(number[0, 2])
when 'amex' then
digit_length == 15 and %w(34 37).include?(number[0, 2])
when 'discover' then
digit_length == 16 and number[0, 4] == "6011"
end
 
B

Ben Giddings

Florian said:
case card_type
when 'visa' then
[13, 16].include?(digit_length) and number[0, 1] == "4"
when 'mastercard' then
digit_length == 16 and ("51" .. "55").include?(number[0, 2])
when 'amex' then
digit_length == 15 and %w(34 37).include?(number[0, 2])
when 'discover' then
digit_length == 16 and number[0, 4] == "6011"
end

Actually, you don't need the "then"s either (and you should probably
have an else, even though nil is "untrue" as well)

case card_type
when 'visa'
[13, 16].include?(digit_length) and number[0] == ?4
when 'mastercard'
digit_length == 16 and ("51" .. "55").include?(number[0, 2])
when 'amex'
digit_length == 15 and %w(34 37).include?(number[0, 2])
when 'discover'
digit_length == 16 and number[0, 4] == "6011"
else
false
end

Ben
 
F

Florian Gross

Ben said:
Florian said:
case card_type
when 'visa' then
[13, 16].include?(digit_length) and number[0, 1] == "4"
when 'mastercard' then
digit_length == 16 and ("51" .. "55").include?(number[0, 2])
when 'amex' then
digit_length == 15 and %w(34 37).include?(number[0, 2])
when 'discover' then
digit_length == 16 and number[0, 4] == "6011"
end

Actually, you don't need the "then"s either (and you should probably
have an else, even though nil is "untrue" as well)

I know, but I somehow think it looks more balanced that way. Though I
was not sure whether to use "then" or ":" in this case -- I guess it is
a matter of taste and not too important. :)
 
F

Florian Gross

Jeffrey said:
free your mind neo

right, there is no spoon

yeah

Hm, I get the reference, but I'm not sure I understand what you're
trying to hint at -- was I being too hard to understand? Sorry in that
case. I'd be pleased to clear it up, if you can come up with concrete
questions.

Oh, and sorry if I'm misunderstanding.
 
J

Jeffrey Moss

They were good suggestions, I haven't quite adjusted to ruby, still in a
perl mindset. That's what I meant. I'm trying to free my mind. The perl code
was pretty long, maybe over 100 lines, in ruby its like 20, heh heh.

I leave the "then" off too, I only use then if its a one liner, and in that
case I will usually use { }'s
if there is a CR right after the if line, then its self explanatory I think
(and emacs indents the line after so its all good)
minor details

-Jeff

----- Original Message -----
From: "Florian Gross" <[email protected]>
Newsgroups: comp.lang.ruby
To: "ruby-talk ML" <[email protected]>
Sent: Wednesday, March 23, 2005 5:39 PM
Subject: Re: Credit Card Verification as an exercise
 
F

Florian Gross

Jeffrey said:
They were good suggestions, I haven't quite adjusted to ruby, still in a
perl mindset. That's what I meant. I'm trying to free my mind. The perl
code was pretty long, maybe over 100 lines, in ruby its like 20, heh heh.

Heh, that's one reason we love it so much. :)
I leave the "then" off too, I only use then if its a one liner, and in
that case I will usually use { }'s
if there is a CR right after the if line, then its self explanatory I
think (and emacs indents the line after so its all good)
minor details

I guess my habit comes from writing such code:

if items.all? do |item|
item > 5 and
more complex checks and
so on or
whatever
end then
do something
end

That was the reason for me generally adapting the 'then' suffixes, I think.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,995
Messages
2,570,236
Members
46,822
Latest member
israfaceZa

Latest Threads

Top