lib/mix/tasks/moon.gen.component.ex

defmodule Mix.Tasks.Moon.Gen.Component do
  @shortdoc "Generates component and page"

  @moduledoc """
  Generates a component and a component page by component module name given

      $ mix moon.gen.component Form.MyModule

  """

  use Mix.Task
  import Mix.Generator

  import String, only: [replace: 3, downcase: 1, split: 2]
  import Enum, only: [reverse: 1, join: 2]
  import List, only: [last: 1]

  defstruct name: nil,
            path: nil

  @doc false
  def run([name]) do
    name |> context() |> copy_templates() |> print_shell_instructions()
  end

  defp context(name) do
    %{
      name: name,
      path: name |> replace(~r/([a-z])([A-Z])/, "\\1_\\2") |> downcase() |> replace(".", "/"),
      short: name |> split(".") |> last()
    }
  end

  defp pathes(%{path: path}) do
    [
      component: "lib/moon/design/#{path}.ex",
      page: "lib/moon_web/pages/design/#{path}_page.ex",
      example: "lib/moon_web/examples/design/#{path}_example/default.ex"
    ]
  end

  defp copy_templates(context) do
    Enum.each(pathes(context), fn {template, file_path} ->
      file_path |> split("/") |> reverse() |> tl() |> reverse() |> join("/") |> create_directory()

      data =
        EEx.eval_file(
          "priv/templates/moon.gen.component/#{template}.ex",
          Enum.map(context, fn {key, value} -> {key, value} end)
        )

      create_file(file_path, data, force: false)
    end)

    context
  end

  def print_shell_instructions(%{path: path, name: name}) do
    Mix.shell().info("""

    Add the resource to your lib/moon_web/router.ex

      live("/components/v2/#{path}", MoonWeb.Pages.Design.#{name}Page)


    And following to your lib/moon_web/schema/link.ex

      MoonWeb.Pages.Design.#{name}Page

    """)
  end
end