defmodule Envy do @moduledoc """ Provides explicit and auto loading of env files. ## Example The following will set the `FOO` environment variable with the value of `bar`. ``` foo=bar ``` You can define comments with `#` but can't use `#` in values without wrapping the value in double quotes. ``` foo="#bar" # Comment ``` """ @doc """ Loads the `.env` and the `Mix.env` specific env file. eg: If `Mix.env` is `test` then envy will attempt to load `.env.test`. """ def auto_load do Application.ensure_started(:mix) current_env = Mix.env |> to_string |> String.downcase [".env", ".env.#{current_env}"] |> load end @doc """ Loads a list of env files. """ def load(env_files) do for path <- env_files do if File.exists?(path) do File.read!(path) |> parse end end end @doc """ Parses env formatted file. """ def parse(content) do content |> get_pairs |> load_env end defp get_pairs(content) do content |> String.split("\n") |> Enum.reject(&blank_entry?/1) |> Enum.map(&parse_line/1) end defp parse_line(line) do [key, value] = line |> String.strip |> String.split("=") [key, parse_value(value)] end defp parse_value(value) do if String.starts_with?(value, "\"") do unquote_string(value) else value |> String.split("#", parts: 2) |> List.first end end defp unquote_string(value) do value |> String.split(~r{(? Enum.drop(1) |> List.first |> String.replace(~r{\\"}, ~S(")) end defp load_env(pairs) when is_list(pairs) do Enum.each(pairs, fn([key, value]) -> System.put_env(String.upcase(key), value) end) end defp blank_entry?(string) do string == "" end end