You're missing a quote around the def. You also need to unquote the value in the Map update expression inside the def. And lastly you need to use Enum.map here instead of Enum.each so that __using__/1 returns the AST constructed:
defmacro __using__(_) do
Enum.map ~w(public private), fn value ->
quote do
def unquote(:"make_#{value}")(user = %User{}) do
%{user | privacy: unquote(value)}
end
end
end
end
Test:
defmodule User do
defstruct [:privacy]
end
defmodule A do
defmacro __using__(_) do
Enum.map ~w(public private), fn value ->
quote do
def unquote(:"make_#{value}")(user = %User{}) do
%{user | privacy: unquote(value)}
end
end
end
end
end
defmodule B do
use A
end
iex(1)> %User{} |> B.make_public
%User{privacy: "public"}
Edit: Change requested in comments:
defmacro __using__(_) do
Enum.map ~w(public private), fn value ->
quote do
def unquote(:"make_#{value}")(user = %User{}) do
%{user | privacy: unquote(value)}
end
def unquote(:"make_#{String.upcase(value)}")(user = %User{}) do
%{user | privacy: unquote(String.upcase(value))}
end
end
end
end
iex(1)> %User{} |> B.make_public
%User{privacy: "public"}
iex(2)> %User{} |> B.make_PUBLIC
%User{privacy: "PUBLIC"}
iex(3)> %User{} |> B.make_private
%User{privacy: "private"}
iex(4)> %User{} |> B.make_PRIVATE
%User{privacy: "PRIVATE"}