exercism/elixir/dancing-dots/lib/dancing_dots/animation.ex

50 lines
1.3 KiB
Elixir
Raw Normal View History

2024-03-08 08:36:14 +00:00
defmodule DancingDots.Animation do
@type dot :: DancingDots.Dot.t()
@type opts :: keyword
@type error :: any
@type frame_number :: pos_integer
@callback init(opts) :: {:ok, opts} | {:error, error}
@callback handle_frame(dot, frame_number, opts) :: dot
defmacro __using__(_) do
quote do
@behaviour DancingDots.Animation
def init(opts), do: {:ok, opts}
defoverridable init: 1
end
end
end
defmodule DancingDots.Flicker do
use DancingDots.Animation
@impl DancingDots.Animation
def handle_frame(%DancingDots.Dot{opacity: opacity} = dot, frame_number, _opts)
when rem(frame_number, 4) == 0,
do: %{dot | opacity: opacity / 2}
@impl DancingDots.Animation
def handle_frame(dot, _frame_number, _opts), do: dot
end
defmodule DancingDots.Zoom do
use DancingDots.Animation
@impl DancingDots.Animation
def init(opts) do
case Keyword.get(opts, :velocity) do
velocity when is_number(velocity) ->
{:ok, opts}
velocity ->
{:error,
"The :velocity option is required, and its value must be a number. Got: #{inspect(velocity)}"}
end
end
@impl DancingDots.Animation
def handle_frame(%DancingDots.Dot{radius: radius} = dot, frame_number, opts),
do: %{dot | radius: radius + (frame_number - 1) * Keyword.get(opts, :velocity)}
end