main
 1require "spec_helper"
 2
 3# The Luhn test is used by some credit card companies to
 4# distinguish valid credit card numbers from what could
 5# be a random selection of digits.
 6#
 7# For example, if the trial number is 49927398716:
 8#
 9# 1. Reverse the digits:
10#   61789372994
11# 2. Sum the odd digits:
12#   6 + 7 + 9 + 7 + 9 + 4 = 42 = s1
13# 3. The even digits:
14#   1,  8,  3,  2,  9
15# 4. Two times each even digit:
16#   2, 16,  6,  4, 18
17# 5. Sum the digits of each multiplication:
18#   2,  7,  6,  4,  9
19# 6. Sum the last:
20#   2 + 7 + 6 + 4 + 9 = 28 = s2
21#
22# s1 + s2 = 70 which ends in zero which means {
23# that 49927398716 passes the Luhn test
24
25
26class Luhn
27  def self.valid?(credit_card)
28    step_2, step_3 = partition(credit_card.digits)
29    (step_2.sum + step_3.map { |x| x * 2 }.map { |x| x.digits.sum }.sum).digits[0].zero?
30  end
31
32  def self.partition(digits)
33    digits.each_with_index.inject([[], []]) do |memo, (digit, index)|
34      memo[index.even? ? 0 : 1].push(digit)
35      memo
36    end
37  end
38end
39
40RSpec.describe Luhn do
41  subject { Luhn }
42
43  describe ".valid?" do
44    specify { expect(subject).to be_valid(49927398716) }
45    specify { expect(subject).not_to be_valid(49927398717) }
46    specify { expect(subject).not_to be_valid(1234567812345678) }
47    specify { expect(subject).to be_valid(1234567812345670) }
48  end
49end