• Operand
  • ./bin/ganged/upon.

gram: op

> ./lib/source/page.ex

Lenses
(coming soon!)


# domain/index depends on `page.key` and `page.name` only.

defmodule Source.Page do
  # defmodule NotFoundError, do: defexception [:message, plug_status: 404]

  @address System.get_env("PAGE_BASE")

  def query() do query(true) end
  def query(require_public) do
    Source.nodes(@address, "~.md")
    |> Enum.map(&read/1)
    |> Enum.filter(& if require_public, do: &1.public, else: true)
    |> Enum.sort_by(& &1.day) |> Enum.reverse
    |> Enum.with_index |> Enum.map(fn {node, n} -> %{node | sequence: n} end)
  end

  def query_by_key!(key) do
    Enum.find(query(), &(&1.key == key)) ||
      raise NotFoundError, "no page uses key `#{key}`."
  end

  def query_by_label!(label) do
    case Enum.filter(query(), &(label in &1.labels)) do
      [] -> raise NotFoundError, "No pages are labeled `#{label}`."
      pages -> pages
    end
  end

  defstruct [
    :key, :composer, :name, :day, :public, :id, :sequence,
    :body, :summary, :labels,
  ]

  @enforce_keys [
    :key, :composer, :name, :day, :id,
    :body, :summary, :labels,
  ]

  def read(n = %Source.Node{}) do
    node = [n.base, n.address] |> Path.join
    [clock, key] = node |> Path.basename(".md") |> String.split(".", parts: 2)
    reading = node |> YamlFrontMatter.parse_file

    case reading do
      {:ok, angles, body} ->
        %Source.Page{ key: key, id: key, day: clock, body: body, public: true, }
        |> Map.merge(
          for {key, shape} <- angles, into: %{}, do: { key |> String.to_atom, shape })

      _ ->
        node |> IO.inspect(label: "node")
        reading |> IO.inspect(label: "parse")
        %Source.Page{ key: key, id: key, day: clock, body: "oops", public: true,
          summary: "[oops] problem reading page on disc.",
        }

    end
  end
end