defmodule Crono do
@moduledoc "README.md"
|> File.read!()
|> String.split("<!-- MDOC !-->")
|> Enum.fetch!(1)
import Crono.Parser
import NimbleParsec
defparsecp(
:parse_input,
fields([
tag(minute(), :minute),
tag(hour(), :hour),
tag(day(), :day),
tag(month(), :month),
tag(weekday(), :weekday)
])
)
@doc """
Parses a cron expression, returning a `Crono.CronExpression` struct if successful.
## Examples
```elixir
iex> Crono.parse("* * * * *")
{:ok, %Crono.Expression{minute: :*, hour: :*, day: :*, month: :*, weekday: :*}}
iex> Crono.parse("5 * * * *")
{:ok, %Crono.Expression{minute: 5, hour: :*, day: :*, month: :*, weekday: :*}}
iex> Crono.parse("5/10 * * * *")
{:ok,%Crono.Expression{minute: [step: {5, 10}], hour: :*, day: :*, month: :*, weekday: :*}}
iex> Crono.parse("15-45 * * * *")
{:ok, %Crono.Expression{minute: [range: {15, 45}], hour: :*, day: :*, month: :*, weekday: :*}}
iex> Crono.parse("15,45 * * * *")
{:ok, %Crono.Expression{minute: [list: [15, 45]], hour: :*, day: :*, month: :*, weekday: :*}}
iex> Crono.parse("15,45 */6 14,28 * *")
{:ok, %Crono.Expression{minute: [list: [15, 45]], hour: [step: {:*, 6}], day: [list: [14, 28]], month: :*, weekday: :*}}
iex> Crono.parse("0 0 1 JAN *")
{:ok, %Crono.Expression{minute: 0, hour: 0, day: 1, month: 1, weekday: :*}}
iex> Crono.parse("0 0 * * WED")
{:ok, %Crono.Expression{minute: 0, hour: 0, day: :*, month: :*, weekday: 3}}
```
"""
def parse(input) do
parsed_input = parse_input(input)
case parsed_input do
{:ok, parsed_input, _, _, _, _} ->
expression =
Enum.reduce(parsed_input, %Crono.Expression{}, fn
{field, [:*]}, expression ->
Map.put(expression, field, :*)
{field, [value]}, expression when is_integer(value) ->
Map.put(expression, field, value)
{field, value}, expression ->
Map.put(expression, field, value)
end)
{:ok, expression}
{:error, error, _, _, _, _} ->
{:error, error}
end
end
@doc """
Like `Crono.parse/1`, but raises on error.
"""
def parse!(input) do
case parse(input) do
{:ok, %Crono.Expression{} = expression} -> expression
{:error, error} -> raise error
end
end
end