2015-05-28 10 views
29

Ich möchte eine Funktion Namen dynamisch erstellen. Ich schrieb dieses MakroWie erstellt man einen dynamischen Funktionsnamen mit Elixir-Makro?

defmacro generate_dynamic(name) do 
    quote do 
    def add_(unquote(name)) do 
    end 
    end 
end 

Und ich habe es wie folgt aus:

defmodule AnotherModule do 
    generate_dynamic :animal 
end 

Nun erhalte ich nur AnotherModule.add_ Funktion definiert, während ich AnotherModule.add_animal Funktion erwarten.

Antwort

36

Um dies zu erreichen, können Sie :add_ dem Namen voranstellen, bevor Sie nicht quotieren. Auch die Klammern nach dem Methodennamen sind in diesem Fall erforderlich, um Mehrdeutigkeiten zu vermeiden. Dies sollte den Trick:

defmacro generate_dynamic(name) do 
    quote do 
    def unquote(:"add_#{name}")() do 
     # ... 
    end 
    end 
end 
17

Manchmal als nützliche Verknüpfung können Sie das gleiche Ergebnis inline erreichen, ohne einen Makro schreibt ein unquote Fragment verwenden.

defmodule Hello do 
    [:alice, :bob] |> Enum.each fn name -> 
    def unquote(:"hello_#{name}")() do 
     IO.inspect("Hello #{unquote(name)}") 
    end 
    end 
end 

Hello.hello_bob # => "Hello bob" 
Hello.hello_alice # => "Hello alice" 
+1

I 'dachte unquote' funktionierte nur von ** in einem Makro **. Wie funktioniert es in einer anonymen Funktion? – asymmetric

+7

Ich antworte selbst: unquote und [unquote Fragmente] (http://elixir-lang.org/docs/stable/elixir/Kernel.SpecialForms.html) sind zwei verschiedene Dinge. – asymmetric

+0

Jusy, um das oben genannte zu verdeutlichen: unquote-Fragmente sind "unquote", die außerhalb eines "quote" -Blocks liegen. – asymmetric

5

Ich habe diese gleiche Art von Dingen in einem Kern und Mimik Rubys attr_accessor zu versuchen:

defmodule MacroExp do 
    defmacro attr_accessor(atom) do 
    getter = String.to_atom("get_#{atom}") 
    setter = String.to_atom("set_#{atom}") 
    quote do 
     def unquote(getter)(data) do 
     data |> Map.from_struct |> Map.get(unquote(atom)) 
     end 
     def unquote(setter)(data, value) do 
     data |> Map.put(unquote(atom), value) 
     end 
    end 
    end 

    defmacro attr_reader(atom) do 
    getter = String.to_atom("get_#{atom}") 
    quote do 
     def unquote(getter)(data) do 
     data |> Map.from_struct |> Map.get(unquote(atom)) 
     end 
    end 
    end 
end 


defmodule Calculation do 
    import MacroExp 
    defstruct first: nil, second: nil, operator: :plus 

    attr_accessor :first # defines set_first/2 and get_first/1 
    attr_accessor :second # defines set_second/2 and get_second/1 
    attr_reader :operator # defines set_operator/2 and get_operator/1 

    def result(%Calculation{first: first, second: second, operator: :plus}) do 
    first + second 
    end 
end 

https://gist.github.com/rcdilorenzo/77d7a29737de39f0cd84

Verwandte Themen