cover/Elixir.Tools.User.Validate.html

1 defmodule Tools.User.Validate do
2 import Code, only: [string_to_quoted: 1]
3 import Enum, only: [map: 2, reduce: 3, find: 2, member?: 2, all?: 2]
4 import String, only: [split: 2, trim: 1]
5 import Tools.User.Ast, only: [bound: 1, refs: 1]
6
7 def check(tool) do
8 tool[:code]
9 |> process(tool[:params], tool[:name])
10 10 |> unwrap(tool)
11 end
12
13
:-(
defp process([], _, _), do: :ok
14
:-(
defp process(nil, _, _), do: :ok
15 10 defp process(_, nil, _), do: :ok
16
:-(
defp process(_, "", _), do: :ok
17
18 defp process(code, params, name) do
19
:-(
allowed = split(params, ",") |> map(&trim/1)
20
:-(
reduce(code, :ok, &fold(&1, allowed, name, &2))
21 end
22
23
:-(
defp fold(_code, _allowed, _name, {:error, _} = err), do: err
24
25 defp fold(code, allowed, name, :ok) do
26
:-(
code |> string_to_quoted() |> scan(allowed, name)
27 end
28
29
:-(
defp scan({:ok, ast}, allowed, name), do: vet(ast, allowed, name)
30
:-(
defp scan({:error, _}, _, _), do: :ok
31
32 defp vet(ast, allowed, name) do
33
:-(
bad = find(refs(ast), &bad?(&1, allowed, bound(ast)))
34
:-(
resolve(bad, name)
35 end
36
37 defp bad?(var, allowed, bound) do
38
:-(
[allowed, bound] |> all?(&skip?(&1, var))
39 end
40
41
:-(
defp skip?(list, var), do: not member?(list, var)
42
43
:-(
defp resolve(nil, _), do: :ok
44
:-(
defp resolve(undefined, name), do: {:error, name, undefined}
45
46 10 defp unwrap(:ok, tool), do: tool
47
48 defp unwrap({:error, name, var}, _tool) do
49
:-(
raise RuntimeError, "#{name} undefined variable #{var}"
50 end
51 end
Line Hits Source