Packages

Use Elixir maps as a document storage format.

Current section

Files

Jump to
eon lib eon.ex
Raw

lib/eon.ex

defmodule EON do
def from_file(filename), do: load_file(filename, false, nil)
def from_file_unsafe(filename), do: load_file(filename, true, [])
def from_file_unsafe(filename, bindings), do: load_file(filename, true, bindings)
def load_file(filename, allow_unsafe, bindings) do
{:ok, file} = File.read(filename)
safe = check_if_safe(file)
cond do
allow_unsafe ->
{contents, results} = Code.eval_string(file, bindings)
{:ok, Map.merge(%{}, contents)}
safe ->
{contents, results} = Code.eval_string(file, [])
{:ok, Map.merge(%{}, contents)}
true ->
{:error, "#{filename} contains unsafe data. Load with EON.from_file_unsafe to ignore this."}
end
end
def to_file(map, filename) do
map = Map.merge(%{}, map)
contents = Macro.to_string(quote do: unquote(map))
{:ok, file} = File.open(filename, [:write])
IO.binwrite(file, contents)
{:ok, filename}
end
def check_if_safe(file) do
{:ok, contents} = Code.string_to_quoted(file)
elem(contents, 2)
|> Enum.map(&is_safe?/1)
|> List.flatten
|> Enum.all?(&(&1))
end
def is_safe?(value) do
case value do
{key, {expression, line, value}} ->
if expression != :{} and expression != :%{} do
false
else
value
|> Enum.filter(&(is_tuple(&1)))
|> Enum.map(&is_safe?/1)
end
{key, value} when is_list(value) ->
only_tuples = value |> Enum.filter(&(is_tuple(&1)))
results = only_tuples |> Enum.map(&is_safe?/1)
Enum.all?(results, &(&1))
{expression, line, value} ->
expression == :{} or expression == :%{}
_ ->
true
end
end
end