Skip to content

Commit

Permalink
remove warnings for multi functions
Browse files Browse the repository at this point in the history
  • Loading branch information
smoes committed May 28, 2024
1 parent 168f382 commit be95c42
Show file tree
Hide file tree
Showing 3 changed files with 43 additions and 10 deletions.
40 changes: 31 additions & 9 deletions lib/efx.ex
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,11 @@ defmodule Efx do
defmacro __before_compile__(_) do
caller = __CALLER__.module
effects = Module.get_attribute(caller, :effects, [])
effect_impls = Module.get_attribute(caller, :effect_impls, [])

effect_impls =
Module.get_attribute(caller, :effect_impls, [])
|> Enum.map(fn {_, _, impl} -> impl end)

specs = Module.get_attribute(caller, :spec, [])

Module.delete_attribute(caller, :effects)
Expand Down Expand Up @@ -179,16 +183,24 @@ defmodule Efx do

# we store the implementations here to put them all together in the end
# to avoid warnings about non grouped definitions of the same function
Module.put_attribute(module, :effect_impls, impl)
arity = Enum.count(args)

already_exists? = already_exists?(module, name, arity)

unless already_exists? do
Module.put_attribute(module, :effect_impls, {name, Enum.count(args), impl})
end

if Mix.env() == :test do
quote do
@impl unquote(module)
def unquote(alt_fun) do
if EfxCase.MockState.mocked?(unquote(module)) do
EfxCase.MockState.call(unquote(module), unquote(name), unquote(alt_args))
else
Kernel.apply(__MODULE__, unquote(impl_name), unquote(alt_args))
unless already_exists? do
quote do
@impl unquote(module)
def unquote(alt_fun) do
if EfxCase.MockState.mocked?(unquote(module)) do
EfxCase.MockState.call(unquote(module), unquote(name), unquote(alt_args))
else
Kernel.apply(__MODULE__, unquote(impl_name), unquote(alt_args))
end
end
end
end
Expand All @@ -207,4 +219,14 @@ defmodule Efx do

@spec spec_arity(tuple()) :: arity()
defp spec_arity({:"::", _, [{_, _, args} | _]}), do: Enum.count(args)

@spec already_exists?(module(), atom(), arity()) :: boolean()
def already_exists?(module, name, arity) do
Enum.any?(
Module.get_attribute(module, :effect_impls),
fn {other_name, other_arity, _} ->
name == other_name && arity == other_arity
end
)
end
end
2 changes: 1 addition & 1 deletion mix.exs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
defmodule Efx.MixProject do
use Mix.Project

@version "0.1.5"
@version "0.1.6"
@github_page "https://github.com/bravobike/efx"

def project do
Expand Down
11 changes: 11 additions & 0 deletions test/support/efx_example.ex
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,15 @@ defmodule EfxCase.EfxExample do
defeffect fun_with_wildcard(_arg) do

Check warning on line 17 in test/support/efx_example.ex

View workflow job for this annotation

GitHub Actions / Test on OTP 25.0.4 / Elixir 1.14.0

got "@impl EfxCase.EfxExample" for function fun_with_wildcard/1 but this behaviour does not specify such callback. There are no known callbacks, please specify the proper @behaviour and make sure it defines callbacks
[1, 2, 3, 4, 5]
end

# we use this to see if functions with multiple
# implementations work properly at compile time
@spec multi_fun(any()) :: list()
defeffect multi_fun([] = list) do

Check warning on line 24 in test/support/efx_example.ex

View workflow job for this annotation

GitHub Actions / Test on OTP 25.0.4 / Elixir 1.14.0

got "@impl EfxCase.EfxExample" for function multi_fun/1 but this behaviour does not specify such callback. There are no known callbacks, please specify the proper @behaviour and make sure it defines callbacks
list
end

defeffect multi_fun(string) do
string
end
end

0 comments on commit be95c42

Please sign in to comment.