Forum: Ruby [SOLUTION] Checking Credit Cards (#122)

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
334805ec86cb3fe1ac2eda776a921fb2?d=identicon&s=25 Brad Ediger (Guest)
on 2007-04-29 20:18
(Received via mailing list)
Let's try this again. List ate my post. Maybe it's the S/MIME sig?

----

OK, this is the first Quiz contribution I have made (publicly). I
think it is a good balance between terse and readable.

JEG2, the luhn_valid? check is what I mean by Functional Programming
in Ruby, or as you say, the Power of Iterators. :-)

--be

####
#!/usr/bin/env ruby -wKU

# Some utility functions first
require 'enumerator'
module Enumerable
   # Maps n-at-a-time (n = arity of given block) and collects the
results
   def mapn(&b)
     r = []
     each_slice(b.arity) {|*args| r << b.call(*args) }
     r
   end

   def sum; inject(0){|s, i| s + i} end
end

class CreditCardNumber < String
   TYPES = {"3[47]\\d{13}"       => "Amex",
            "6011\\d{12}"        => "Discover",
            "5[1-5]\\d{14}"      => "Mastercard",
            "4(\\d{12}|\\d{15})" => "Visa"}

   # Returns the type of the given card, or nil if the card does not
match a pattern
   def card_type
     (t = TYPES.detect{|re, t| /^#{re}$/ === self}) && t.last
   end

   # Returns true iff Luhn check passes for this number
   def luhn_valid?
     # a trick: double_and_sum[8] == sum_digits(8*2) == sum_digits
(16) == 1 + 6 == 7
     double_and_sum = [0, 2, 4, 6, 8, 1, 3, 5, 7, 9]
     split(//).reverse.mapn{|a,b| a.to_i + double_and_sum
[b.to_i]}.sum % 10 == 0
   end

   # Returns true iff card matches a known type and Luhn check passes.
   def valid?
     luhn_valid? && !card_type.nil?
   end
end

if (arg = ARGV.join.gsub(/[^0-9]/, '')) and !arg.empty?
   number = CreditCardNumber.new(arg)

   if number.valid?
     puts "Valid #{number.card_type}"
   else
     puts "Invalid card"
   end
end
4299e35bacef054df40583da2d51edea?d=identicon&s=25 James Gray (bbazzarrakk)
on 2007-05-02 14:06
(Received via mailing list)
On Apr 29, 2007, at 1:17 PM, Brad Ediger wrote:

> OK, this is the first Quiz contribution I have made (publicly).

Wow, a semi-local solving the quiz.  I guess that means you need to
get back to another OK.rb meeting Brad.  ;)

Welcome to all the new solvers!

James Edward Gray II
4299e35bacef054df40583da2d51edea?d=identicon&s=25 James Gray (bbazzarrakk)
on 2007-05-02 15:57
(Received via mailing list)
On Apr 29, 2007, at 1:17 PM, Brad Ediger wrote:

>   # Maps n-at-a-time (n = arity of given block) and collects the
> results
>   def mapn(&b)
>     r = []
>     each_slice(b.arity) {|*args| r << b.call(*args) }
>     r
>   end

That's pretty darn clever.  You can collapse it to one line with
inject() of course:

   def mapn(&b)
     enum_slice(b.arity).inject([]) {|r, args| r << b.call(*args) }
   end

James Edward Gray II
334805ec86cb3fe1ac2eda776a921fb2?d=identicon&s=25 Brad Ediger (Guest)
on 2007-05-02 18:45
(Received via mailing list)
On May 2, 2007, at 8:57 AM, James Edward Gray II wrote:

> That's pretty darn clever.  You can collapse it to one line with
> inject() of course:
>
>   def mapn(&b)
>     enum_slice(b.arity).inject([]) {|r, args| r << b.call(*args) }
>   end

Didn't even think about inject here. Awesome. I'm sure that I'm going
to be using mapn more, as it's cool.

I can't take credit for the mapn concept though: eachn is a Facets
function I stumbled across.

--be
93d566cc26b230c553c197c4cd8ac6e4?d=identicon&s=25 Pit Capitain (Guest)
on 2007-05-02 19:27
(Received via mailing list)
James Edward Gray II schrieb:
> That's pretty darn clever.  You can collapse it to one line with
> inject() of course:
>
>   def mapn(&b)
>     enum_slice(b.arity).inject([]) {|r, args| r << b.call(*args) }
>   end

Simpler:

   def mapn(&b)
     to_enum(:each_slice, b.arity).map(&b)
   end

Regards,
Pit
This topic is locked and can not be replied to.