Packages

fnord

0.8.60

AI code archaeology

Current section

Files

Jump to
fnord lib services once.ex
Raw

lib/services/once.ex

defmodule Services.Once do
@moduledoc """
This module provides a mechanism to perform actions only once, using a unique
key provided by the caller to determine whether the action has already been
performed this session.
"""
use Agent
@doc """
Starts the agent that keeps track of seen keys.
"""
def start_link() do
Agent.start_link(fn -> Map.new() end, name: __MODULE__)
end
@doc """
Checks if a key has been seen before. If the key has not been seen, it
returns `{:error, :not_seen}`. If the key has been seen, it returns `{:ok,
value}` where `value` is the value associated with the key, or `true` if no
value was specified.
"""
def get(key) do
Agent.get(__MODULE__, fn seen ->
with {:ok, value} <- Map.fetch(seen, key) do
{:ok, value}
else
_ -> {:error, :not_seen}
end
end)
end
@doc """
Marks a key as seen. If the key has not been seen before, it returns `true`
and updates the internal state. If the key has already been seen, it returns
`false` without updating the state.
"""
def set(key, value \\ true) do
Agent.get_and_update(__MODULE__, fn seen ->
if Map.has_key?(seen, key) do
{false, seen}
else
{true, Map.put(seen, key, value)}
end
end)
end
@doc """
Emits a warning (using `UI.warn/1`) if the message has not yet been emitted
during this session.
"""
def warn(msg) do
if set(msg) do
UI.warn(msg)
end
:ok
end
@doc """
Run the given zero-arity function only once per unique key.
Subsequent calls with the same key will be ignored.
"""
@spec run(term(), (-> any())) :: any() | :ignore
def run(key, fun) when is_function(fun, 0) do
case set(key) do
true -> fun.()
false -> :ignore
end
end
end