Skip to content

Instantly share code, notes, and snippets.

@Cifer-Y
Created May 7, 2016 16:48
Show Gist options
  • Save Cifer-Y/d3e34e2ee53ca0a5f4cf6e143fc4f879 to your computer and use it in GitHub Desktop.
Save Cifer-Y/d3e34e2ee53ca0a5f4cf6e143fc4f879 to your computer and use it in GitHub Desktop.
defmodule CardValidation do
def output_result(cards) do
cards
|> Enum.map(fn(card) ->
"#{card_type(card)}: #{card |> strip_card}"
|> String.ljust(30)
|> Kernel.<>("(#{luhn(card)})")
end)
|> Enum.join("\n")
|> IO.puts
end
def card_type(card), do: amex?(card) || discover?(card) || master_card?(card) || visa?(card) || "Unknown"
def amex?(card), do: card_head(:amex, card) && card_length(:amex, card) && "AMEX"
def discover?(card), do: card_head(:discover, card) && card_length(:discover, card) && "Discover"
def master_card?(card), do: card_head(:master_card, card) && card_length(:master_card, card) && "MasterCard"
def visa?(card), do: card_head(:visa, card) && card_length(:visa, card) && "VISA"
def card_head(:amex, "34" <> _), do: true
def card_head(:amex, "37" <> _), do: true
def card_head(:amex, _), do: false
def card_head(:discover, "6011" <> _), do: true
def card_head(:discover, _), do: false
def card_head(:master_card, "51" <> _), do: true
def card_head(:master_card, "52" <> _), do: true
def card_head(:master_card, "53" <> _), do: true
def card_head(:master_card, "54" <> _), do: true
def card_head(:master_card, "55" <> _), do: true
def card_head(:master_card, _), do: false
def card_head(:visa, "4" <> _), do: true
def card_head(:visa, _), do: false
def card_length(:amex, card), do: card_length(card) == 15
def card_length(:discover, card), do: card_length(card) == 16
def card_length(:master_card, card), do: card_length(card) == 16
def card_length(:visa, card), do: card_length(card) == 16 || card_length(card) == 13
def card_length(card), do: card |> strip_card |> String.length
def luhn(card) do
card
|> get_data
|> update_data
|> count_result
|> valid_format?
end
def get_data(card), do: card |> strip_card |> String.to_integer |> Integer.digits
def update_data(data) do
reversed = data |> Enum.reverse
doubled = reversed
|> Enum.drop(1)
|> Enum.take_every(2)
|> Enum.map(&(&1 * 2))
|> Enum.flat_map(&Integer.digits/1)
reversed
|> Enum.take_every(2)
|> Enum.concat(doubled)
end
def count_result(data) do
data
|> Enum.sum
|> rem(10)
|> Kernel.==(0)
end
def valid_format?(true), do: "valid" |> color_text(:green)
def valid_format?(false), do: "invalid" |> color_text(:red)
def color_text(text, color), do: IO.ANSI.format([color, :bright, "#{text}"], true)
def strip_card(card), do: card |> String.replace(~r/\s+/, "")
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment