...
 
Commits (2)
image: elixir:alpine
variables:
MIX_ENV: "test"
before_script:
- mix deps.get
mix:
script:
- mix test
defmodule Duration do
@type t :: %__MODULE__{
years: non_neg_integer,
months: non_neg_integer,
days: non_neg_integer,
months: pos_integer,
days: pos_integer,
hours: non_neg_integer,
minutes: non_neg_integer,
seconds: non_neg_integer
......@@ -20,28 +20,67 @@ defmodule Duration do
Documentation for Duration.
"""
def new(%Duration{} = val), do: {:ok, val}
def new(val) when is_binary(val) do
parse(val)
end
def new(opts) when is_list(opts) do
params = opts |> Keyword.take([:years, :months, :days, :hours, :minutes, :seconds])
params = params |> Enum.map(fn {k, v} -> {k, abs(v)} end)
if params == opts do
{:ok, struct(__MODULE__, params)}
else
{:error, :wrong_options}
end
end
@doc """
Hello world.
## Examples
iex> Duration.parse_duration("PT3S")
iex> Duration.parse("PT3S")
{:ok, %Duration{seconds: 3}}
"""
def parse_duration(value) when is_binary(value) do
def parse(value) when is_binary(value) do
case Parser.parse(value) do
{:ok, params, _, _, _, _} ->
{:ok, struct(__MODULE__, params)}
z ->
{:error, z}
end
_ ->
{:error, :invalid_duration}
ends
end
def parse_duration(_) do
def parse(_) do
{:error}
end
@doc """
Converts Duration into Timex.shift_options, wich can be used with Timex
## Examples
Go forward
iex > Duration.to_timex_options(%Duration{years: 1})
{:ok, [days: 0, hours: 0, minutes: 0, months: 0, seconds: 0, years: 1]}
Go forward
iex > Duration.to_timex_options(%Duration{years: 1}; :backward)
{:ok, [days: 0, hours: 0, minutes: 0, months: 0, seconds: 0, years: -1]}
"""
def to_timex_options(%Duration{} = duration, direction \\ :forward) when direction in [:forward, :backward] do
options =
case direction do
:forward -> Map.from_struct(duration) |> Map.to_list
:backward -> Map.from_struct(duration) |> Enum.map(fn {k, v} -> {k, v * -1} end)
end
{:ok, options |> Enum.filter(fn {_, v} -> v != 0 end)}
end
end
defimpl String.Chars, for: Duration do
......
if Code.ensure_loaded?(NimbleParsec) do
defmodule Duration.Parser.Helpers do
@moduledoc false
import NimbleParsec
def year do
......
......@@ -21,7 +21,10 @@ defmodule Duration.MixProject do
# Run "mix help deps" to learn about dependencies.
defp deps do
[
{:nimble_parsec, "~> 0.5.0", only: :dev}
{:nimble_parsec, "~> 0.5.0", only: :dev},
# {:credo, "~> 1.1", only: [:dev, :test], runtime: false},
# {:dialyxir, "~> 1.0.0-rc.6", only: [:dev, :test], runtime: false},
# {:timex, "~> 3.6", only: [:dev, :test], runtime: false}
]
end
end
%{
"bunt": {:hex, :bunt, "0.2.0", "951c6e801e8b1d2cbe58ebbd3e616a869061ddadcc4863d0a2182541acae9a38", [:mix], [], "hexpm"},
"certifi": {:hex, :certifi, "2.5.1", "867ce347f7c7d78563450a18a6a28a8090331e77fa02380b4a21962a65d36ee5", [:rebar3], [{:parse_trans, "~>3.3", [hex: :parse_trans, repo: "hexpm", optional: false]}], "hexpm"},
"combine": {:hex, :combine, "0.10.0", "eff8224eeb56498a2af13011d142c5e7997a80c8f5b97c499f84c841032e429f", [:mix], [], "hexpm"},
"credo": {:hex, :credo, "1.1.2", "02b6422f3e659eb74b05aca3c20c1d8da0119a05ee82577a82e6c2938bf29f81", [:mix], [{:bunt, "~> 0.2.0", [hex: :bunt, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm"},
"dialyxir": {:hex, :dialyxir, "1.0.0-rc.6", "78e97d9c0ff1b5521dd68041193891aebebce52fc3b93463c0a6806874557d7d", [:mix], [{:erlex, "~> 0.2.1", [hex: :erlex, repo: "hexpm", optional: false]}], "hexpm"},
"erlex": {:hex, :erlex, "0.2.4", "23791959df45fe8f01f388c6f7eb733cc361668cbeedd801bf491c55a029917b", [:mix], [], "hexpm"},
"gettext": {:hex, :gettext, "0.17.0", "abe21542c831887a2b16f4c94556db9c421ab301aee417b7c4fbde7fbdbe01ec", [:mix], [], "hexpm"},
"hackney": {:hex, :hackney, "1.15.1", "9f8f471c844b8ce395f7b6d8398139e26ddca9ebc171a8b91342ee15a19963f4", [:rebar3], [{:certifi, "2.5.1", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "6.0.0", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "1.0.1", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "~>1.1", [hex: :mimerl, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "1.1.4", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}], "hexpm"},
"idna": {:hex, :idna, "6.0.0", "689c46cbcdf3524c44d5f3dde8001f364cd7608a99556d8fbd8239a5798d4c10", [:rebar3], [{:unicode_util_compat, "0.4.1", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm"},
"jason": {:hex, :jason, "1.1.2", "b03dedea67a99223a2eaf9f1264ce37154564de899fd3d8b9a21b1a6fd64afe7", [:mix], [{:decimal, "~> 1.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm"},
"metrics": {:hex, :metrics, "1.0.1", "25f094dea2cda98213cecc3aeff09e940299d950904393b2a29d191c346a8486", [:rebar3], [], "hexpm"},
"mimerl": {:hex, :mimerl, "1.2.0", "67e2d3f571088d5cfd3e550c383094b47159f3eee8ffa08e64106cdf5e981be3", [:rebar3], [], "hexpm"},
"nimble_parsec": {:hex, :nimble_parsec, "0.5.0", "90e2eca3d0266e5c53f8fbe0079694740b9c91b6747f2b7e3c5d21966bba8300", [:mix], [], "hexpm"},
"parse_trans": {:hex, :parse_trans, "3.3.0", "09765507a3c7590a784615cfd421d101aec25098d50b89d7aa1d66646bc571c1", [:rebar3], [], "hexpm"},
"ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.4", "f0eafff810d2041e93f915ef59899c923f4568f4585904d010387ed74988e77b", [:make, :mix, :rebar3], [], "hexpm"},
"timex": {:hex, :timex, "3.6.1", "efdf56d0e67a6b956cc57774353b0329c8ab7726766a11547e529357ffdc1d56", [:mix], [{:combine, "~> 0.10", [hex: :combine, repo: "hexpm", optional: false]}, {:gettext, "~> 0.10", [hex: :gettext, repo: "hexpm", optional: false]}, {:tzdata, "~> 0.1.8 or ~> 0.5 or ~> 1.0.0", [hex: :tzdata, repo: "hexpm", optional: false]}], "hexpm"},
"tzdata": {:hex, :tzdata, "1.0.1", "f6027a331af7d837471248e62733c6ebee86a72e57c613aa071ebb1f750fc71a", [:mix], [{:hackney, "~> 1.0", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm"},
"unicode_util_compat": {:hex, :unicode_util_compat, "0.4.1", "d869e4c68901dd9531385bb0c8c40444ebf624e60b6962d95952775cac5e90cd", [:rebar3], [], "hexpm"},
}
......@@ -3,15 +3,15 @@ defmodule DurationTest do
doctest Duration
test "parse durations" do
assert Duration.parse_duration("PT3S") == {:ok, %Duration{seconds: 3}}
assert Duration.parse_duration("P3M") == {:ok, %Duration{months: 3}}
assert Duration.parse_duration("PT3M") == {:ok, %Duration{minutes: 3}}
assert Duration.parse("PT3S") == {:ok, %Duration{seconds: 3}}
assert Duration.parse("P3M") == {:ok, %Duration{months: 3}}
assert Duration.parse("PT3M") == {:ok, %Duration{minutes: 3}}
assert Duration.parse_duration("P12341223T235759") ==
assert Duration.parse("P12341223T235759") ==
{:ok,
%Duration{years: 1234, months: 12, days: 23, hours: 23, minutes: 57, seconds: 59}}
assert Duration.parse_duration("P1234-12-23T23:57:59") ==
assert Duration.parse("P1234-12-23T23:57:59") ==
{:ok,
%Duration{years: 1234, months: 12, days: 23, hours: 23, minutes: 57, seconds: 59}}
end
......@@ -23,11 +23,17 @@ defmodule DurationTest do
end
test "errors" do
assert {:error, _} = Duration.parse_duration("")
assert {:error, _} = Duration.parse_duration("P12341331T246060")
assert {:error, _} = Duration.parse_duration("P12341232T246060")
assert {:error, _} = Duration.parse_duration("P12341231T256060")
assert {:error, _} = Duration.parse_duration("P12341231T246160")
assert {:error, _} = Duration.parse_duration("P12341231T246061")
assert {:error, _} = Duration.parse("")
assert {:error, _} = Duration.parse("P12341331T246060")
assert {:error, _} = Duration.parse("P12341232T246060")
assert {:error, _} = Duration.parse("P12341231T256060")
assert {:error, _} = Duration.parse("P12341231T246160")
assert {:error, _} = Duration.parse("P12341231T246061")
end
test "Timex.integration" do
{:ok, duration} = Duration.new("PT1S")
assert {:ok, [seconds: 1]} = Duration.to_timex_options(duration, :forward)
assert {:ok, [seconds: -1]} = Duration.to_timex_options(duration, :backward)
end
end