[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.ruby

Credit Card Verification as an exercise

Jeffrey Moss

3/23/2005 11:23:00 PM

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/car...

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 = 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
end

def number_matches_type
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)
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

8 Answers

Florian Gross

3/23/2005 11:33:00 PM

0

Jeffrey Moss wrote:

> 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

Jeffrey Moss

3/23/2005 11:42:00 PM

0

free your mind neo

right, there is no spoon

yeah

----- Original Message -----
From: "Florian Gross" <flgr@ccan.de>
Newsgroups: comp.lang.ruby
To: "ruby-talk ML" <ruby-talk@ruby-lang.org>
Sent: Wednesday, March 23, 2005 4:34 PM
Subject: Re: Credit Card Verification as an exercise


> Jeffrey Moss wrote:
>
>> 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
>


Ben Giddings

3/23/2005 11:55:00 PM

0

Florian Gross wrote:
> 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


Florian Gross

3/24/2005 12:37:00 AM

0

Ben Giddings wrote:

> Florian Gross wrote:
>
>> 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. :)

Florian Gross

3/24/2005 12:39:00 AM

0

Jeffrey Moss wrote:

> 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.

Jeffrey Moss

3/24/2005 1:21:00 AM

0

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" <flgr@ccan.de>
Newsgroups: comp.lang.ruby
To: "ruby-talk ML" <ruby-talk@ruby-lang.org>
Sent: Wednesday, March 23, 2005 5:39 PM
Subject: Re: Credit Card Verification as an exercise


> Jeffrey Moss wrote:
>
>> 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.
>



Florian Gross

3/24/2005 2:07:00 AM

0

Jeffrey Moss wrote:

> 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.

tim

3/24/2005 12:38:00 PM

0


Jeffrey Moss wrote:
> Couldn't find any credit card verification code written in ruby so I
wrote up my own.

There is this: http://rubyforge.org/projects/...