Current section

Files

Jump to
d_bounce lib d_bounce.ex
Raw

lib/d_bounce.ex

defmodule DBounce do
@moduledoc """
DBounce(https://www.npmjs.com/package/d-bounce) implementation in Elixir.
## Examples
iex> require Logger
Logger
iex> DBounce.start_link
{:ok, #PID<0.123.0>}
iex> DBounce.bounce(:task1, fn -> Logger.debug("Hello") end, 5000)
#PID<0.158.0>
~ after 5 seconds
09:06:07.173 [debug] Hello
iex> DBounce.bounce(:task1, fn -> Logger.debug("Hello") end, 5000)
#PID<0.160.0>
iex> DBounce.bounce(:task1, fn -> Logger.debug("World") end, 5000)
#PID<0.162.0>
~ after 5 seconds
09:06:46.517 [debug] World
# Only executed once!
# You can start with name
iex> DBounce.start_link(:bouncer1)
{:ok, #PID<0.165.0>}
iex> DBounce.bounce(:bouncer1, :task2, fn -> Logger.debug("Hello") end, 5000)
#PID<0.168.0>
~ after 5 seconds
09:09:40.054 [debug] Hello
"""
@doc false
# @spec start_link(Atom.t) :: GenServer.on_start
@spec start_link(Atom.t) :: GenServer.on_start
def start_link(name) do
Agent.start_link(fn -> Map.new end, name: name)
end
# @spec start_link() :: GenServer.on_start
def start_link() do
start_link(__MODULE__)
end
# @spec bounce(PID.t, any, Function.t, Integer.t)
def bounce(pid, name, function, delay) do
outer_self = self()
Agent.get_and_update(
pid,
fn map ->
case Map.get(map, name) do
nil -> nil
current_timer -> Process.cancel_timer(current_timer)
end
timer = Process.send_after(outer_self, nil, delay)
{map, Map.put(map, name, timer)}
end
)
receive do
_ ->
Agent.update(pid, fn map -> Map.delete(map, name) end)
function.()
end
end
# @spec bounce(Function.t, Atom.t, Integer.t)
def bounce(name, function, delay) do
bounce(__MODULE__, name, function, delay)
end
end