Skip to content

Commit

Permalink
Bulletproofing for PESEL numbers containing other characters than digits
Browse files Browse the repository at this point in the history
  • Loading branch information
crabonature committed Jan 7, 2018
1 parent 1bcf003 commit f1b8b4a
Show file tree
Hide file tree
Showing 5 changed files with 39 additions and 9 deletions.
6 changes: 5 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# Changelog

## v0.2.0

* fix ArgumentError when passing broken PESEL containing not only digits

## v0.1.0

* here it begins
* here it begins
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ to your list of dependencies in `mix.exs`:
```elixir
def deps do
[
{:ex_pesel, "~> 0.1.0"}
{:ex_pesel, "~> 0.2.0"}
]
end
```
Expand Down
19 changes: 17 additions & 2 deletions lib/ex_pesel.ex
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,9 @@ defmodule ExPesel do
iex> ExPesel.valid?("23455532312131123123")
false
iex> ExPesel.valid?("some really bad data")
false
"""
@spec valid?(String.t()) :: boolean()
defdelegate valid?(pesel), to: Pesel
Expand Down Expand Up @@ -75,6 +78,9 @@ defmodule ExPesel do
iex> ExPesel.valid_with?("44051401458", {1944, 6, 13})
false
iex> ExPesel.valid_with?("some really bad data", {1944, 6, 13})
false
"""
def valid_with?(pesel, sex_or_birthday)

Expand Down Expand Up @@ -115,8 +121,11 @@ defmodule ExPesel do
iex> ExPesel.birthdate("90720312611")
{2290, 12, 3}
iex> ExPesel.birthdate("some really bad input")
:unknown
"""
@spec birthdate(String.t()) :: {1800..2299, 1..12, 1..31}
@spec birthdate(String.t()) :: {1800..2299, 1..12, 1..31} | :unknown
defdelegate birthdate(pesel), to: Pesel

@doc """
Expand All @@ -132,8 +141,11 @@ defmodule ExPesel do
iex> ExPesel.sex("88122302080")
:female
iex> ExPesel.sex("some bad input")
:unknown
"""
@spec sex(String.t()) :: :male | :female
@spec sex(String.t()) :: :male | :female | :unknown
defdelegate sex(pesel), to: Pesel

@doc """
Expand All @@ -147,6 +159,9 @@ defmodule ExPesel do
iex> ExPesel.zombie?("88122302080")
false
iex> ExPesel.zombie?("I'm a zombie man!")
false
"""
@spec zombie?(String.t()) :: boolean()
defdelegate zombie?(pesel), to: Pesel
Expand Down
19 changes: 15 additions & 4 deletions lib/ex_pesel/pesel.ex
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ defmodule ExPesel.Pesel do
# for 2000-2099 we got addition of 20 to mm
# for 2100-2199 we got addition of 40 to mm
# for 2200-2299 we got addition of 60 to mm
@spec birthdate(String.t()) :: {1800..2299, 1..12, 1..3}
@spec birthdate(String.t()) :: {1800..2299, 1..12, 1..3} | :unknown
def birthdate(pesel), do: do_birthdate(to_list(pesel))

# sorry for that but in elixir there is no multiguards
Expand All @@ -67,6 +67,8 @@ defmodule ExPesel.Pesel do
defp do_birthdate([y1, y2, m1, m2, d1, d2 | _])
when m1 < 10, do: date({18, y1, y2}, {m1 - 8, m2}, {d1, d2})

defp do_birthdate([]), do: :unknown

defp date(as_year, as_month, as_day) do
{year(as_year), month(as_month), day(as_day)}
end
Expand All @@ -78,24 +80,33 @@ defmodule ExPesel.Pesel do
# Sex is encoded with 10 digit
# odd for male
# even for female
@spec sex(String.t()) :: :male | :female
@spec sex(String.t()) :: :male | :female | :unknown
def sex(pesel) when is_binary(pesel), do: do_sex(to_list(pesel))

defp do_sex([_, _, _, _, _, _, _, _, _, s | _]) when rem(s, 2) == 1, do: :male
defp do_sex(_), do: :female
defp do_sex([]), do: :unknown
defp do_sex(_), do: :female

# PESEL is zombie if
# date of birth is 123 years before today
@spec zombie?(String.t()) :: boolean()
def zombie?(pesel) when is_binary(pesel), do: is_zombie?(pesel)

defp is_zombie?(pesel), do: birthdate(pesel) < years_before(today(), @years)
defp is_zombie?(pesel), do: dead?(birthdate(pesel))
defp dead?(:unknown), do: false
defp dead?(birthday), do: birthday < years_before(today(), @years)
defp years_before({year, month, day}, dist), do: {year - dist, month, day}

# Transpose from string to list
defp to_list(pesel) do
pesel
|> scan()
|> resolve()
|> String.split("", trim: true)
|> Enum.map(&String.to_integer/1)
end

defp scan(pesel), do: Regex.scan(~r/^\d{11}$/, pesel)
defp resolve([]), do: ""
defp resolve([[pesel]]), do: pesel
end
2 changes: 1 addition & 1 deletion mix.exs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
defmodule ExPesel.MixProject do
use Mix.Project

@version "0.1.0"
@version "0.2.0"

@description "Library for PESEL number."
@repo_url "https://github.com/crabonature/ex_pesel"
Expand Down

0 comments on commit f1b8b4a

Please sign in to comment.