2017-05-20 8 views
1

内の動的な関数を定義する関数の値が利用できない理由をdefmacroの内側に機能しますが理解できない関数の内部自体エリキシルは、私が動的に定義しようとしていますマクロ

defmacro __using__(_) do 
    Enum.each ~w(public private), fn value -> 
    def unquote(:"make_#{value}")(user = %User{}) do 
     %{user | privacy: value} 
    end 
    end 
end 

エリクシールはvalue()にデフォルトvalueで展開した後、そこにいることを述べていますそのような機能はありません

答えて

0

defの周りにquoteがありません。また、defの中のマップ更新式の値を引用符で囲む必要があります。

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 

はテスト::

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"} 

編集:コメントで要求された変更を:そして最後に、あなたは__using__/1が構築ASTを返すように、ここでは代わりのEnum.eachEnum.mapを使用する必要があります

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"} 
+0

しかし、動的に生成された 'def'と同じレベルに関数を追加する必要がある場合はどうすればよいですか? – Moldaone

+0

'quote'の中に任意の数の' def'を置くことができます。 – Dogbert

+0

問題は、 '__using__'関数が定義のASTリストを期待しているので、複数の' quote'を宣言すると、最後のものだけが取られます。 – Moldaone

関連する問題