elixirtypespec

How do I write a spec for a function that contains special characters?


I have some macros that define functions that have special characters. Specifically ":" and ".". Is it possible to write a spec definition for functions with those characters in it?

defmodule UniqueCharacters do
  defmacro make_wild_function_name do
    function_name = String.to_atom("baz:foo.bar")
    quote do
      def unquote(function_name)(), do: :ok
    end
  end
end

defmodule TestSpec do
  import UniqueCharacters

  #This next line doesn't work
  @spec baz:foo.bar() :: :ok
  make_wild_function_name()
end

This produces the following error:

** (SyntaxError) lib/unique_characters.ex:14: keyword argument must be followed by space after: baz:

    (elixir) lib/kernel/parallel_compiler.ex:229: anonymous fn/4 in Kernel.ParallelCompiler.spawn_workers/7

Is there a way to escape the characters in the function spec so that this will compile without removing the spec? I can change the ":" to "_" or something more well behaved but the "." is basically non-negotiable.


Solution

  • Can you specify the typespec in your macro? If so, this seems to work fine:

    defmodule UniqueCharacters do
      defmacro make_wild_function_name do
        function_name = String.to_atom("baz:foo.bar")
        quote do
          @spec unquote(function_name)() :: :ok
          def unquote(function_name)(), do: :ok
        end
      end
    end
    
    defmodule TestSpec do
      import UniqueCharacters
    
      make_wild_function_name()
    end
    

    I feel like bundling the typespec with the definition makes the most sense; is that enough?

    Edit: Looks like this also works, although kinda messy:

    defmodule UniqueCharacters do
      defmacro make_wild_function_name do
        function_name = String.to_atom("baz:foo.bar")
        quote do
          def unquote(function_name)(), do: :ok
        end
      end
    end
    
    defmodule TestSpec do
      import UniqueCharacters
    
      @spec unquote(:'baz:foo.bar')() :: :ok
      make_wild_function_name()
    end