-
-
Save seeekr/9f781ee081836e081638df209ac60928 to your computer and use it in GitHub Desktop.
Elixir: override Mix config with environment variables
This file contains 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 Confix do | |
defmacro __using__(app: app_name) do | |
quote do | |
import unquote(__MODULE__), only: :macros | |
@confix_app unquote(app_name) | |
end | |
end | |
defmacro cfg(key, type \\ :string) do | |
quote do | |
def unquote(key)() do | |
unquote(__MODULE__).get(@confix_app, __MODULE__, unquote(key), unquote(type)) | |
end | |
end | |
end | |
def get(app_name, module, key, type \\ :string) do | |
case System.get_env(env_var(module, key)) do | |
nil -> Application.get_env(app_name, module)[key] | |
str -> parse_val(str, type) | |
end | |
end | |
def get_all(app_name) do | |
Application.get_all_env(app_name) | |
|> Enum.map(fn {module, _} -> {module_name(module), get_module(app_name, module)} end) | |
|> Enum.into(Map.new) | |
end | |
def get_module(app_name, module) do | |
Application.get_env(app_name, module) | |
|> Enum.map(fn {key, _} -> {key, get(app_name, module, key)} end) | |
|> Enum.into(Map.new) | |
end | |
defp env_var(module, key) do | |
String.upcase "#{stringify module}_#{stringify key}" | |
end | |
defp module_name(module) do | |
module | |
|> to_string | |
|> String.replace_leading("Elixir.", "") | |
end | |
defp stringify(atom) do | |
atom | |
|> module_name | |
|> String.replace(".", "_") | |
|> String.replace_trailing("?", "") | |
end | |
defp parse_val(str, type) do | |
fun = | |
case type do | |
:atom -> &String.to_atom/1 | |
:boolean -> &to_boolean/1 | |
:float -> &String.to_float/1 | |
:integer -> &String.to_integer/1 | |
{:list, element_type} -> &to_list(&1, element_type) | |
{:set, element_type} -> &to_set(&1, element_type) | |
:string -> &(&1) | |
end | |
fun.(str) | |
end | |
defp to_boolean(str) do | |
String.downcase(str) == "true" | |
end | |
defp to_list(str, element_type) do | |
str |> String.split(",") |> Enum.map(&parse_val(&1, element_type)) | |
end | |
defp to_set(str, element_type) do | |
str |> to_list(element_type) |> MapSet.new | |
end | |
end |
This file contains 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 Foo do | |
use Config, app: :foo_app | |
cfg :disable_foo?, :boolean | |
cfg :bar_delay, :integer | |
cfg :baz_name | |
cfg :blahs, {:list, :float} | |
cfg :blerks, {:set, :atom} | |
def print_stuff do | |
IO.puts "Disable foo? #{disable_foo?}" | |
IO.puts "Bar delay: #{bar_delay}" | |
IO.puts "Baz name: #{baz_name}" | |
IO.puts "Blahs: #{inspect blahs}" | |
IO.puts "Blerks: #{inspect blerks}" | |
end | |
end | |
##### | |
# Example config.exs | |
use Mix.Config | |
config :foo_app, Foo, | |
disable_foo?: false, | |
bar_delay: 42, | |
baz_name: "Baz, James Baz", | |
blahs: [1.23, 4.56, 7.89], | |
blerks: MapSet.new([:green_eggs, :ham]) | |
##### | |
# Example environment variables | |
# FOO_DISABLE_FOO=true | |
# FOO_BAR_DELAY=747 | |
# FOO_BAZ_NAME='James T. Kirk' | |
# FOO_BLAHS=9.87,6.54,3.21 | |
# FOO_BLERKS=spam,jam |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Macro-defined functions in target module are also public now, since I find it more convenient to configure some top-level module with general stuff and then access that config from other modules.