1
votes

I'm messing around with macros in elixir purely for fun and not profit :). So I have a comma separated string and I want to dynamically create a function with that list as arguments i.e.

defmacro  __using__(opts) do
  args = "a,b,c"
  quote do
    def test(unquote(args)) do
      IO.inspect("#{a},#{b},#{c}")
    end
  end
end

The problem I have is that the method created is: test("1,2,3") and not test(1,2,3) for obvious reasons. So how do I convert a string into a method argument?

Chris

1

1 Answers

1
votes

There's probably a better way but one way to convert "a,b,c" to something that can be injected into def's argument list would be to use Code.string_to_quoted!/1 and unquote_splicing:

defmacro  __using__(_opts) do
  args = "a,b,c"
  args = Code.string_to_quoted!("[#{args}]")
  quote do
    def test(unquote_splicing(args)) do
      IO.inspect(unquote(args))
    end
  end
end

Note that due to hygiene, you'll have to use args to access the variables and you cannot directly access a, b, or c inside the def.

Full Example:

defmodule Macros do
  defmacro  __using__(_opts) do
    args = "a,b,c"
    args = Code.string_to_quoted!("[#{args}]")
    quote do
      def test(unquote_splicing(args)) do
        IO.inspect(unquote(args))
      end
    end
  end
end

defmodule Main do
  use Macros

  def main do
    test("a", "b", "c")
    test(1, 2, 3)
  end
end

Main.main

Output:

["a", "b", "c"]
[1, 2, 3]