defmodule Tempus.Sigils do @moduledoc "Handy sigils to instantiate `Tempus.Slot` and `Tempus.Slots`" alias Tempus.Slot @doc ~S""" Handles the sigil `~I` for `Tempus.Slot`. It returns a slot without interpolations and without escape characters, except for the escaping of the closing sigil character itself. ## Examples iex> import Tempus.Sigils iex> ~I(2021-03-30T06:35:40Z|2021-03-30T06:36:00Z) %Tempus.Slot{from: ~U[2021-03-30 06:35:40Z], to: ~U[2021-03-30 06:36:00Z]} iex> ~I(2021-03-30|2021-03-31)d %Tempus.Slot{from: ~U[2021-03-30 00:00:00.000000Z], to: ~U[2021-03-31 23:59:59.999999Z]} iex> ~I(2021-03-30)d %Tempus.Slot{from: ~U[2021-03-30 00:00:00.000000Z], to: ~U[2021-03-30 23:59:59.999999Z]} """ defmacro sigil_I({:<<>>, _, [binary]}, modifiers) when is_binary(binary) do by_mod = fn ?d -> Date ?t -> Time ?u -> DateTime end from_iso = modifiers |> case do [] -> [DateTime, DateTime] [ft] when ft in 'dtu' -> List.duplicate(by_mod.(ft), 2) [f, t] = mods when f in 'dtu' and t in 'dtu' -> Enum.map(mods, by_mod) end |> Enum.map(&Function.capture(&1, :from_iso8601, 1)) result = binary |> String.split("|") |> Enum.zip(from_iso) |> Enum.map(fn {value, mapper} -> case mapper.(value) do {:ok, result} -> Slot.wrap(result) {:ok, result, _} -> Slot.wrap(result) {:error, error} -> raise CompileError, file: __CALLER__.file, line: __CALLER__.line, description: inspect(error) end end) |> Slot.join() |> Macro.escape() quote(generated: true, location: :keep, do: unquote(result)) end end