View Source Nvir.Parser behaviour (Nvir v0.10.0)

A simple .env file parser.

Summary

Callbacks

Must rturn a list of variable definitions in a result tuple.

Functions

Returns a list of {key, value} for all variables in the given content.

Types

buffer()

@type buffer() :: buffer()

key()

@type key() :: String.t()

parser()

@type parser() :: (buffer() ->
               {:ok, term(), buffer()} | {:error, {atom(), term(), buffer()}})

value()

@type value() :: String.t()

variable()

@type variable() :: {key(), binary() | [binary() | {:var, binary()}]}

Callbacks

parse_file(path)

@callback parse_file(path :: String.t()) :: {:ok, [variable()]} | {:error, Exception.t()}

Must rturn a list of variable definitions in a result tuple.

Variables definitions are defined as lists of {key, value} tuples where the value is either a string or a list of string and {:var, string} tuples.

For instance, given this file content:

# .env
WHO=World
GREETING=Hello $WHO!

The parse_file/1 callback should return the following:

{:ok,
  [
    {"WHO", "World"},
    {"GREETING", ["Hello ", {:var, "WHO"}, "!"]}
  ]}

There is no need to handle different interpolation scenarios at the parser level. This env file:

PATH=b
PATH=$PATH:c
PATH=a:$PATH

Should produce the following:

{:ok,
  [
    {"PATH", "b"},
    {"PATH", [{:var, "PATH"}, ":c"]},
    {"PATH", ["a:", {:var, "PATH"}]}
  ]}

Interpolation will be handled by Nvir.dotenv!/1 when variables will be applied.

Functions

parse(input)

@spec parse(binary()) :: {:ok, [variable()]} | {:error, Exception.t()}

Returns a list of {key, value} for all variables in the given content.

This function only parses strings, and will not attempt to read from a path.

Each returned value is either a string, or a list of chunks that are either a binary or a {:var, name} tuple. Those values can be used with Nvir.interpolate_var/2 by providing a resolver calback that returns the value of previous variables.

Resolver example

iex> file_contents = "GREETING=$INTRO $WHO!"
iex> {:ok, [{"GREETING", template}]} = Nvir.Parser.parse(file_contents)
iex> resolver = fn
...>   "INTRO" -> "Hello"
...>   "WHO" -> "World"
...> end
iex> Nvir.interpolate_var(template, resolver)
"Hello World!"

When working with the system env you will likely use &System.get_env(&1, "") as a resolver. It is common to use an empty string for undefined system variables, but you can of course raise from your function if it better suits your needs.