lib/data/file.ex

defmodule Dragon.Data.File do
  @moduledoc """
  Tools for loading data files (yml)
  """
  use Dragon.Context
  import Dragon.Tools.File, only: [drop_root: 2]
  import Dragon.Tools.File.WalkTree
  import Dragon.Tools.Dict
  import Dragon.Data, only: [get_into: 2, data_path: 2]

  # def load(dragon, args, rest, forward) do
  def load(%Dragon{} = dragon, %{type: "file", path: path} = args) do
    stdout([:green, "Loading data", :reset, " from ", :bright, drop_root(dragon.root, path)])
    prefix = get_into(dragon, args)

    %Dragon{dragon | data_paths: Map.put(dragon.data_paths, Path.join(dragon.root, path), [])}
    |> walk_tree(path,
      match: %{~r/\.(ya?ml|json)$/ => &load_data_file/3},
      follow_meta: true,
      prefix: prefix
    )
  end

  ##############################################################################
  def load_data_file(dragon, path, opts) do
    # strip off the first parts of the name... meh?
    datapath =
      case {Map.get(opts, :prefix), data_path(dragon.root, path)} do
        {nil, [_ | path]} -> path
        {prefix, path} when is_list(prefix) -> prefix ++ path
      end

    stdout([
      :green,
      "Loading ",
      :reset,
      :bright,
      drop_root(dragon.root, path),
      :reset,
      :light_black,
      " into data path: ",
      :light_blue,
      "@",
      Enum.join(datapath, ".")
    ])

    with {:ok, data} <- get_file_data(path),
         do: put_into(dragon, [:data | datapath], data)
  end

  def get_file_data(path) do
    case Path.extname(path) do
      ".json" -> File.read!(path) |> Jason.decode()
      ".yml" -> YamlElixir.read_all_from_file(path)
      ".yaml" -> YamlElixir.read_all_from_file(path)
    end
    |> case do
      {:ok, [data]} ->
        {:ok, data}

      {:ok, [_ | _] = list} ->
        {:ok, list}

      {:ok, data} when is_map(data) ->
        {:ok, data}

      error ->
        IO.inspect(error, label: "Error parsing Data")
        abort("Cannot continue")
    end
  end
end