1
\$\begingroup\$

In a project I decided to parse a file and create functions during compilation to speed up rendering of a payroll template. I had (or still have?) a hard time grasping macros in Elixir so I started experimenting in a smaller scale. This was the winner and it also worked out in the project:

defmodule Swapper do
  defmodule Helper do
    defmacro make_custom_swapper(name, left, right) do
      quote bind_quoted: [n: name, l: left, r: right] do
        def unquote(:"#{n}_swapper")(unquote(l)), do: unquote(r)
        def unquote(:"#{n}_swapper")(unquote(r)), do: unquote(l)
      end
    end
  end

  defmodule Maker do
    require Helper
    defmacro generate_multiple_custom_swappers(pairs) do
      quote do
        for {n,l,r} <- unquote(pairs) do
          Helper.make_custom_swapper(n,l,r)
        end
      end
    end
  end
end

defmodule TestingGrounds do
  require Swapper.Maker
  require Swapper.Helper

  # testing Helper
  Swapper.Helper.make_custom_swapper(:lofa,:a,27)

  letters = String.split("abcdefghijklmnopqrstuvwxyz", "", trim: true)
  letter_swapper_list =
    for l <- letters do
      {:letter, l, String.upcase(l)}
    end

  things_to_swap = [{:eclipse, "moon", "sun"}|letter_swapper_list]

  # the big guns
  Swapper.Maker.generate_multiple_custom_swappers(things_to_swap)
end

I'm glad that it works but getting to this solution involved adding more stuff where I got lucky. It feels exactly like this when I first discovered &/1 that seemed like the solution to everything:

defmodule A do
  def massage(string) do
    string
    |> (&splitter/1).() # == splitter 
  end

  defp splitter(str) do
    str
    |> String.split("")
  end
end
\$\endgroup\$

migrated from stackoverflow.com Mar 23 '17 at 17:11

This question came from our site for professional and enthusiast programmers.

1
\$\begingroup\$

I like the simplicity of just using unquote at the module level to generate the defs, such as:

defmodule MyModule do
  def do_map_stuff(method, arg) do
    IO.inspect([method, arg])
  end

  Enum.each [:method1, :method2, :method3], fn method ->
    def unquote(method)(map) when is_map(map) do
    do_map_stuff(unquote(method), map)
  end

    def unquote(method)(arg)  do
    do_map_stuff(unquote(method), arg)
    end
  end
end
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.