From 4ffb388c794f232dce4e79429484dc56364f43aa Mon Sep 17 00:00:00 2001 From: Peter Mueller Date: Fri, 28 Apr 2017 23:48:15 -0400 Subject: [PATCH 1/2] add npi and longer form of npi --- .gitignore | 3 +++ lib/ex_junk.ex | 40 ++++++++++++++++++++++++++++++++++++++++ test/ex_junk_test.exs | 20 ++++++++++++++++++++ 3 files changed, 63 insertions(+) diff --git a/.gitignore b/.gitignore index b6012c7..4f7a773 100644 --- a/.gitignore +++ b/.gitignore @@ -18,3 +18,6 @@ erl_crash.dump # Also ignore archive artifacts (built via "mix archive.build"). *.ez + +# asdf-vm version file +/.tool-versions diff --git a/lib/ex_junk.ex b/lib/ex_junk.ex index de89021..9ce0732 100644 --- a/lib/ex_junk.ex +++ b/lib/ex_junk.ex @@ -35,6 +35,36 @@ defmodule Junk do post_op(output, opts) end + def junk(:long_npi, opts) do + opts = construct_opts(opts) + |> Map.put(:size, 8) + # grab 8 digits, and put a 1 or 2 on the front + base_digits = junk(Integer, opts) + |> Integer.digits + |> (fn digits -> [8,0,8,4,0] ++ [Enum.random(1..2)] ++ digits end).() + + # starting from the right, doubles digits + # splits into 2 digits where needed + # sums, and adds 24 (for the 80840 of the longer form npi) + check_sum = base_digits + |> Enum.reverse + |> Junk.map_every(2, fn(n) ->Integer.digits(n*2) end) + |> List.flatten + |> Enum.sum + + # calcs the check digit + check_digit = case Kernel.rem(check_sum, 10) do + 0 -> 0 + n -> 10 - n + end + + (base_digits ++ [check_digit]) |> Integer.undigits + end + + def junk(:npi, opts) do + junk(:long_npi, opts) - trunc(80840 * :math.pow(10, 10)) + end + def junk(f, opts) when is_function(f) do opts = construct_opts(opts) apply(f, opts.parameters) @@ -49,6 +79,16 @@ defmodule Junk do end end + def map_every(enumerable, nth, mapper) do + {res, _acc} = Enum.map_reduce(enumerable, 0, fn(x, i) -> if (rem(i, nth) == 0) do + {mapper.(x), i+1} + else + {x, i+1} + end + end) + res + end + defp construct_opts(opts) do Enum.into(opts, Map.from_struct(%Junk{})) end diff --git a/test/ex_junk_test.exs b/test/ex_junk_test.exs index 3078cc6..b933286 100644 --- a/test/ex_junk_test.exs +++ b/test/ex_junk_test.exs @@ -23,6 +23,13 @@ defmodule JunkTest do assert output != Junk.junk(String, byte_size: 5) end + test "unnecessary options are ignored" do + string = Junk.junk(String, size: 10) + integer = Junk.junk(Integer, byte_size: "asdf") + assert is_binary(string) == true + assert integer |> is_integer == true + end + test "returns unique Strings" do output = Junk.junk(String) assert is_binary(output) == true @@ -79,6 +86,19 @@ defmodule JunkTest do assert "123-45-6789" = output end + test ":npi returns a short NPI" do + digits = Junk.junk(:npi) |> Integer.digits + assert Kernel.length(digits) == 10 + assert Enum.member?([1,2], List.first(digits)) + end + + test ":long_npi returns a long NPI" do + digits = Junk.junk(:long_npi) |> Integer.digits + assert Kernel.length(digits) == 15 + first_6 = digits |> Enum.take(6) |> Integer.undigits + assert Enum.member?([808401,808402], first_6) + end + def ssn do "123-45-6789" end From c390949fb79f1b8334417b9e88fd50b90dec3d91 Mon Sep 17 00:00:00 2001 From: Peter Mueller Date: Thu, 11 May 2017 14:36:16 -0400 Subject: [PATCH 2/2] refactor into luhn function --- lib/ex_junk.ex | 40 +++++++++++++++++++++------------------- test/ex_junk_test.exs | 4 ++++ 2 files changed, 25 insertions(+), 19 deletions(-) diff --git a/lib/ex_junk.ex b/lib/ex_junk.ex index 9ce0732..1a66923 100644 --- a/lib/ex_junk.ex +++ b/lib/ex_junk.ex @@ -39,26 +39,11 @@ defmodule Junk do opts = construct_opts(opts) |> Map.put(:size, 8) # grab 8 digits, and put a 1 or 2 on the front - base_digits = junk(Integer, opts) + junk(Integer, opts) |> Integer.digits |> (fn digits -> [8,0,8,4,0] ++ [Enum.random(1..2)] ++ digits end).() - - # starting from the right, doubles digits - # splits into 2 digits where needed - # sums, and adds 24 (for the 80840 of the longer form npi) - check_sum = base_digits - |> Enum.reverse - |> Junk.map_every(2, fn(n) ->Integer.digits(n*2) end) - |> List.flatten - |> Enum.sum - - # calcs the check digit - check_digit = case Kernel.rem(check_sum, 10) do - 0 -> 0 - n -> 10 - n - end - - (base_digits ++ [check_digit]) |> Integer.undigits + |> Integer.undigits + |> Junk.luhn end def junk(:npi, opts) do @@ -79,6 +64,23 @@ defmodule Junk do end end + def luhn(number) do + base_digits = Integer.digits(number) + check_sum = base_digits + |> Enum.reverse + |> Junk.map_every(2, fn(n) ->Integer.digits(n*2) end) + |> List.flatten + |> Enum.sum + + # calcs the check digit + check_digit = case Kernel.rem(check_sum, 10) do + 0 -> 0 + n -> 10 - n + end + + (base_digits ++ [check_digit]) |> Integer.undigits + end + def map_every(enumerable, nth, mapper) do {res, _acc} = Enum.map_reduce(enumerable, 0, fn(x, i) -> if (rem(i, nth) == 0) do {mapper.(x), i+1} @@ -94,6 +96,6 @@ defmodule Junk do end defp post_op(output, opts) do - output = if opts.prefix, do: "#{opts.prefix}-#{output}", else: output + if opts.prefix, do: "#{opts.prefix}-#{output}", else: output end end diff --git a/test/ex_junk_test.exs b/test/ex_junk_test.exs index b933286..418893a 100644 --- a/test/ex_junk_test.exs +++ b/test/ex_junk_test.exs @@ -99,6 +99,10 @@ defmodule JunkTest do assert Enum.member?([808401,808402], first_6) end + test "luhn returns a luhn'd number" do + assert Junk.luhn(80840268496713) == 808402684967138 + end + def ssn do "123-45-6789" end