Created
July 29, 2020 07:12
-
-
Save lud/2eedbea6e10232c94398918fc1a79c84 to your computer and use it in GitHub Desktop.
Elixir uppercase constants with macros
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
defmodule Constants.Compiler do | |
@moduledoc false | |
defmacro __using__(_) do | |
quote do | |
Module.register_attribute(__MODULE__, :const_def, accumulate: true) | |
import unquote(__MODULE__), only: [const: 2] | |
@before_compile unquote(__MODULE__) | |
end | |
end | |
defmacro const(key, value) when is_binary(key) do | |
quote do | |
@const_def {unquote(key), unquote(value)} | |
end | |
end | |
defmacro const(key, value) do | |
raise ArgumentError, "Constants keys must be binaries, got: #{inspect(key)}" | |
end | |
defmacro __before_compile__(env) do | |
quote location: :keep, unquote: false do | |
for {key, value} <- Module.get_attribute(__MODULE__, :const_def) do | |
# escaping so the value can be unquoted in the macro block | |
value = Macro.escape(value) | |
defmacro sigil_x({:<<>>, _, [unquote(key)]}, []) do | |
# escaping so we return a quoted expression | |
Macro.escape(unquote(value)) | |
end | |
end | |
defmacro sigil_x({:<<>>, _, [key]}, []) do | |
raise ArgumentError, "Undefined constant #{key}" | |
end | |
defmacro sigil_x(key, []) do | |
raise ArgumentError, "Invalid constant key #{key}" | |
end | |
defmacro sigil_x(_, [some | _]) do | |
raise ArgumentError, "Constant sigil does not accept modifiers" | |
end | |
end | |
end | |
end | |
defmodule Constants do | |
use Constants.Compiler | |
defmacro __using__(_) do | |
quote do | |
import unquote(__MODULE__), only: [sigil_x: 2] | |
end | |
end | |
const("A_VALUE", 123) | |
const("A_CALL", System.cwd()) | |
end | |
defmodule Constants.Test do | |
use Constants | |
def test do | |
{~x(A_CALL), ~x(A_VALUE)} | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment