cover/Elixir.Tools.User.Exec.html

1 defmodule Tools.User.Exec do
2 import Code, only: [eval_string: 2]
3 import Enum, only: [map: 2, join: 2, at: 2]
4 import Log, only: [log: 5]
5 import String, only: [split: 2, trim: 1, to_atom: 1]
6 import Map, only: [to_list: 1]
7
8 @icon "🛠️"
9
10
:-(
def icon, do: @icon
11
12 def exec(tool, args) when tool != nil do
13 2 log(@icon, tool.name, ": ", args, :red)
14 2 result = first(tool.code, tool, args)
15 2 log("", "", "", result, :yellow)
16 2 result
17 end
18
19
:-(
def exec(nil, _args), do: {:error, "Tool not found"}
20
21
:-(
defp first([], _, _), do: "No code found"
22
23 defp first([code | _], tool, args) do
24 2 tool.imports |> modules() |> imports() |> plus(code) |> eval(args, tool.name)
25 end
26
27
:-(
defp modules(nil), do: []
28
:-(
defp modules(""), do: []
29 2 defp modules(text), do: split(text, ",") |> map(&trim/1)
30
31 defp imports(modules) when is_list(modules) do
32 2 ["import Tool.Index"] ++ map(modules, &imports/1)
33 end
34
35 2 defp imports(module), do: "import #{module}"
36
37 defp plus(imports, code) do
38 2 "\n#{join(imports, "\n")}\n\n#{code}\n"
39 end
40
41 defp eval(text, args, name) do
42 attempt(text, args)
43 2 |> result(name)
44 end
45
46 2 defp attempt(text, args) do
47 {:ok, run(text, args)}
48 rescue
49
:-(
error -> {:error, error, __STACKTRACE__}
50 end
51
52 2 defp result({:ok, value}, _), do: value
53
:-(
defp result({:error, error, stack}, name), do: failed(error, stack, name)
54
55 defp run(text, args) do
56 2 bindings = to_list(args) |> map(&atomize/1)
57 2 result(eval_string(text, bindings))
58 end
59
60
:-(
defp atomize({k, v}) when is_binary(k), do: {to_atom(k), v}
61
:-(
defp atomize({k, v}), do: {k, v}
62
63 2 defp result({res, _}), do: res
64
65 defp failed(%CompileError{description: desc}, _, name),
66
:-(
do: "#{name} needs #{var(desc)}"
67
68
:-(
defp failed(error, stack, _), do: reraise(error, stack)
69
70 defp var(desc) do
71
:-(
at(split(desc, "\""), 1)
72 end
73 end
Line Hits Source