| 1 |
|
defmodule Tools.User.Cfg do |
| 2 |
|
import Enum, only: [join: 2, map: 2, reduce: 3] |
| 3 |
|
import File, only: [read!: 1] |
| 4 |
|
import List, only: [first: 1] |
| 5 |
|
import Map, only: [new: 2, put: 3] |
| 6 |
|
import Regex, only: [replace: 3, scan: 3] |
| 7 |
|
import String, only: [split: 2, to_atom: 1, trim: 1] |
| 8 |
|
|
| 9 |
|
@code ~r/```elixir\n(.*?)\n```/s |
| 10 |
|
|
| 11 |
|
def parse(path) do |
| 12 |
10 |
path |> read!() |> sever() |> extract() |
| 13 |
|
end |
| 14 |
|
|
| 15 |
|
defp sever(content) do |
| 16 |
10 |
split(content, "---") |
| 17 |
|
end |
| 18 |
|
|
| 19 |
|
defp extract([_, header | rest]) do |
| 20 |
|
yaml(header) |
| 21 |
|
|> atomize() |
| 22 |
|
|> enrich(rest) |
| 23 |
10 |
|> finish(rest) |
| 24 |
|
end |
| 25 |
|
|
| 26 |
|
defp enrich(cfg, rest) do |
| 27 |
10 |
put(cfg, :code, blocks(join(rest, "---"))) |
| 28 |
|
end |
| 29 |
|
|
| 30 |
|
defp finish(cfg, rest) do |
| 31 |
10 |
put(cfg, :body, body(join(rest, "---"))) |
| 32 |
|
end |
| 33 |
|
|
| 34 |
|
defp blocks(markdown) do |
| 35 |
|
scan(@code, markdown, capture: :all_but_first) |
| 36 |
10 |
|> map(&first/1) |
| 37 |
|
end |
| 38 |
|
|
| 39 |
|
defp body(markdown) do |
| 40 |
10 |
replace(@code, markdown, "") |> trim() |
| 41 |
|
end |
| 42 |
|
|
| 43 |
|
defp atomize(map) do |
| 44 |
10 |
map |> new(fn {k, v} -> {to_atom(k), v} end) |
| 45 |
|
end |
| 46 |
|
|
| 47 |
|
defp yaml(header) do |
| 48 |
10 |
split(trim(header), "\n") |> reduce(%{}, &line/2) |
| 49 |
|
end |
| 50 |
|
|
| 51 |
|
defp line(text, acc) do |
| 52 |
40 |
split(text, ":") |> build(acc) |
| 53 |
|
end |
| 54 |
|
|
| 55 |
40 |
defp build([key, value], acc), do: put(acc, trim(key), trim(value)) |
| 56 |
:-( |
defp build(_, acc), do: acc |
| 57 |
|
end |