lib/mix/tasks/template.hex.ex

defmodule Mix.Tasks.Template.Hex do

  use Private

  @moduledoc(
    Path.join([__DIR__, "../../../README.md"])
    |> File.read!
    |> String.replace(~r/\A.*^### Use\w+/ms, "")
    |> String.replace(~r/^###.*/ms, ""))

  def run(_) do
    Mix.Hex.start()

    "gen_template"
    |> search()
    |> extract_stuff_we_need()
    |> display_results()
  end

  private do

    defp extract_stuff_we_need({:ok, response}) do
      extract_stuff_we_need(response)
    end

    defp extract_stuff_we_need({:error, term}) do
      Mix.raise "error #{inspect(term)} while searching hex packages"
    end

    defp extract_stuff_we_need({200, content, _}) do
      content
      |> Enum.filter(&is_a_template?/1)
    end

    defp extract_stuff_we_need({error, _, _}) do
      Mix.raise "error #{error} while searching hex packages"
    end

    defp is_a_template?(%{ "name" => name }) do
      name |> String.starts_with?("gen_template_")
    end

    defp display_results([]) do
      Mix.shell.info "Strange... no templates found on hex.pm"
    end

    defp display_results(results) do
      Mix.shell.info(["\n", :underline, "Templates on hex.pm", :reset, "\n"])
      results |> Enum.each(&display_a_result/1)
      Mix.shell.info("Install a template using `mix template.install «name»`\n")
    end

    defp display_a_result(%{ "name" => name,
                             "meta" =>  %{
                               "description" => description
                             }}) do
      Mix.shell.info([:bright, :green, name,
                      :reset, ":\n",
                      indent(description)])

    end

    defp indent(string) do
      "    #{String.replace(string, "\n", "\n    ") |> String.trim_trailing}\n"
    end


    # hex changed the internal API in fall 2017, so we have to deal with both

    require Hex.API.Package
    
    cond do
      function_exported?(Hex.API.Package, :search, 1) ->
        defdelegate search(package), to: Hex.API.Package
        
      function_exported?(Hex.API.Package, :search, 2) ->

        defp search(package) do
          # url = Hex.State.fetch!(:api_url) <> "/"
          Hex.API.Package.search(nil, package)
        end

      true ->
        raise "Can't find Hex.API.Package.search/1 or /2"
    end

    
  end
end