5

I have three identical methods in my module, that do (almost) exactly the same thing. Instead of repeating the function definitions, I am trying to define them once to keep code minimal and same for all of them.

So far I've tried using Code.eval_string:

defmodule MyModule do
  Enum.each ~w(method1 method2 method3), fn method ->
    @method method

    Code.eval_string """
      def #{@method}(map) when is_map(map) do
        do_map_stuff(:#{@method}, map)
      end

      def #{@method}(arg) do
        do_other_stuff(:#{@method}, arg)
      end
    """
  end

  ## Other Methods

end

but this throws ArgumentError:

Compiling 1 file (.ex)
** (ArgumentError) cannot invoke def/2 outside module
    (elixir) lib/kernel.ex:4297: Kernel.assert_module_scope/3
    (elixir) lib/kernel.ex:3299: Kernel.define/4
    (elixir) expanding macro: Kernel.def/2
    nofile:1: (file)

I think quote/unquote might be the way to go, but I'm not exactly sure how to do this using them (I've already read the Meta Guide on the Elixir website).

1 Answer 1

4

Something like this?

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
Sign up to request clarification or add additional context in comments.

1 Comment

I updated it to use atoms instead of strings which suit my case better (and also look much more cleaner and readable!)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.