Skip to content

Instantly share code, notes, and snippets.

@andersonmcook
Last active June 20, 2018 15:33
Show Gist options
  • Select an option

  • Save andersonmcook/da201f7c665de5f317aab7a3acc5770b to your computer and use it in GitHub Desktop.

Select an option

Save andersonmcook/da201f7c665de5f317aab7a3acc5770b to your computer and use it in GitHub Desktop.
Naïve approaches to cross-module constants not using config
# use Mix.Config
# config :constants,
# :some_string: "some_string",
# :range_i_like: 1..5,
# :a_map: %{letters: ~w(a b c)}
defmodule Constants.Macro do
# Take code and convert to AST
# Inject name into quoted expression as the name of the macro
# Inject value into quoted expression as the value the macro returns
defmacro create(name, value) do
quote do
defmacro unquote(name) do
unquote(value)
end
end
end
# non-literal range in guard should be escaped with Macro.escape/2
defmacro create_escaped(name, value) do
quote do
defmacro unquote(name) do
unquote(Macro.escape(value))
end
end
end
end
defmodule Constants do
alias Constants.Macro, as: CM
require CM
CM.create(some_string, "some_string")
CM.create_escaped(range_i_like, 1..5)
CM.create_escaped(a_map, %{letters: ~w(a b c)})
end
defmodule Impl.A do
alias Constants, as: C
# require module to use its macros
require C
# or import Constants
# or import Constants, only: :macros
def match(C.some_string), do: "you gave me that string I like"
def match(_), do: "nooo"
def in_range?(n) when n in C.range_i_like, do: "#{n} is good, I like it"
def in_range?(_), do: "buh"
def cap(letter) do
case letter in C.a_map().letters do
true -> letter |> String.upcase |> Kernel.<>(" is all grown up")
false -> "i will not capitalize #{letter}"
end
end
def types do
IO.inspect IEx.Info.info(C.some_string)
IO.inspect IEx.Info.info(C.range_i_like)
IO.inspect IEx.Info.info(C.a_map)
IO.inspect IEx.Info.info(C.a_map.letters)
end
end
defmodule Constants.Using do
defmacro __using__(_) do
quote do
@some_string "some_string"
@range_i_like 1..5
@a_map %{letters: ~w(a b c)}
end
end
end
defmodule Impl.B do
use Constants.Using
def match(@some_string), do: "you gave me that string I like a second time"
def match(_), do: "nooo, again"
def in_range?(n) when n in @range_i_like, do: "#{n} is still cool with me"
def in_range?(_), do: "buh, again"
def cap(letter) do
case letter in @a_map.letters do
true -> letter |> String.upcase |> Kernel.<>(" is now a big boy")
false -> "again, i will not capitalize #{letter}"
end
end
def types do
IO.inspect IEx.Info.info(@some_string)
IO.inspect IEx.Info.info(@range_i_like)
IO.inspect IEx.Info.info(@a_map)
IO.inspect IEx.Info.info(@a_map.letters)
end
end
defmodule Doublecheck do
use Constants.Using
require Constants
def all_good? do
IO.inspect Constants.some_string === @some_string and
Constants.range_i_like === @range_i_like and
Constants.a_map === @a_map, label: "these are the same"
end
end
IO.puts ""
IO.inspect Impl.A.match("some_string"), label: "Impl.A.match(\"some_string\")"
IO.inspect Impl.A.match("nah"), label: "Impl.A.match(\"nah\")"
IO.inspect Impl.B.match("some_string"), label: "Impl.B.match(\"some_string\")"
IO.inspect Impl.B.match("nah"), label: "Impl.B.match(\"nah\")"
IO.puts ""
IO.inspect Impl.A.in_range?(3), label: "Impl.A.in_range?(3)"
IO.inspect Impl.A.in_range?(9), label: "Impl.A.in_range?(9)"
IO.inspect Impl.B.in_range?(3), label: "Impl.B.in_range?(3)"
IO.inspect Impl.B.in_range?(9), label: "Impl.B.in_range?(9)"
IO.puts ""
IO.inspect Impl.A.cap("a"), label: "Impl.A.cap(\"a\")"
IO.inspect Impl.A.cap("d"), label: "Impl.A.cap(\"d\")"
IO.inspect Impl.B.cap("a"), label: "Impl.B.cap(\"a\")"
IO.inspect Impl.B.cap("d"), label: "Impl.B.cap(\"d\")"
IO.puts ""
Doublecheck.all_good?()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment